From 22aa104bce457e7d70b05d7a32cdf09f25ac06b1 Mon Sep 17 00:00:00 2001
From: yukang <moorekang@gmail.com>
Date: Fri, 2 Aug 2024 00:28:57 +0800
Subject: [PATCH 01/12] don't suggest turning crate-level attributes into outer
 style

---
 compiler/rustc_ast/src/ast.rs                 | 11 ++++++
 compiler/rustc_parse/src/parser/attr.rs       | 38 +++++++++++++------
 compiler/rustc_parse/src/parser/stmt.rs       |  5 +++
 tests/ui/delegation/inner-attr.stderr         |  5 ---
 .../attribute/attr-stmt-expr-attr-bad.stderr  | 15 --------
 tests/ui/parser/attribute/attr.stderr         |  5 ---
 .../inner-attr-after-doc-comment.stderr       |  5 ---
 tests/ui/parser/inner-attr.stderr             |  5 ---
 .../isgg-invalid-outer-attttr-issue-127930.rs | 10 +++++
 ...g-invalid-outer-attttr-issue-127930.stderr | 12 ++++++
 tests/ui/parser/issues/issue-30318.fixed      |  2 +-
 tests/ui/parser/issues/issue-30318.rs         |  2 +-
 tests/ui/parser/issues/issue-30318.stderr     |  8 ++--
 13 files changed, 70 insertions(+), 53 deletions(-)
 create mode 100644 tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.rs
 create mode 100644 tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.stderr

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fc1af3fc3dd11..0c81c0f4c93e1 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2898,6 +2898,17 @@ pub struct AttrItem {
     pub tokens: Option<LazyAttrTokenStream>,
 }
 
+impl AttrItem {
+    pub fn is_valid_for_outer_style(&self) -> bool {
+        self.path == sym::cfg_attr
+            || self.path == sym::cfg
+            || self.path == sym::forbid
+            || self.path == sym::warn
+            || self.path == sym::allow
+            || self.path == sym::deny
+    }
+}
+
 /// `TraitRef`s appear in impls.
 ///
 /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 12b9414d1f760..7b64a60960b5e 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -67,6 +67,7 @@ impl<'a> Parser<'a> {
                             token::CommentKind::Line => OuterAttributeType::DocComment,
                             token::CommentKind::Block => OuterAttributeType::DocBlockComment,
                         },
+                        true,
                     ) {
                         err.note(fluent::parse_note);
                         err.span_suggestion_verbose(
@@ -130,7 +131,11 @@ impl<'a> Parser<'a> {
 
             // Emit error if inner attribute is encountered and forbidden.
             if style == ast::AttrStyle::Inner {
-                this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
+                this.error_on_forbidden_inner_attr(
+                    attr_sp,
+                    inner_parse_policy,
+                    item.is_valid_for_outer_style(),
+                );
             }
 
             Ok(attr::mk_attr_from_item(&self.psess.attr_id_generator, item, None, style, attr_sp))
@@ -142,6 +147,7 @@ impl<'a> Parser<'a> {
         err: &mut Diag<'_>,
         span: Span,
         attr_type: OuterAttributeType,
+        suggest_to_outer: bool,
     ) -> Option<Span> {
         let mut snapshot = self.create_snapshot_for_diagnostic();
         let lo = span.lo()
@@ -176,16 +182,18 @@ impl<'a> Parser<'a> {
                 // FIXME(#100717)
                 err.arg("item", item.kind.descr());
                 err.span_label(item.span, fluent::parse_label_does_not_annotate_this);
-                err.span_suggestion_verbose(
-                    replacement_span,
-                    fluent::parse_sugg_change_inner_to_outer,
-                    match attr_type {
-                        OuterAttributeType::Attribute => "",
-                        OuterAttributeType::DocBlockComment => "*",
-                        OuterAttributeType::DocComment => "/",
-                    },
-                    rustc_errors::Applicability::MachineApplicable,
-                );
+                if suggest_to_outer {
+                    err.span_suggestion_verbose(
+                        replacement_span,
+                        fluent::parse_sugg_change_inner_to_outer,
+                        match attr_type {
+                            OuterAttributeType::Attribute => "",
+                            OuterAttributeType::DocBlockComment => "*",
+                            OuterAttributeType::DocComment => "/",
+                        },
+                        rustc_errors::Applicability::MachineApplicable,
+                    );
+                }
                 return None;
             }
             Err(item_err) => {
@@ -196,7 +204,12 @@ impl<'a> Parser<'a> {
         Some(replacement_span)
     }
 
-    pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy) {
+    pub(super) fn error_on_forbidden_inner_attr(
+        &self,
+        attr_sp: Span,
+        policy: InnerAttrPolicy,
+        suggest_to_outer: bool,
+    ) {
         if let InnerAttrPolicy::Forbidden(reason) = policy {
             let mut diag = match reason.as_ref().copied() {
                 Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
@@ -230,6 +243,7 @@ impl<'a> Parser<'a> {
                     &mut diag,
                     attr_sp,
                     OuterAttributeType::Attribute,
+                    suggest_to_outer,
                 )
                 .is_some()
             {
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 7b0daaa14335f..fe8fbeea4767e 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -439,11 +439,16 @@ impl<'a> Parser<'a> {
     pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
         let (attrs, block) = self.parse_inner_attrs_and_block()?;
         if let [.., last] = &*attrs {
+            let suggest_to_outer = match &last.kind {
+                ast::AttrKind::Normal(attr) => attr.item.is_valid_for_outer_style(),
+                _ => false,
+            };
             self.error_on_forbidden_inner_attr(
                 last.span,
                 super::attr::InnerAttrPolicy::Forbidden(Some(
                     InnerAttrForbiddenReason::InCodeBlock,
                 )),
+                suggest_to_outer,
             );
         }
         Ok(block)
diff --git a/tests/ui/delegation/inner-attr.stderr b/tests/ui/delegation/inner-attr.stderr
index f3b53e331ad88..257ab760ffc1a 100644
--- a/tests/ui/delegation/inner-attr.stderr
+++ b/tests/ui/delegation/inner-attr.stderr
@@ -8,11 +8,6 @@ LL | fn main() {}
    | ------------ the inner attribute doesn't annotate this function
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-help: to annotate the function, change the attribute from inner to outer style
-   |
-LL - reuse a as b { #![rustc_dummy] self }
-LL + reuse a as b { #[rustc_dummy] self }
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
index 1ba130e20b578..bd860841b8060 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
@@ -359,11 +359,6 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
    |                        previous outer attribute
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-help: to annotate the item macro invocation, change the attribute from inner to outer style
-   |
-LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
-LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo!(); }
-   |
 
 error: an inner attribute is not permitted following an outer attribute
   --> $DIR/attr-stmt-expr-attr-bad.rs:77:32
@@ -375,11 +370,6 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
    |                        previous outer attribute
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-help: to annotate the item macro invocation, change the attribute from inner to outer style
-   |
-LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
-LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo![]; }
-   |
 
 error: an inner attribute is not permitted following an outer attribute
   --> $DIR/attr-stmt-expr-attr-bad.rs:79:32
@@ -391,11 +381,6 @@ LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
    |                        previous outer attribute
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-help: to annotate the item macro invocation, change the attribute from inner to outer style
-   |
-LL - #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
-LL + #[cfg(FALSE)] fn s() { #[attr] #[attr] foo!{}; }
-   |
 
 error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:85:35
diff --git a/tests/ui/parser/attribute/attr.stderr b/tests/ui/parser/attribute/attr.stderr
index 2e0b16efb6cea..a79a5246c2a9a 100644
--- a/tests/ui/parser/attribute/attr.stderr
+++ b/tests/ui/parser/attribute/attr.stderr
@@ -7,11 +7,6 @@ LL | fn foo() {}
    | ----------- the inner attribute doesn't annotate this function
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-help: to annotate the function, change the attribute from inner to outer style
-   |
-LL - #![lang = "foo"]
-LL + #[lang = "foo"]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/inner-attr-after-doc-comment.stderr b/tests/ui/parser/inner-attr-after-doc-comment.stderr
index 6dbc0fd93fd42..f087c2e4d6540 100644
--- a/tests/ui/parser/inner-attr-after-doc-comment.stderr
+++ b/tests/ui/parser/inner-attr-after-doc-comment.stderr
@@ -13,11 +13,6 @@ LL |   fn main() {}
    |   ------------ the inner attribute doesn't annotate this function
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-help: to annotate the function, change the attribute from inner to outer style
-   |
-LL - #![recursion_limit="100"]
-LL + #[recursion_limit="100"]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/inner-attr.stderr b/tests/ui/parser/inner-attr.stderr
index 57ca164fc15a2..18a82ea4c3856 100644
--- a/tests/ui/parser/inner-attr.stderr
+++ b/tests/ui/parser/inner-attr.stderr
@@ -10,11 +10,6 @@ LL | fn main() {}
    | ------------ the inner attribute doesn't annotate this function
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-help: to annotate the function, change the attribute from inner to outer style
-   |
-LL - #![recursion_limit="100"]
-LL + #[recursion_limit="100"]
-   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.rs b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.rs
new file mode 100644
index 0000000000000..26541a89a565a
--- /dev/null
+++ b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.rs
@@ -0,0 +1,10 @@
+#![allow(dead_code)]
+fn foo() {}
+
+#![feature(iter_array_chunks)] //~ ERROR an inner attribute is not permitted in this context
+fn bar() {}
+
+fn main() {
+    foo();
+    bar();
+}
diff --git a/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.stderr b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.stderr
new file mode 100644
index 0000000000000..d6daa21e7418d
--- /dev/null
+++ b/tests/ui/parser/issues/isgg-invalid-outer-attttr-issue-127930.stderr
@@ -0,0 +1,12 @@
+error: an inner attribute is not permitted in this context
+  --> $DIR/isgg-invalid-outer-attttr-issue-127930.rs:4:1
+   |
+LL | #![feature(iter_array_chunks)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn bar() {}
+   | ----------- the inner attribute doesn't annotate this function
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/issues/issue-30318.fixed b/tests/ui/parser/issues/issue-30318.fixed
index d1661be519393..d4720834746fc 100644
--- a/tests/ui/parser/issues/issue-30318.fixed
+++ b/tests/ui/parser/issues/issue-30318.fixed
@@ -6,7 +6,7 @@ fn foo() { }
 //~^ ERROR expected outer doc comment
 fn bar() { } //~ NOTE the inner doc comment doesn't annotate this function
 
-#[test] //~ ERROR an inner attribute is not permitted in this context
+#[cfg(test)] //~ ERROR an inner attribute is not permitted in this context
 fn baz() { } //~ NOTE the inner attribute doesn't annotate this function
 //~^^ NOTE inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually
 
diff --git a/tests/ui/parser/issues/issue-30318.rs b/tests/ui/parser/issues/issue-30318.rs
index 6f055cd4f7e95..0555379836ac9 100644
--- a/tests/ui/parser/issues/issue-30318.rs
+++ b/tests/ui/parser/issues/issue-30318.rs
@@ -6,7 +6,7 @@ fn foo() { }
 //~^ ERROR expected outer doc comment
 fn bar() { } //~ NOTE the inner doc comment doesn't annotate this function
 
-#![test] //~ ERROR an inner attribute is not permitted in this context
+#![cfg(test)] //~ ERROR an inner attribute is not permitted in this context
 fn baz() { } //~ NOTE the inner attribute doesn't annotate this function
 //~^^ NOTE inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually
 
diff --git a/tests/ui/parser/issues/issue-30318.stderr b/tests/ui/parser/issues/issue-30318.stderr
index c441a92abad92..56bc200db1d3a 100644
--- a/tests/ui/parser/issues/issue-30318.stderr
+++ b/tests/ui/parser/issues/issue-30318.stderr
@@ -15,16 +15,16 @@ LL | /// Misplaced comment...
 error: an inner attribute is not permitted in this context
   --> $DIR/issue-30318.rs:9:1
    |
-LL | #![test]
-   | ^^^^^^^^
+LL | #![cfg(test)]
+   | ^^^^^^^^^^^^^
 LL | fn baz() { }
    | ------------ the inner attribute doesn't annotate this function
    |
    = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
 help: to annotate the function, change the attribute from inner to outer style
    |
-LL - #![test]
-LL + #[test]
+LL - #![cfg(test)]
+LL + #[cfg(test)]
    |
 
 error[E0753]: expected outer doc comment

From b335ec9ec8d1132efee4e900a1c173efc7f4a357 Mon Sep 17 00:00:00 2001
From: Flying-Toast <38232168+Flying-Toast@users.noreply.github.com>
Date: Sat, 23 Mar 2024 10:49:05 -0400
Subject: [PATCH 02/12] Add a special case for CStr/CString in the
 improper_ctypes lint

Instead of saying to "consider adding a `#[repr(C)]` or
`#[repr(transparent)]` attribute to this struct", we now tell users to
"Use `*const ffi::c_char` instead, and pass the value from
`CStr::as_ptr()`" when the type involved is a `CStr` or a `CString`.

Co-authored-by: Jieyou Xu <jieyouxu@outlook.com>
---
 compiler/rustc_lint/messages.ftl              |  5 ++
 compiler/rustc_lint/src/types.rs              | 54 ++++++++----
 compiler/rustc_span/src/symbol.rs             |  1 +
 library/core/src/ffi/c_str.rs                 |  1 +
 ...extern-C-non-FFI-safe-arg-ice-52334.stderr | 12 +--
 tests/ui/lint/lint-ctypes-cstr.rs             | 36 ++++++++
 tests/ui/lint/lint-ctypes-cstr.stderr         | 84 +++++++++++++++++++
 7 files changed, 172 insertions(+), 21 deletions(-)
 create mode 100644 tests/ui/lint/lint-ctypes-cstr.rs
 create mode 100644 tests/ui/lint/lint-ctypes-cstr.stderr

diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7e4feb0a82716..52a03772dc23c 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -361,6 +361,11 @@ lint_improper_ctypes_box = box cannot be represented as a single pointer
 lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
 
 lint_improper_ctypes_char_reason = the `char` type has no C equivalent
+
+lint_improper_ctypes_cstr_help =
+    consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+lint_improper_ctypes_cstr_reason = `CStr`/`CString` do not have a guaranteed layout
+
 lint_improper_ctypes_dyn = trait objects have no C equivalent
 
 lint_improper_ctypes_enum_repr_help =
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index f3196cfed533e..d84d60ef5a7c1 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -984,6 +984,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
     mode: CItemKind,
 }
 
+/// Accumulator for recursive ffi type checking
+struct CTypesVisitorState<'tcx> {
+    cache: FxHashSet<Ty<'tcx>>,
+    /// The original type being checked, before we recursed
+    /// to any other types it contains.
+    base_ty: Ty<'tcx>,
+}
+
 enum FfiResult<'tcx> {
     FfiSafe,
     FfiPhantom(Ty<'tcx>),
@@ -1212,7 +1220,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Checks if the given field's type is "ffi-safe".
     fn check_field_type_for_ffi(
         &self,
-        cache: &mut FxHashSet<Ty<'tcx>>,
+        acc: &mut CTypesVisitorState<'tcx>,
         field: &ty::FieldDef,
         args: GenericArgsRef<'tcx>,
     ) -> FfiResult<'tcx> {
@@ -1222,13 +1230,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             .tcx
             .try_normalize_erasing_regions(self.cx.param_env, field_ty)
             .unwrap_or(field_ty);
-        self.check_type_for_ffi(cache, field_ty)
+        self.check_type_for_ffi(acc, field_ty)
     }
 
     /// Checks if the given `VariantDef`'s field types are "ffi-safe".
     fn check_variant_for_ffi(
         &self,
-        cache: &mut FxHashSet<Ty<'tcx>>,
+        acc: &mut CTypesVisitorState<'tcx>,
         ty: Ty<'tcx>,
         def: ty::AdtDef<'tcx>,
         variant: &ty::VariantDef,
@@ -1238,7 +1246,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         let transparent_with_all_zst_fields = if def.repr().transparent() {
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
                 // Transparent newtypes have at most one non-ZST field which needs to be checked..
-                match self.check_field_type_for_ffi(cache, field, args) {
+                match self.check_field_type_for_ffi(acc, field, args) {
                     FfiUnsafe { ty, .. } if ty.is_unit() => (),
                     r => return r,
                 }
@@ -1256,7 +1264,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
         let mut all_phantom = !variant.fields.is_empty();
         for field in &variant.fields {
-            all_phantom &= match self.check_field_type_for_ffi(cache, field, args) {
+            all_phantom &= match self.check_field_type_for_ffi(acc, field, args) {
                 FfiSafe => false,
                 // `()` fields are FFI-safe!
                 FfiUnsafe { ty, .. } if ty.is_unit() => false,
@@ -1276,7 +1284,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
     /// Checks if the given type is "ffi-safe" (has a stable, well-defined
     /// representation which can be exported to C code).
-    fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult<'tcx> {
+    fn check_type_for_ffi(
+        &self,
+        acc: &mut CTypesVisitorState<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> FfiResult<'tcx> {
         use FfiResult::*;
 
         let tcx = self.cx.tcx;
@@ -1285,7 +1297,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         // `struct S(*mut S);`.
         // FIXME: A recursion limit is necessary as well, for irregular
         // recursive types.
-        if !cache.insert(ty) {
+        if !acc.cache.insert(ty) {
             return FfiSafe;
         }
 
@@ -1307,6 +1319,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
                 match def.adt_kind() {
                     AdtKind::Struct | AdtKind::Union => {
+                        if let Some(sym::cstring_type | sym::cstr_type) =
+                            tcx.get_diagnostic_name(def.did())
+                            && !acc.base_ty.is_mutable_ptr()
+                        {
+                            return FfiUnsafe {
+                                ty,
+                                reason: fluent::lint_improper_ctypes_cstr_reason,
+                                help: Some(fluent::lint_improper_ctypes_cstr_help),
+                            };
+                        }
+
                         if !def.repr().c() && !def.repr().transparent() {
                             return FfiUnsafe {
                                 ty,
@@ -1353,7 +1376,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             };
                         }
 
-                        self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), args)
+                        self.check_variant_for_ffi(acc, ty, def, def.non_enum_variant(), args)
                     }
                     AdtKind::Enum => {
                         if def.variants().is_empty() {
@@ -1377,7 +1400,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             if let Some(ty) =
                                 repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
                             {
-                                return self.check_type_for_ffi(cache, ty);
+                                return self.check_type_for_ffi(acc, ty);
                             }
 
                             return FfiUnsafe {
@@ -1398,7 +1421,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                                 };
                             }
 
-                            match self.check_variant_for_ffi(cache, ty, def, variant, args) {
+                            match self.check_variant_for_ffi(acc, ty, def, variant, args) {
                                 FfiSafe => (),
                                 r => return r,
                             }
@@ -1468,9 +1491,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
-            ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(cache, ty),
+            ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty),
 
-            ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
+            ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty),
 
             ty::FnPtr(sig) => {
                 if self.is_internal_abi(sig.abi()) {
@@ -1483,7 +1506,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
                 let sig = tcx.instantiate_bound_regions_with_erased(sig);
                 for arg in sig.inputs() {
-                    match self.check_type_for_ffi(cache, *arg) {
+                    match self.check_type_for_ffi(acc, *arg) {
                         FfiSafe => {}
                         r => return r,
                     }
@@ -1494,7 +1517,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     return FfiSafe;
                 }
 
-                self.check_type_for_ffi(cache, ret_ty)
+                self.check_type_for_ffi(acc, ret_ty)
             }
 
             ty::Foreign(..) => FfiSafe,
@@ -1617,7 +1640,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             return;
         }
 
-        match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
+        let mut acc = CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty };
+        match self.check_type_for_ffi(&mut acc, ty) {
             FfiResult::FfiSafe => {}
             FfiResult::FfiPhantom(ty) => {
                 self.emit_ffi_unsafe_type_lint(
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 94cf21da4efb8..407f95a0f21e3 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -671,6 +671,7 @@ symbols! {
         crate_visibility_modifier,
         crt_dash_static: "crt-static",
         csky_target_feature,
+        cstr_type,
         cstring_type,
         ctlz,
         ctlz_nonzero,
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 22084dcff8f88..7808d42ab5de4 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -91,6 +91,7 @@ use crate::{fmt, intrinsics, ops, slice, str};
 /// [str]: prim@str "str"
 #[derive(PartialEq, Eq, Hash)]
 #[stable(feature = "core_c_str", since = "1.64.0")]
+#[rustc_diagnostic_item = "cstr_type"]
 #[rustc_has_incoherent_inherent_impls]
 #[lang = "CStr"]
 // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
index 8349298847918..044c1ae2dd42f 100644
--- a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
+++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
@@ -1,21 +1,21 @@
-warning: `extern` fn uses type `[i8 or u8 (arch dependant)]`, which is not FFI-safe
+warning: `extern` fn uses type `CStr`, which is not FFI-safe
   --> $DIR/extern-C-non-FFI-safe-arg-ice-52334.rs:7:12
    |
 LL | type Foo = extern "C" fn(::std::ffi::CStr);
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
-   = note: slices have no C equivalent
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
    = note: `#[warn(improper_ctypes_definitions)]` on by default
 
-warning: `extern` block uses type `[i8 or u8 (arch dependant)]`, which is not FFI-safe
+warning: `extern` block uses type `CStr`, which is not FFI-safe
   --> $DIR/extern-C-non-FFI-safe-arg-ice-52334.rs:10:18
    |
 LL |     fn meh(blah: Foo);
    |                  ^^^ not FFI-safe
    |
-   = help: consider using a raw pointer instead
-   = note: slices have no C equivalent
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
    = note: `#[warn(improper_ctypes)]` on by default
 
 warning: 2 warnings emitted
diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/lint-ctypes-cstr.rs
new file mode 100644
index 0000000000000..b04decd0bcacc
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-cstr.rs
@@ -0,0 +1,36 @@
+#![crate_type = "lib"]
+#![deny(improper_ctypes, improper_ctypes_definitions)]
+
+use std::ffi::{CStr, CString};
+
+extern "C" {
+    fn take_cstr(s: CStr);
+    //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
+    //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+    fn take_cstr_ref(s: &CStr);
+    //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
+    //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+    fn take_cstring(s: CString);
+    //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
+    //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+    fn take_cstring_ref(s: &CString);
+    //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
+    //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+
+    fn no_special_help_for_mut_cstring(s: *mut CString);
+    //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
+    //~| HELP consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+
+    fn no_special_help_for_mut_cstring_ref(s: &mut CString);
+    //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
+    //~| HELP consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+}
+
+extern "C" fn rust_take_cstr_ref(s: &CStr) {}
+//~^ ERROR `extern` fn uses type `CStr`, which is not FFI-safe
+//~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+extern "C" fn rust_take_cstring(s: CString) {}
+//~^ ERROR `extern` fn uses type `CString`, which is not FFI-safe
+//~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+extern "C" fn rust_no_special_help_for_mut_cstring(s: *mut CString) {}
+extern "C" fn rust_no_special_help_for_mut_cstring_ref(s: &mut CString) {}
diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/lint-ctypes-cstr.stderr
new file mode 100644
index 0000000000000..8957758d57732
--- /dev/null
+++ b/tests/ui/lint/lint-ctypes-cstr.stderr
@@ -0,0 +1,84 @@
+error: `extern` block uses type `CStr`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:7:21
+   |
+LL |     fn take_cstr(s: CStr);
+   |                     ^^^^ not FFI-safe
+   |
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-cstr.rs:2:9
+   |
+LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
+   |         ^^^^^^^^^^^^^^^
+
+error: `extern` block uses type `CStr`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:10:25
+   |
+LL |     fn take_cstr_ref(s: &CStr);
+   |                         ^^^^^ not FFI-safe
+   |
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
+
+error: `extern` block uses type `CString`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:13:24
+   |
+LL |     fn take_cstring(s: CString);
+   |                        ^^^^^^^ not FFI-safe
+   |
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
+
+error: `extern` block uses type `CString`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:16:28
+   |
+LL |     fn take_cstring_ref(s: &CString);
+   |                            ^^^^^^^^ not FFI-safe
+   |
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
+
+error: `extern` block uses type `CString`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:20:43
+   |
+LL |     fn no_special_help_for_mut_cstring(s: *mut CString);
+   |                                           ^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` block uses type `CString`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:24:47
+   |
+LL |     fn no_special_help_for_mut_cstring_ref(s: &mut CString);
+   |                                               ^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` fn uses type `CStr`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:29:37
+   |
+LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
+   |                                     ^^^^^ not FFI-safe
+   |
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
+note: the lint level is defined here
+  --> $DIR/lint-ctypes-cstr.rs:2:26
+   |
+LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `extern` fn uses type `CString`, which is not FFI-safe
+  --> $DIR/lint-ctypes-cstr.rs:32:36
+   |
+LL | extern "C" fn rust_take_cstring(s: CString) {}
+   |                                    ^^^^^^^ not FFI-safe
+   |
+   = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
+   = note: `CStr`/`CString` do not have a guaranteed layout
+
+error: aborting due to 8 previous errors
+

From f6767f7a68f42101e6820171c033565e0f3a807a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 31 Jul 2024 22:39:40 +0000
Subject: [PATCH 03/12] Detect `*` operator on `!Sized` expression

```
error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:15:9
   |
LL |     let x = *"";
   |         ^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
   = note: all local variables must have a statically known size
   = help: unsized locals are gated as an unstable feature
help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
   |
LL -     let x = *"";
LL +     let x = "";
   |
```
---
 compiler/rustc_hir_typeck/src/expr.rs         |  6 +-
 compiler/rustc_middle/src/traits/mod.rs       |  2 +-
 .../src/error_reporting/traits/suggestions.rs | 49 ++++++++++--
 tests/ui/dst/dst-rvalue.stderr                | 10 +++
 tests/ui/issues/issue-17651.stderr            |  5 ++
 tests/ui/sized/unsized-binding.stderr         |  5 ++
 ...nsized-str-in-return-expr-arg-and-local.rs | 30 ++++++++
 ...ed-str-in-return-expr-arg-and-local.stderr | 74 +++++++++++++++++++
 .../suggestions/issue-84973-blacklist.stderr  |  5 ++
 tests/ui/unsized/unsized6.stderr              | 10 +++
 10 files changed, 187 insertions(+), 9 deletions(-)
 create mode 100644 tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
 create mode 100644 tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr

diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index e54f9486f6a89..f13321a56bf7d 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -841,6 +841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ret_ty = ret_coercion.borrow().expected_ty();
         let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
         let mut span = return_expr.span;
+        let mut hir_id = return_expr.hir_id;
         // Use the span of the trailing expression for our cause,
         // not the span of the entire function
         if !explicit_return
@@ -848,6 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let Some(last_expr) = body.expr
         {
             span = last_expr.span;
+            hir_id = last_expr.hir_id;
         }
         ret_coercion.borrow_mut().coerce(
             self,
@@ -864,6 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.select_obligations_where_possible(|errors| {
                 self.point_at_return_for_opaque_ty_error(
                     errors,
+                    hir_id,
                     span,
                     return_expr_ty,
                     return_expr.span,
@@ -921,6 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn point_at_return_for_opaque_ty_error(
         &self,
         errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        hir_id: HirId,
         span: Span,
         return_expr_ty: Ty<'tcx>,
         return_span: Span,
@@ -935,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let new_cause = ObligationCause::new(
                     cause.span,
                     cause.body_id,
-                    ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))),
+                    ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))),
                 );
                 *cause = new_cause;
             }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index d54e2ca0a74f7..a3277fb96d229 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -353,7 +353,7 @@ pub enum ObligationCauseCode<'tcx> {
     ReturnValue(HirId),
 
     /// Opaque return type of this function
-    OpaqueReturnType(Option<(Ty<'tcx>, Span)>),
+    OpaqueReturnType(Option<(Ty<'tcx>, HirId)>),
 
     /// Block implicit return
     BlockTailExpression(HirId, hir::MatchSource),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 0d15ef55e24e7..b1aa455ce8860 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2725,6 +2725,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
         let predicate = predicate.upcast(tcx);
+        let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| {
+            if let Some(pred) = predicate.as_trait_clause()
+                && tcx.is_lang_item(pred.def_id(), LangItem::Sized)
+                && let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
+            {
+                err.span_suggestion_verbose(
+                    expr.span.until(inner.span),
+                    "references are always `Sized`, even if they point to unsized data; consider \
+                     not dereferencing the expression",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        };
         match *cause_code {
             ObligationCauseCode::ExprAssignable
             | ObligationCauseCode::MatchExpressionArm { .. }
@@ -2771,6 +2785,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
                 if !span.is_dummy() =>
             {
+                if let ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, pos) = &cause_code {
+                    if let Node::Expr(expr) = tcx.parent_hir_node(*hir_id)
+                        && let hir::ExprKind::Call(_, args) = expr.kind
+                        && let Some(expr) = args.get(*pos)
+                    {
+                        suggest_remove_deref(err, &expr);
+                    } else if let Node::Expr(expr) = self.tcx.hir_node(*hir_id)
+                        && let hir::ExprKind::MethodCall(_, _, args, _) = expr.kind
+                        && let Some(expr) = args.get(*pos)
+                    {
+                        suggest_remove_deref(err, &expr);
+                    }
+                }
                 let item_name = tcx.def_path_str(item_def_id);
                 let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
                 let mut multispan = MultiSpan::from(span);
@@ -2968,6 +2995,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     ));
                     err.downgrade_to_delayed_bug();
                 }
+                let mut local = true;
                 match tcx.parent_hir_node(hir_id) {
                     Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
                         err.span_suggestion_verbose(
@@ -2976,7 +3004,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             "&",
                             Applicability::MachineApplicable,
                         );
-                        err.note("all local variables must have a statically known size");
                     }
                     Node::LetStmt(hir::LetStmt {
                         init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }),
@@ -2991,7 +3018,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             "&",
                             Applicability::MachineApplicable,
                         );
-                        err.note("all local variables must have a statically known size");
+                    }
+                    Node::LetStmt(hir::LetStmt { init: Some(expr), .. }) => {
+                        // When encountering an assignment of an unsized trait, like `let x = *"";`,
+                        // we check if the RHS is a deref operation, to suggest removing it.
+                        suggest_remove_deref(err, &expr);
                     }
                     Node::Param(param) => {
                         err.span_suggestion_verbose(
@@ -3001,10 +3032,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             "&",
                             Applicability::MachineApplicable,
                         );
+                        local = false;
                     }
-                    _ => {
-                        err.note("all local variables must have a statically known size");
-                    }
+                    _ => {}
+                }
+                if local {
+                    err.note("all local variables must have a statically known size");
                 }
                 if !tcx.features().unsized_locals {
                     err.help("unsized locals are gated as an unstable feature");
@@ -3527,14 +3560,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 );
             }
             ObligationCauseCode::OpaqueReturnType(expr_info) => {
-                if let Some((expr_ty, expr_span)) = expr_info {
+                if let Some((expr_ty, hir_id)) = expr_info {
                     let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file);
+                    let expr = self.infcx.tcx.hir().expect_expr(hir_id);
                     err.span_label(
-                        expr_span,
+                        expr.span,
                         with_forced_trimmed_paths!(format!(
                             "return type was inferred to be `{expr_ty}` here",
                         )),
                     );
+                    suggest_remove_deref(err, &expr);
                 }
             }
         }
diff --git a/tests/ui/dst/dst-rvalue.stderr b/tests/ui/dst/dst-rvalue.stderr
index 8d0a82b707dda..d8c529617f75f 100644
--- a/tests/ui/dst/dst-rvalue.stderr
+++ b/tests/ui/dst/dst-rvalue.stderr
@@ -9,6 +9,11 @@ LL |     let _x: Box<str> = Box::new(*"hello world");
    = help: the trait `Sized` is not implemented for `str`
 note: required by a bound in `Box::<T>::new`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let _x: Box<str> = Box::new(*"hello world");
+LL +     let _x: Box<str> = Box::new("hello world");
+   |
 
 error[E0277]: the size for values of type `[isize]` cannot be known at compilation time
   --> $DIR/dst-rvalue.rs:8:37
@@ -21,6 +26,11 @@ LL |     let _x: Box<[isize]> = Box::new(*array);
    = help: the trait `Sized` is not implemented for `[isize]`
 note: required by a bound in `Box::<T>::new`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let _x: Box<[isize]> = Box::new(*array);
+LL +     let _x: Box<[isize]> = Box::new(array);
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-17651.stderr b/tests/ui/issues/issue-17651.stderr
index 0c95a3c0c40d8..9519507320d82 100644
--- a/tests/ui/issues/issue-17651.stderr
+++ b/tests/ui/issues/issue-17651.stderr
@@ -9,6 +9,11 @@ LL |     (|| Box::new(*(&[0][..])))();
    = help: the trait `Sized` is not implemented for `[{integer}]`
 note: required by a bound in `Box::<T>::new`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     (|| Box::new(*(&[0][..])))();
+LL +     (|| Box::new((&[0][..])))();
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/sized/unsized-binding.stderr b/tests/ui/sized/unsized-binding.stderr
index 7c3276032c2b4..8de236cd0b6e0 100644
--- a/tests/ui/sized/unsized-binding.stderr
+++ b/tests/ui/sized/unsized-binding.stderr
@@ -7,6 +7,11 @@ LL |     let x = *"";
    = help: the trait `Sized` is not implemented for `str`
    = note: all local variables must have a statically known size
    = help: unsized locals are gated as an unstable feature
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let x = *"";
+LL +     let x = "";
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
new file mode 100644
index 0000000000000..35abbb80d99e5
--- /dev/null
+++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.rs
@@ -0,0 +1,30 @@
+fn foo() -> impl Sized {
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+//~| HELP the trait `Sized` is not implemented for `str`
+    *"" //~ HELP consider not dereferencing the expression
+}
+fn bar(_: impl Sized) {}
+struct S;
+
+impl S {
+    fn baz(&self, _: impl Sized) {}
+}
+
+fn main() {
+    let _ = foo();
+    let x = *"";
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| HELP consider not dereferencing the expression
+    //~| HELP the trait `Sized` is not implemented for `str`
+    //~| HELP unsized locals are gated as an unstable feature
+    bar(x);
+    S.baz(x);
+    bar(*"");
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| HELP consider not dereferencing the expression
+    //~| HELP the trait `Sized` is not implemented for `str`
+    S.baz(*"");
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    //~| HELP consider not dereferencing the expression
+    //~| HELP the trait `Sized` is not implemented for `str`
+}
diff --git a/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr
new file mode 100644
index 0000000000000..9b7258aff1261
--- /dev/null
+++ b/tests/ui/sized/unsized-str-in-return-expr-arg-and-local.stderr
@@ -0,0 +1,74 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:1:13
+   |
+LL | fn foo() -> impl Sized {
+   |             ^^^^^^^^^^ doesn't have a size known at compile-time
+...
+LL |     *""
+   |     --- return type was inferred to be `str` here
+   |
+   = help: the trait `Sized` is not implemented for `str`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     *""
+LL +     ""
+   |
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:15:9
+   |
+LL |     let x = *"";
+   |         ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let x = *"";
+LL +     let x = "";
+   |
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:22:9
+   |
+LL |     bar(*"");
+   |     --- ^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by a bound in `bar`
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:6:16
+   |
+LL | fn bar(_: impl Sized) {}
+   |                ^^^^^ required by this bound in `bar`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     bar(*"");
+LL +     bar("");
+   |
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:26:11
+   |
+LL |     S.baz(*"");
+   |       --- ^^^ doesn't have a size known at compile-time
+   |       |
+   |       required by a bound introduced by this call
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by a bound in `S::baz`
+  --> $DIR/unsized-str-in-return-expr-arg-and-local.rs:10:27
+   |
+LL |     fn baz(&self, _: impl Sized) {}
+   |                           ^^^^^ required by this bound in `S::baz`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     S.baz(*"");
+LL +     S.baz("");
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/issue-84973-blacklist.stderr b/tests/ui/suggestions/issue-84973-blacklist.stderr
index 4fd063e46926a..c1ef1cd428e4a 100644
--- a/tests/ui/suggestions/issue-84973-blacklist.stderr
+++ b/tests/ui/suggestions/issue-84973-blacklist.stderr
@@ -66,6 +66,11 @@ note: required by a bound in `f_sized`
    |
 LL | fn f_sized<T: Sized>(t: T) {}
    |               ^^^^^ required by this bound in `f_sized`
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     f_sized(*ref_cl);
+LL +     f_sized(ref_cl);
+   |
 
 error[E0277]: `Rc<{integer}>` cannot be sent between threads safely
   --> $DIR/issue-84973-blacklist.rs:27:12
diff --git a/tests/ui/unsized/unsized6.stderr b/tests/ui/unsized/unsized6.stderr
index 56e7f60f9ff08..d406120efc532 100644
--- a/tests/ui/unsized/unsized6.stderr
+++ b/tests/ui/unsized/unsized6.stderr
@@ -123,6 +123,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f3<X: ?Sized>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL + fn f3<X>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
    |
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let y = *x2;
+LL +     let y = x2;
+   |
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:26:10
@@ -177,6 +182,11 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn f4<X: ?Sized + T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
 LL + fn f4<X: T>(x1: Box<X>, x2: Box<X>, x3: Box<X>) {
    |
+help: references are always `Sized`, even if they point to unsized data; consider not dereferencing the expression
+   |
+LL -     let y = *x2;
+LL +     let y = x2;
+   |
 
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized6.rs:34:10

From 4c5e888eb6846d4c777bd05cbc6af06a50faeb6a Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Thu, 22 Aug 2024 17:13:13 -0400
Subject: [PATCH 04/12] rustdoc: show exact case-sensitive matches first

fixes #119480
---
 src/librustdoc/html/static/js/search.js | 8 ++++++++
 tests/rustdoc-js-std/exact-case.js      | 7 +++++++
 2 files changed, 15 insertions(+)
 create mode 100644 tests/rustdoc-js-std/exact-case.js

diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 3eb27ea087c1d..63f492d5ac17e 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1393,6 +1393,7 @@ function initSearch(rawSearchIndex) {
          */
         async function sortResults(results, isType, preferredCrate) {
             const userQuery = parsedQuery.userQuery;
+            const casedUserQuery = parsedQuery.original;
             const result_list = [];
             for (const result of results.values()) {
                 result.item = searchIndex[result.id];
@@ -1403,6 +1404,13 @@ function initSearch(rawSearchIndex) {
             result_list.sort((aaa, bbb) => {
                 let a, b;
 
+                // sort by exact case-sensitive match
+                a = (aaa.item.name !== casedUserQuery);
+                b = (bbb.item.name !== casedUserQuery);
+                if (a !== b) {
+                    return a - b;
+                }
+
                 // sort by exact match with regard to the last word (mismatch goes later)
                 a = (aaa.word !== userQuery);
                 b = (bbb.word !== userQuery);
diff --git a/tests/rustdoc-js-std/exact-case.js b/tests/rustdoc-js-std/exact-case.js
new file mode 100644
index 0000000000000..d9faff22fff70
--- /dev/null
+++ b/tests/rustdoc-js-std/exact-case.js
@@ -0,0 +1,7 @@
+const EXPECTED = {
+    'query': 'Copy',
+    'others': [
+        { 'path': 'std::marker', 'name': 'Copy' },
+        { 'path': 'std::fs', 'name': 'copy' },
+    ],
+}

From b968b26c03510c80782c4524a334f5fa440cb2d8 Mon Sep 17 00:00:00 2001
From: Noa <coolreader18@gmail.com>
Date: Thu, 22 Aug 2024 14:42:24 -0500
Subject: [PATCH 05/12] Put Pin::as_deref_mut in impl Pin<Ptr>

---
 library/core/src/pin.rs | 121 ++++++++++++++++++++--------------------
 1 file changed, 62 insertions(+), 59 deletions(-)

diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 0569b8b762433..1ad509892d26a 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1291,8 +1291,8 @@ impl<Ptr: Deref> Pin<Ptr> {
     ///     // Now, if `x` was the only reference, we have a mutable reference to
     ///     // data that we pinned above, which we could use to move it as we have
     ///     // seen in the previous example. We have violated the pinning API contract.
-    ///  }
-    ///  ```
+    /// }
+    /// ```
     ///
     /// ## Pinning of closure captures
     ///
@@ -1356,20 +1356,6 @@ impl<Ptr: Deref> Pin<Ptr> {
         Pin { __pointer: pointer }
     }
 
-    /// Gets a shared reference to the pinned value this [`Pin`] points to.
-    ///
-    /// This is a generic method to go from `&Pin<Pointer<T>>` to `Pin<&T>`.
-    /// It is safe because, as part of the contract of `Pin::new_unchecked`,
-    /// the pointee cannot move after `Pin<Pointer<T>>` got created.
-    /// "Malicious" implementations of `Pointer::Deref` are likewise
-    /// ruled out by the contract of `Pin::new_unchecked`.
-    #[stable(feature = "pin", since = "1.33.0")]
-    #[inline(always)]
-    pub fn as_ref(&self) -> Pin<&Ptr::Target> {
-        // SAFETY: see documentation on this function
-        unsafe { Pin::new_unchecked(&*self.__pointer) }
-    }
-
     /// Unwraps this `Pin<Ptr>`, returning the underlying `Ptr`.
     ///
     /// # Safety
@@ -1394,9 +1380,21 @@ impl<Ptr: Deref> Pin<Ptr> {
     pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr {
         pin.__pointer
     }
-}
 
-impl<Ptr: DerefMut> Pin<Ptr> {
+    /// Gets a shared reference to the pinned value this [`Pin`] points to.
+    ///
+    /// This is a generic method to go from `&Pin<Pointer<T>>` to `Pin<&T>`.
+    /// It is safe because, as part of the contract of `Pin::new_unchecked`,
+    /// the pointee cannot move after `Pin<Pointer<T>>` got created.
+    /// "Malicious" implementations of `Pointer::Deref` are likewise
+    /// ruled out by the contract of `Pin::new_unchecked`.
+    #[stable(feature = "pin", since = "1.33.0")]
+    #[inline(always)]
+    pub fn as_ref(&self) -> Pin<&Ptr::Target> {
+        // SAFETY: see documentation on this function
+        unsafe { Pin::new_unchecked(&*self.__pointer) }
+    }
+
     /// Gets a mutable reference to the pinned value this `Pin<Ptr>` points to.
     ///
     /// This is a generic method to go from `&mut Pin<Pointer<T>>` to `Pin<&mut T>`.
@@ -1428,11 +1426,55 @@ impl<Ptr: DerefMut> Pin<Ptr> {
     /// ```
     #[stable(feature = "pin", since = "1.33.0")]
     #[inline(always)]
-    pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> {
+    pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target>
+    where
+        Ptr: DerefMut,
+    {
         // SAFETY: see documentation on this function
         unsafe { Pin::new_unchecked(&mut *self.__pointer) }
     }
 
+    /// Gets `Pin<&mut T>` to the underlying pinned value from this nested `Pin`-pointer.
+    ///
+    /// This is a generic method to go from `Pin<&mut Pin<Pointer<T>>>` to `Pin<&mut T>`. It is
+    /// safe because the existence of a `Pin<Pointer<T>>` ensures that the pointee, `T`, cannot
+    /// move in the future, and this method does not enable the pointee to move. "Malicious"
+    /// implementations of `Ptr::DerefMut` are likewise ruled out by the contract of
+    /// `Pin::new_unchecked`.
+    #[unstable(feature = "pin_deref_mut", issue = "86918")]
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[inline(always)]
+    pub fn as_deref_mut(self: Pin<&mut Pin<Ptr>>) -> Pin<&mut Ptr::Target>
+    where
+        Ptr: DerefMut,
+    {
+        // SAFETY: What we're asserting here is that going from
+        //
+        //     Pin<&mut Pin<Ptr>>
+        //
+        // to
+        //
+        //     Pin<&mut Ptr::Target>
+        //
+        // is safe.
+        //
+        // We need to ensure that two things hold for that to be the case:
+        //
+        // 1) Once we give out a `Pin<&mut Ptr::Target>`, a `&mut Ptr::Target` will not be given out.
+        // 2) By giving out a `Pin<&mut Ptr::Target>`, we do not risk violating
+        // `Pin<&mut Pin<Ptr>>`
+        //
+        // The existence of `Pin<Ptr>` is sufficient to guarantee #1: since we already have a
+        // `Pin<Ptr>`, it must already uphold the pinning guarantees, which must mean that
+        // `Pin<&mut Ptr::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely
+        // on the fact that `Ptr` is _also_ pinned.
+        //
+        // For #2, we need to ensure that code given a `Pin<&mut Ptr::Target>` cannot cause the
+        // `Pin<Ptr>` to move? That is not possible, since `Pin<&mut Ptr::Target>` no longer retains
+        // any access to the `Ptr` itself, much less the `Pin<Ptr>`.
+        unsafe { self.get_unchecked_mut() }.as_mut()
+    }
+
     /// Assigns a new value to the memory location pointed to by the `Pin<Ptr>`.
     ///
     /// This overwrites pinned data, but that is okay: the original pinned value's destructor gets
@@ -1457,6 +1499,7 @@ impl<Ptr: DerefMut> Pin<Ptr> {
     #[inline(always)]
     pub fn set(&mut self, value: Ptr::Target)
     where
+        Ptr: DerefMut,
         Ptr::Target: Sized,
     {
         *(self.__pointer) = value;
@@ -1613,46 +1656,6 @@ impl<T: ?Sized> Pin<&'static T> {
     }
 }
 
-impl<'a, Ptr: DerefMut> Pin<&'a mut Pin<Ptr>> {
-    /// Gets `Pin<&mut T>` to the underlying pinned value from this nested `Pin`-pointer.
-    ///
-    /// This is a generic method to go from `Pin<&mut Pin<Pointer<T>>>` to `Pin<&mut T>`. It is
-    /// safe because the existence of a `Pin<Pointer<T>>` ensures that the pointee, `T`, cannot
-    /// move in the future, and this method does not enable the pointee to move. "Malicious"
-    /// implementations of `Ptr::DerefMut` are likewise ruled out by the contract of
-    /// `Pin::new_unchecked`.
-    #[unstable(feature = "pin_deref_mut", issue = "86918")]
-    #[must_use = "`self` will be dropped if the result is not used"]
-    #[inline(always)]
-    pub fn as_deref_mut(self) -> Pin<&'a mut Ptr::Target> {
-        // SAFETY: What we're asserting here is that going from
-        //
-        //     Pin<&mut Pin<Ptr>>
-        //
-        // to
-        //
-        //     Pin<&mut Ptr::Target>
-        //
-        // is safe.
-        //
-        // We need to ensure that two things hold for that to be the case:
-        //
-        // 1) Once we give out a `Pin<&mut Ptr::Target>`, a `&mut Ptr::Target` will not be given out.
-        // 2) By giving out a `Pin<&mut Ptr::Target>`, we do not risk violating
-        // `Pin<&mut Pin<Ptr>>`
-        //
-        // The existence of `Pin<Ptr>` is sufficient to guarantee #1: since we already have a
-        // `Pin<Ptr>`, it must already uphold the pinning guarantees, which must mean that
-        // `Pin<&mut Ptr::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely
-        // on the fact that `Ptr` is _also_ pinned.
-        //
-        // For #2, we need to ensure that code given a `Pin<&mut Ptr::Target>` cannot cause the
-        // `Pin<Ptr>` to move? That is not possible, since `Pin<&mut Ptr::Target>` no longer retains
-        // any access to the `Ptr` itself, much less the `Pin<Ptr>`.
-        unsafe { self.get_unchecked_mut() }.as_mut()
-    }
-}
-
 impl<T: ?Sized> Pin<&'static mut T> {
     /// Gets a pinning mutable reference from a static mutable reference.
     ///

From c65ef3d37c312dc0404da8b5c3f781d376778aad Mon Sep 17 00:00:00 2001
From: Noa <coolreader18@gmail.com>
Date: Fri, 23 Aug 2024 13:06:26 -0500
Subject: [PATCH 06/12] Move into_inner_unchecked back to the bottom of the
 impl block

---
 library/core/src/pin.rs | 50 ++++++++++++++++++++---------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 1ad509892d26a..0f9e6061c32da 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1356,31 +1356,6 @@ impl<Ptr: Deref> Pin<Ptr> {
         Pin { __pointer: pointer }
     }
 
-    /// Unwraps this `Pin<Ptr>`, returning the underlying `Ptr`.
-    ///
-    /// # Safety
-    ///
-    /// This function is unsafe. You must guarantee that you will continue to
-    /// treat the pointer `Ptr` as pinned after you call this function, so that
-    /// the invariants on the `Pin` type can be upheld. If the code using the
-    /// resulting `Ptr` does not continue to maintain the pinning invariants that
-    /// is a violation of the API contract and may lead to undefined behavior in
-    /// later (safe) operations.
-    ///
-    /// Note that you must be able to guarantee that the data pointed to by `Ptr`
-    /// will be treated as pinned all the way until its `drop` handler is complete!
-    ///
-    /// *For more information, see the [`pin` module docs][self]*
-    ///
-    /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
-    /// instead.
-    #[inline(always)]
-    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
-    #[stable(feature = "pin_into_inner", since = "1.39.0")]
-    pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr {
-        pin.__pointer
-    }
-
     /// Gets a shared reference to the pinned value this [`Pin`] points to.
     ///
     /// This is a generic method to go from `&Pin<Pointer<T>>` to `Pin<&T>`.
@@ -1504,6 +1479,31 @@ impl<Ptr: Deref> Pin<Ptr> {
     {
         *(self.__pointer) = value;
     }
+
+    /// Unwraps this `Pin<Ptr>`, returning the underlying `Ptr`.
+    ///
+    /// # Safety
+    ///
+    /// This function is unsafe. You must guarantee that you will continue to
+    /// treat the pointer `Ptr` as pinned after you call this function, so that
+    /// the invariants on the `Pin` type can be upheld. If the code using the
+    /// resulting `Ptr` does not continue to maintain the pinning invariants that
+    /// is a violation of the API contract and may lead to undefined behavior in
+    /// later (safe) operations.
+    ///
+    /// Note that you must be able to guarantee that the data pointed to by `Ptr`
+    /// will be treated as pinned all the way until its `drop` handler is complete!
+    ///
+    /// *For more information, see the [`pin` module docs][self]*
+    ///
+    /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used
+    /// instead.
+    #[inline(always)]
+    #[rustc_const_unstable(feature = "const_pin", issue = "76654")]
+    #[stable(feature = "pin_into_inner", since = "1.39.0")]
+    pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr {
+        pin.__pointer
+    }
 }
 
 impl<'a, T: ?Sized> Pin<&'a T> {

From 62f7d5305e2f702fae205105dffb22447c5b1e6d Mon Sep 17 00:00:00 2001
From: Scott McMurray <scottmcm@users.noreply.github.com>
Date: Fri, 23 Aug 2024 12:02:26 -0700
Subject: [PATCH 07/12] Update `compiler_builtins` to `0.1.121`

---
 library/Cargo.lock       | 4 ++--
 library/alloc/Cargo.toml | 2 +-
 library/std/Cargo.toml   | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/library/Cargo.lock b/library/Cargo.lock
index f2f446b61085d..aa22181a4639a 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -58,9 +58,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.120"
+version = "0.1.121"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38c44e9c76d996d8049dee591a997eab801069ad86ed892ed3039f68b73d301c"
+checksum = "ce956e6dc07082ec481f0935a51e83b343f8ca51be560452c0ebf830d0bdf5a5"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 43799acc02736..a39a0a6ce0ea2 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2021"
 
 [dependencies]
 core = { path = "../core" }
-compiler_builtins = { version = "0.1.120", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "0.1.121", features = ['rustc-dep-of-std'] }
 
 [dev-dependencies]
 rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index dca42a3e98ec1..334c75df2315a 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core", public = true }
-compiler_builtins = { version = "0.1.120" }
+compiler_builtins = { version = "0.1.121" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.14", default-features = false, features = [

From 5c6285c5f07a7cb47eff6efe90a9dc20634c3b2d Mon Sep 17 00:00:00 2001
From: Thom Chiovoloni <chiovolonit@gmail.com>
Date: Fri, 23 Aug 2024 19:16:01 +0000
Subject: [PATCH 08/12] Add myself to the review rotation for libs

---
 triagebot.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/triagebot.toml b/triagebot.toml
index 9bb1befb69983..d7bc60e6c6f09 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -951,6 +951,7 @@ libs = [
     "@joboet",
     "@jhpratt",
     "@tgross35",
+    "@thomcc",
 ]
 bootstrap = [
     "@Mark-Simulacrum",

From 5cef88c1f492beff80d6694b118ea7526c135185 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Thu, 22 Aug 2024 21:07:29 +0000
Subject: [PATCH 09/12] Print the generic parameter along with the variance in
 dumps.

---
 .../rustc_hir_analysis/src/variance/dump.rs   | 32 ++++++++++++++-----
 tests/ui/error-codes/E0208.rs                 |  2 +-
 tests/ui/error-codes/E0208.stderr             |  2 +-
 .../impl-trait/capture-lifetime-not-in-hir.rs |  4 +--
 .../capture-lifetime-not-in-hir.stderr        |  4 +--
 .../impl-trait/implicit-capture-late.stderr   |  2 +-
 tests/ui/impl-trait/in-trait/variance.rs      | 12 ++++---
 tests/ui/impl-trait/in-trait/variance.stderr  | 12 +++----
 tests/ui/impl-trait/variance.e2024.stderr     |  8 ++---
 tests/ui/impl-trait/variance.new.stderr       |  8 ++---
 tests/ui/impl-trait/variance.old.stderr       |  6 ++--
 tests/ui/impl-trait/variance.rs               | 14 ++++----
 tests/ui/type-alias-impl-trait/variance.rs    | 32 +++++++++----------
 .../ui/type-alias-impl-trait/variance.stderr  | 32 +++++++++----------
 .../ui/variance/variance-associated-consts.rs |  2 +-
 .../variance-associated-consts.stderr         |  2 +-
 .../ui/variance/variance-associated-types.rs  |  4 +--
 .../variance/variance-associated-types.stderr |  4 +--
 tests/ui/variance/variance-object-types.rs    |  2 +-
 .../ui/variance/variance-object-types.stderr  |  2 +-
 tests/ui/variance/variance-regions-direct.rs  | 14 ++++----
 .../variance/variance-regions-direct.stderr   | 14 ++++----
 .../ui/variance/variance-regions-indirect.rs  | 10 +++---
 .../variance/variance-regions-indirect.stderr | 10 +++---
 tests/ui/variance/variance-trait-bounds.rs    |  8 ++---
 .../ui/variance/variance-trait-bounds.stderr  |  8 ++---
 .../variance/variance-trait-object-bound.rs   |  2 +-
 .../variance-trait-object-bound.stderr        |  2 +-
 tests/ui/variance/variance-types-bounds.rs    | 10 +++---
 .../ui/variance/variance-types-bounds.stderr  | 10 +++---
 tests/ui/variance/variance-types.rs           | 12 +++----
 tests/ui/variance/variance-types.stderr       | 12 +++----
 32 files changed, 158 insertions(+), 140 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/variance/dump.rs b/compiler/rustc_hir_analysis/src/variance/dump.rs
index 1a17dabb677ac..ace183986bd00 100644
--- a/compiler/rustc_hir_analysis/src/variance/dump.rs
+++ b/compiler/rustc_hir_analysis/src/variance/dump.rs
@@ -1,18 +1,36 @@
+use std::fmt::Write;
+
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_middle::ty::TyCtxt;
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_middle::ty::{GenericArgs, TyCtxt};
 use rustc_span::symbol::sym;
 
+fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
+    let variances = tcx.variances_of(def_id);
+    let generics = GenericArgs::identity_for_item(tcx, def_id);
+    // 7 = 2-letter parameter + ": " + 1-letter variance + ", "
+    let mut ret = String::with_capacity(2 + 7 * variances.len());
+    ret.push('[');
+    for (arg, variance) in generics.iter().zip(variances.iter()) {
+        write!(ret, "{arg}: {variance:?}, ").unwrap();
+    }
+    // Remove trailing `, `.
+    if !variances.is_empty() {
+        ret.pop();
+        ret.pop();
+    }
+    ret.push(']');
+    ret
+}
+
 pub(crate) fn variances(tcx: TyCtxt<'_>) {
     if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
         for id in tcx.hir().items() {
             let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
 
-            let variances = tcx.variances_of(id.owner_id);
-
             tcx.dcx().emit_err(crate::errors::VariancesOf {
                 span: tcx.def_span(id.owner_id),
-                variances: format!("{variances:?}"),
+                variances: format_variances(tcx, id.owner_id.def_id),
             });
         }
     }
@@ -22,11 +40,9 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) {
             continue;
         }
 
-        let variances = tcx.variances_of(id.owner_id);
-
         tcx.dcx().emit_err(crate::errors::VariancesOf {
             span: tcx.def_span(id.owner_id),
-            variances: format!("{variances:?}"),
+            variances: format_variances(tcx, id.owner_id.def_id),
         });
     }
 }
diff --git a/tests/ui/error-codes/E0208.rs b/tests/ui/error-codes/E0208.rs
index 74c138af483c1..2713ba6ed6cb5 100644
--- a/tests/ui/error-codes/E0208.rs
+++ b/tests/ui/error-codes/E0208.rs
@@ -1,7 +1,7 @@
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-struct Foo<'a, T> { //~ ERROR [+, o]
+struct Foo<'a, T> { //~ ERROR ['a: +, T: o]
     t: &'a mut T,
 }
 
diff --git a/tests/ui/error-codes/E0208.stderr b/tests/ui/error-codes/E0208.stderr
index 77b6ceae4dcee..a39e93afab3e1 100644
--- a/tests/ui/error-codes/E0208.stderr
+++ b/tests/ui/error-codes/E0208.stderr
@@ -1,4 +1,4 @@
-error: [+, o]
+error: ['a: +, T: o]
   --> $DIR/E0208.rs:4:1
    |
 LL | struct Foo<'a, T> {
diff --git a/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs b/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs
index 9c067cb693444..2fde0f200c0e5 100644
--- a/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs
+++ b/tests/ui/impl-trait/capture-lifetime-not-in-hir.rs
@@ -6,13 +6,13 @@ trait Bar<'a> {
 }
 
 fn foo<'a, T: Bar<'a>>() -> impl Into<T::Assoc> {
-    //~^ ERROR [o, o]
+    //~^ ERROR ['a: o, T: o]
     // captures both T and 'a invariantly
     ()
 }
 
 fn foo2<'a, T: Bar<'a>>() -> impl Into<T::Assoc> + 'a {
-    //~^ ERROR [o, o, o]
+    //~^ ERROR ['a: o, T: o, 'a: o]
     // captures both T and 'a invariantly, and also duplicates `'a`
     // i.e. the opaque looks like `impl Into<<T as Bar<'a>>::Assoc> + 'a_duplicated`
     ()
diff --git a/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr b/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr
index 9d52001b02460..fe8a2772a00b1 100644
--- a/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr
+++ b/tests/ui/impl-trait/capture-lifetime-not-in-hir.stderr
@@ -1,10 +1,10 @@
-error: [o, o]
+error: ['a: o, T: o]
   --> $DIR/capture-lifetime-not-in-hir.rs:8:29
    |
 LL | fn foo<'a, T: Bar<'a>>() -> impl Into<T::Assoc> {
    |                             ^^^^^^^^^^^^^^^^^^^
 
-error: [o, o, o]
+error: ['a: o, T: o, 'a: o]
   --> $DIR/capture-lifetime-not-in-hir.rs:14:30
    |
 LL | fn foo2<'a, T: Bar<'a>>() -> impl Into<T::Assoc> + 'a {
diff --git a/tests/ui/impl-trait/implicit-capture-late.stderr b/tests/ui/impl-trait/implicit-capture-late.stderr
index 080750f849767..3adf78322d2e5 100644
--- a/tests/ui/impl-trait/implicit-capture-late.stderr
+++ b/tests/ui/impl-trait/implicit-capture-late.stderr
@@ -10,7 +10,7 @@ note: lifetime declared here
 LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
    |                                    ^^
 
-error: [o]
+error: ['a: o]
   --> $DIR/implicit-capture-late.rs:10:55
    |
 LL | fn foo(x: Vec<i32>) -> Box<dyn for<'a> Deref<Target = impl ?Sized>> {
diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs
index 65565dcc2a6f4..0ac44bf7546c2 100644
--- a/tests/ui/impl-trait/in-trait/variance.rs
+++ b/tests/ui/impl-trait/in-trait/variance.rs
@@ -7,14 +7,16 @@ impl<T> Captures<'_> for T {}
 
 trait Foo<'i> {
     fn implicit_capture_early<'a: 'a>() -> impl Sized {}
-    //~^ [o, *, *, o, o]
-    // Self, 'i, 'a, 'i_duplicated, 'a_duplicated
+    //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o]
 
-    fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [o, *, *, o, o]
+    fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {}
+    //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o]
 
-    fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} //~ [o, *, o, o]
+    fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {}
+    //~^ [Self: o, 'i: *, 'a: o, 'i: o]
 
-    fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o, *, o, o]
+    fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
+    //~^ [Self: o, 'i: *, 'a: o, 'i: o]
 }
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr
index 8cae5a92f0dd5..54e0afbaa950d 100644
--- a/tests/ui/impl-trait/in-trait/variance.stderr
+++ b/tests/ui/impl-trait/in-trait/variance.stderr
@@ -1,23 +1,23 @@
-error: [o, *, *, o, o]
+error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:9:44
    |
 LL |     fn implicit_capture_early<'a: 'a>() -> impl Sized {}
    |                                            ^^^^^^^^^^
 
-error: [o, *, *, o, o]
-  --> $DIR/variance.rs:13:44
+error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o]
+  --> $DIR/variance.rs:12:44
    |
 LL |     fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {}
    |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, *, o, o]
+error: [Self: o, 'i: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:15:48
    |
 LL |     fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {}
    |                                                ^^^^^^^^^^
 
-error: [o, *, o, o]
-  --> $DIR/variance.rs:17:48
+error: [Self: o, 'i: *, 'a: o, 'i: o]
+  --> $DIR/variance.rs:18:48
    |
 LL |     fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
    |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/variance.e2024.stderr b/tests/ui/impl-trait/variance.e2024.stderr
index 1724505574413..011ab3259c477 100644
--- a/tests/ui/impl-trait/variance.e2024.stderr
+++ b/tests/ui/impl-trait/variance.e2024.stderr
@@ -1,22 +1,22 @@
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:14:36
    |
 LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
    |                                    ^^^^^^^^^^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:19:32
    |
 LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o]
+error: ['a: o]
   --> $DIR/variance.rs:21:40
    |
 LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
    |                                        ^^^^^^^^^^
 
-error: [o]
+error: ['a: o]
   --> $DIR/variance.rs:26:36
    |
 LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
diff --git a/tests/ui/impl-trait/variance.new.stderr b/tests/ui/impl-trait/variance.new.stderr
index 1724505574413..011ab3259c477 100644
--- a/tests/ui/impl-trait/variance.new.stderr
+++ b/tests/ui/impl-trait/variance.new.stderr
@@ -1,22 +1,22 @@
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:14:36
    |
 LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
    |                                    ^^^^^^^^^^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:19:32
    |
 LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o]
+error: ['a: o]
   --> $DIR/variance.rs:21:40
    |
 LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
    |                                        ^^^^^^^^^^
 
-error: [o]
+error: ['a: o]
   --> $DIR/variance.rs:26:36
    |
 LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
diff --git a/tests/ui/impl-trait/variance.old.stderr b/tests/ui/impl-trait/variance.old.stderr
index 9410b54b491a8..ac3bcd2723fb3 100644
--- a/tests/ui/impl-trait/variance.old.stderr
+++ b/tests/ui/impl-trait/variance.old.stderr
@@ -1,10 +1,10 @@
-error: [*]
+error: ['a: *]
   --> $DIR/variance.rs:14:36
    |
 LL | fn not_captured_early<'a: 'a>() -> impl Sized {}
    |                                    ^^^^^^^^^^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:19:32
    |
 LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {}
@@ -16,7 +16,7 @@ error: []
 LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
    |                                        ^^^^^^^^^^
 
-error: [o]
+error: ['a: o]
   --> $DIR/variance.rs:26:36
    |
 LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {}
diff --git a/tests/ui/impl-trait/variance.rs b/tests/ui/impl-trait/variance.rs
index 72b4a831badcb..43f7207a90423 100644
--- a/tests/ui/impl-trait/variance.rs
+++ b/tests/ui/impl-trait/variance.rs
@@ -12,17 +12,17 @@ trait Captures<'a> {}
 impl<T> Captures<'_> for T {}
 
 fn not_captured_early<'a: 'a>() -> impl Sized {}
-//[old]~^ [*]
-//[new]~^^ [*, o]
-//[e2024]~^^^ [*, o]
+//[old]~^ ['a: *]
+//[new]~^^ ['a: *, 'a: o]
+//[e2024]~^^^ ['a: *, 'a: o]
 
-fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [*, o]
+fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ ['a: *, 'a: o]
 
 fn not_captured_late<'a>(_: &'a ()) -> impl Sized {}
 //[old]~^ []
-//[new]~^^ [o]
-//[e2024]~^^^ [o]
+//[new]~^^ ['a: o]
+//[e2024]~^^^ ['a: o]
 
-fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o]
+fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ ['a: o]
 
 fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs
index ba52eaa035971..113f6a4cc4491 100644
--- a/tests/ui/type-alias-impl-trait/variance.rs
+++ b/tests/ui/type-alias-impl-trait/variance.rs
@@ -5,21 +5,21 @@
 trait Captures<'a> {}
 impl<T> Captures<'_> for T {}
 
-type NotCapturedEarly<'a> = impl Sized; //~ [*, o]
+type NotCapturedEarly<'a> = impl Sized; //~ ['a: *, 'a: o]
 //~^ ERROR: unconstrained opaque type
 
-type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ [*, o]
+type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ ['a: *, 'a: o]
 //~^ ERROR: unconstrained opaque type
 
-type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ [*, o, o]
+type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ ['a: *, 'b: o, 'a: o]
 //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
 //~| ERROR: unconstrained opaque type
 
-type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ [*, o, o]
+type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ ['a: *, 'b: o, 'a: o]
 //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
 //~| ERROR: unconstrained opaque type
 
-type Bar<'a, 'b: 'b, T> = impl Sized; //~ ERROR [*, *, o, o, o]
+type Bar<'a, 'b: 'b, T> = impl Sized; //~ ERROR ['a: *, 'b: *, T: o, 'a: o, 'b: o]
 //~^ ERROR: unconstrained opaque type
 
 trait Foo<'i> {
@@ -31,24 +31,24 @@ trait Foo<'i> {
 }
 
 impl<'i> Foo<'i> for &'i () {
-    type ImplicitCapture<'a> = impl Sized; //~ [*, *, o, o]
+    type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [*, *, o, o]
+    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [*, *, o, o]
+    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
     //~^ ERROR: unconstrained opaque type
 }
 
 impl<'i> Foo<'i> for () {
-    type ImplicitCapture<'a> = impl Sized; //~ [*, *, o, o]
+    type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ [*, *, o, o]
+    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ [*, *, o, o]
+    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
     //~^ ERROR: unconstrained opaque type
 }
 
@@ -59,15 +59,15 @@ impl<'a> Nesting<'a> for &'a () {
     type Output = &'a ();
 }
 type NestedDeeply<'a> =
-    impl Nesting< //~ [*, o]
+    impl Nesting< //~ ['a: *, 'a: o]
         'a,
-        Output = impl Nesting< //~ [*, o]
+        Output = impl Nesting< //~ ['a: *, 'a: o]
             'a,
-            Output = impl Nesting< //~ [*, o]
+            Output = impl Nesting< //~ ['a: *, 'a: o]
                 'a,
-                Output = impl Nesting< //~ [*, o]
+                Output = impl Nesting< //~ ['a: *, 'a: o]
                     'a,
-                    Output = impl Nesting<'a> //~ [*, o]
+                    Output = impl Nesting<'a> //~ ['a: *, 'a: o]
                 >
             >,
         >,
diff --git a/tests/ui/type-alias-impl-trait/variance.stderr b/tests/ui/type-alias-impl-trait/variance.stderr
index e5ced7a498171..489dfe03d446c 100644
--- a/tests/ui/type-alias-impl-trait/variance.stderr
+++ b/tests/ui/type-alias-impl-trait/variance.stderr
@@ -110,73 +110,73 @@ LL |     type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>;
    |
    = note: `ExplicitCaptureFromGat` must be used in combination with a concrete type within the same impl
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:8:29
    |
 LL | type NotCapturedEarly<'a> = impl Sized;
    |                             ^^^^^^^^^^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:11:26
    |
 LL | type CapturedEarly<'a> = impl Sized + Captures<'a>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, o, o]
+error: ['a: *, 'b: o, 'a: o]
   --> $DIR/variance.rs:14:56
    |
 LL | type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>;
    |                                                        ^^^^^^^^^^
 
-error: [*, o, o]
+error: ['a: *, 'b: o, 'a: o]
   --> $DIR/variance.rs:18:49
    |
 LL | type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>;
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, *, o, o, o]
+error: ['a: *, 'b: *, T: o, 'a: o, 'b: o]
   --> $DIR/variance.rs:22:27
    |
 LL | type Bar<'a, 'b: 'b, T> = impl Sized;
    |                           ^^^^^^^^^^
 
-error: [*, *, o, o]
+error: ['i: *, 'a: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:34:32
    |
 LL |     type ImplicitCapture<'a> = impl Sized;
    |                                ^^^^^^^^^^
 
-error: [*, *, o, o]
+error: ['i: *, 'a: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:37:42
    |
 LL |     type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>;
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, *, o, o]
+error: ['i: *, 'a: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:40:39
    |
 LL |     type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>;
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, *, o, o]
+error: ['i: *, 'a: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:45:32
    |
 LL |     type ImplicitCapture<'a> = impl Sized;
    |                                ^^^^^^^^^^
 
-error: [*, *, o, o]
+error: ['i: *, 'a: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:48:42
    |
 LL |     type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>;
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, *, o, o]
+error: ['i: *, 'a: *, 'a: o, 'i: o]
   --> $DIR/variance.rs:51:39
    |
 LL |     type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>;
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:62:5
    |
 LL | /     impl Nesting<
@@ -188,7 +188,7 @@ LL | |         >,
 LL | |     >;
    | |_____^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:64:18
    |
 LL |           Output = impl Nesting<
@@ -201,7 +201,7 @@ LL | |             >,
 LL | |         >,
    | |_________^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:66:22
    |
 LL |               Output = impl Nesting<
@@ -214,7 +214,7 @@ LL | |                 >
 LL | |             >,
    | |_____________^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:68:26
    |
 LL |                   Output = impl Nesting<
@@ -224,7 +224,7 @@ LL | |                     Output = impl Nesting<'a>
 LL | |                 >
    | |_________________^
 
-error: [*, o]
+error: ['a: *, 'a: o]
   --> $DIR/variance.rs:70:30
    |
 LL |                     Output = impl Nesting<'a>
diff --git a/tests/ui/variance/variance-associated-consts.rs b/tests/ui/variance/variance-associated-consts.rs
index 6a44a94df3fdd..97edb7e266ad0 100644
--- a/tests/ui/variance/variance-associated-consts.rs
+++ b/tests/ui/variance/variance-associated-consts.rs
@@ -10,7 +10,7 @@ trait Trait {
 }
 
 #[rustc_variance]
-struct Foo<T: Trait> { //~ ERROR [o]
+struct Foo<T: Trait> { //~ ERROR [T: o]
     field: [u8; <T as Trait>::Const]
     //~^ ERROR: unconstrained generic constant
 }
diff --git a/tests/ui/variance/variance-associated-consts.stderr b/tests/ui/variance/variance-associated-consts.stderr
index b955a7686c2a7..5c3ed93464ac6 100644
--- a/tests/ui/variance/variance-associated-consts.stderr
+++ b/tests/ui/variance/variance-associated-consts.stderr
@@ -9,7 +9,7 @@ help: try adding a `where` bound
 LL | struct Foo<T: Trait> where [(); <T as Trait>::Const]: {
    |                      ++++++++++++++++++++++++++++++++
 
-error: [o]
+error: [T: o]
   --> $DIR/variance-associated-consts.rs:13:1
    |
 LL | struct Foo<T: Trait> {
diff --git a/tests/ui/variance/variance-associated-types.rs b/tests/ui/variance/variance-associated-types.rs
index ecb0821827dc0..07ff41062e881 100644
--- a/tests/ui/variance/variance-associated-types.rs
+++ b/tests/ui/variance/variance-associated-types.rs
@@ -10,12 +10,12 @@ trait Trait<'a> {
 }
 
 #[rustc_variance]
-struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +]
+struct Foo<'a, T : Trait<'a>> { //~ ERROR ['a: +, T: +]
     field: (T, &'a ())
 }
 
 #[rustc_variance]
-struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o]
+struct Bar<'a, T : Trait<'a>> { //~ ERROR ['a: o, T: o]
     field: <T as Trait<'a>>::Type
 }
 
diff --git a/tests/ui/variance/variance-associated-types.stderr b/tests/ui/variance/variance-associated-types.stderr
index 70cb246f6e906..ca010b7e7ef40 100644
--- a/tests/ui/variance/variance-associated-types.stderr
+++ b/tests/ui/variance/variance-associated-types.stderr
@@ -1,10 +1,10 @@
-error: [+, +]
+error: ['a: +, T: +]
   --> $DIR/variance-associated-types.rs:13:1
    |
 LL | struct Foo<'a, T : Trait<'a>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, o]
+error: ['a: o, T: o]
   --> $DIR/variance-associated-types.rs:18:1
    |
 LL | struct Bar<'a, T : Trait<'a>> {
diff --git a/tests/ui/variance/variance-object-types.rs b/tests/ui/variance/variance-object-types.rs
index 6ded24cd1e9ed..fd03dec982492 100644
--- a/tests/ui/variance/variance-object-types.rs
+++ b/tests/ui/variance/variance-object-types.rs
@@ -4,7 +4,7 @@
 // For better or worse, associated types are invariant, and hence we
 // get an invariant result for `'a`.
 #[rustc_variance]
-struct Foo<'a> { //~ ERROR [o]
+struct Foo<'a> { //~ ERROR ['a: o]
     x: Box<dyn Fn(i32) -> &'a i32 + 'static>
 }
 
diff --git a/tests/ui/variance/variance-object-types.stderr b/tests/ui/variance/variance-object-types.stderr
index 963f3454e1baf..a6fb9b2403a6b 100644
--- a/tests/ui/variance/variance-object-types.stderr
+++ b/tests/ui/variance/variance-object-types.stderr
@@ -1,4 +1,4 @@
-error: [o]
+error: ['a: o]
   --> $DIR/variance-object-types.rs:7:1
    |
 LL | struct Foo<'a> {
diff --git a/tests/ui/variance/variance-regions-direct.rs b/tests/ui/variance/variance-regions-direct.rs
index f1763c403f1a1..2bcacec33ea5a 100644
--- a/tests/ui/variance/variance-regions-direct.rs
+++ b/tests/ui/variance/variance-regions-direct.rs
@@ -6,7 +6,7 @@
 // Regions that just appear in normal spots are contravariant:
 
 #[rustc_variance]
-struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +]
+struct Test2<'a, 'b, 'c> { //~ ERROR ['a: +, 'b: +, 'c: +]
     x: &'a isize,
     y: &'b [isize],
     c: &'c str
@@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +]
 // Those same annotations in function arguments become covariant:
 
 #[rustc_variance]
-struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -]
+struct Test3<'a, 'b, 'c> { //~ ERROR ['a: -, 'b: -, 'c: -]
     x: extern "Rust" fn(&'a isize),
     y: extern "Rust" fn(&'b [isize]),
     c: extern "Rust" fn(&'c str),
@@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -]
 // Mutability induces invariance:
 
 #[rustc_variance]
-struct Test4<'a, 'b:'a> { //~ ERROR [+, o]
+struct Test4<'a, 'b:'a> { //~ ERROR ['a: +, 'b: o]
     x: &'a mut &'b isize,
 }
 
@@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [+, o]
 // contravariant context:
 
 #[rustc_variance]
-struct Test5<'a, 'b:'a> { //~ ERROR [-, o]
+struct Test5<'a, 'b:'a> { //~ ERROR ['a: -, 'b: o]
     x: extern "Rust" fn(&'a mut &'b isize),
 }
 
@@ -42,14 +42,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR [-, o]
 // argument list occurs in an invariant context.
 
 #[rustc_variance]
-struct Test6<'a, 'b:'a> { //~ ERROR [+, o]
+struct Test6<'a, 'b:'a> { //~ ERROR ['a: +, 'b: o]
     x: &'a mut extern "Rust" fn(&'b isize),
 }
 
 // No uses at all is bivariant:
 
 #[rustc_variance]
-struct Test7<'a> { //~ ERROR [*]
+struct Test7<'a> { //~ ERROR ['a: *]
     //~^ ERROR: `'a` is never used
     x: isize
 }
@@ -57,7 +57,7 @@ struct Test7<'a> { //~ ERROR [*]
 // Try enums too.
 
 #[rustc_variance]
-enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR ['a: -, 'b: +, 'c: o]
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
     Test8C(&'b mut &'c str),
diff --git a/tests/ui/variance/variance-regions-direct.stderr b/tests/ui/variance/variance-regions-direct.stderr
index edfc888f65667..45ce0303fb251 100644
--- a/tests/ui/variance/variance-regions-direct.stderr
+++ b/tests/ui/variance/variance-regions-direct.stderr
@@ -6,43 +6,43 @@ LL | struct Test7<'a> {
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
-error: [+, +, +]
+error: ['a: +, 'b: +, 'c: +]
   --> $DIR/variance-regions-direct.rs:9:1
    |
 LL | struct Test2<'a, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [-, -, -]
+error: ['a: -, 'b: -, 'c: -]
   --> $DIR/variance-regions-direct.rs:18:1
    |
 LL | struct Test3<'a, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+, o]
+error: ['a: +, 'b: o]
   --> $DIR/variance-regions-direct.rs:27:1
    |
 LL | struct Test4<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [-, o]
+error: ['a: -, 'b: o]
   --> $DIR/variance-regions-direct.rs:35:1
    |
 LL | struct Test5<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+, o]
+error: ['a: +, 'b: o]
   --> $DIR/variance-regions-direct.rs:45:1
    |
 LL | struct Test6<'a, 'b:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*]
+error: ['a: *]
   --> $DIR/variance-regions-direct.rs:52:1
    |
 LL | struct Test7<'a> {
    | ^^^^^^^^^^^^^^^^
 
-error: [-, +, o]
+error: ['a: -, 'b: +, 'c: o]
   --> $DIR/variance-regions-direct.rs:60:1
    |
 LL | enum Test8<'a, 'b, 'c:'b> {
diff --git a/tests/ui/variance/variance-regions-indirect.rs b/tests/ui/variance/variance-regions-indirect.rs
index 31e25641d8c3a..aaa4d3f877995 100644
--- a/tests/ui/variance/variance-regions-indirect.rs
+++ b/tests/ui/variance/variance-regions-indirect.rs
@@ -5,7 +5,7 @@
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR ['a: -, 'b: +, 'c: o, 'd: *]
     //~^ ERROR: `'d` is never used
     Test8A(extern "Rust" fn(&'a isize)),
     Test8B(&'b [isize]),
@@ -13,25 +13,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *]
 }
 
 #[rustc_variance]
-struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR ['w: *, 'x: o, 'y: +, 'z: -]
     //~^ ERROR: `'w` is never used
     f: Base<'z, 'y, 'x, 'w>
 }
 
 #[rustc_variance] // Combine - and + to yield o
-struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
+struct Derived2<'a, 'b:'a, 'c> { //~ ERROR ['a: o, 'b: o, 'c: *]
     //~^ ERROR: `'c` is never used
     f: Base<'a, 'a, 'b, 'c>
 }
 
 #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
-struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *]
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR ['a: o, 'b: +, 'c: *]
     //~^ ERROR: `'c` is never used
     f: Base<'a, 'b, 'a, 'c>
 }
 
 #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
-struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR ['a: -, 'b: +, 'c: o]
     f: Base<'a, 'b, 'c, 'a>
 }
 
diff --git a/tests/ui/variance/variance-regions-indirect.stderr b/tests/ui/variance/variance-regions-indirect.stderr
index 901ec0c6a762b..ed839b3235009 100644
--- a/tests/ui/variance/variance-regions-indirect.stderr
+++ b/tests/ui/variance/variance-regions-indirect.stderr
@@ -30,31 +30,31 @@ LL | struct Derived3<'a:'b, 'b, 'c> {
    |
    = help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData`
 
-error: [-, +, o, *]
+error: ['a: -, 'b: +, 'c: o, 'd: *]
   --> $DIR/variance-regions-indirect.rs:8:1
    |
 LL | enum Base<'a, 'b, 'c:'b, 'd> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, o, +, -]
+error: ['w: *, 'x: o, 'y: +, 'z: -]
   --> $DIR/variance-regions-indirect.rs:16:1
    |
 LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, o, *]
+error: ['a: o, 'b: o, 'c: *]
   --> $DIR/variance-regions-indirect.rs:22:1
    |
 LL | struct Derived2<'a, 'b:'a, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, +, *]
+error: ['a: o, 'b: +, 'c: *]
   --> $DIR/variance-regions-indirect.rs:28:1
    |
 LL | struct Derived3<'a:'b, 'b, 'c> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [-, +, o]
+error: ['a: -, 'b: +, 'c: o]
   --> $DIR/variance-regions-indirect.rs:34:1
    |
 LL | struct Derived4<'a, 'b, 'c:'b> {
diff --git a/tests/ui/variance/variance-trait-bounds.rs b/tests/ui/variance/variance-trait-bounds.rs
index 25a01b160ddd1..f86fa2bbef7a0 100644
--- a/tests/ui/variance/variance-trait-bounds.rs
+++ b/tests/ui/variance/variance-trait-bounds.rs
@@ -13,24 +13,24 @@ trait Setter<T> {
 }
 
 #[rustc_variance]
-struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +]
+struct TestStruct<U,T:Setter<U>> { //~ ERROR [U: +, T: +]
     t: T, u: U
 }
 
 #[rustc_variance]
-enum TestEnum<U,T:Setter<U>> { //~ ERROR [*, +]
+enum TestEnum<U,T:Setter<U>> { //~ ERROR [U: *, T: +]
     //~^ ERROR: `U` is never used
     Foo(T)
 }
 
 #[rustc_variance]
-struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
+struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [U: *, T: +]
     //~^ ERROR: `U` is never used
     t: T
 }
 
 #[rustc_variance]
-struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +]
+struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [U: *, T: +]
     //~^ ERROR: `U` is never used
     t: T
 }
diff --git a/tests/ui/variance/variance-trait-bounds.stderr b/tests/ui/variance/variance-trait-bounds.stderr
index 95ed18c1ad2bf..49cee3cbeca75 100644
--- a/tests/ui/variance/variance-trait-bounds.stderr
+++ b/tests/ui/variance/variance-trait-bounds.stderr
@@ -25,25 +25,25 @@ LL | struct TestBox<U,T:Getter<U>+Setter<U>> {
    = help: consider removing `U`, referring to it in a field, or using a marker such as `PhantomData`
    = help: if you intended `U` to be a const parameter, use `const U: /* Type */` instead
 
-error: [+, +]
+error: [U: +, T: +]
   --> $DIR/variance-trait-bounds.rs:16:1
    |
 LL | struct TestStruct<U,T:Setter<U>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, +]
+error: [U: *, T: +]
   --> $DIR/variance-trait-bounds.rs:21:1
    |
 LL | enum TestEnum<U,T:Setter<U>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, +]
+error: [U: *, T: +]
   --> $DIR/variance-trait-bounds.rs:27:1
    |
 LL | struct TestContraStruct<U,T:Setter<U>> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [*, +]
+error: [U: *, T: +]
   --> $DIR/variance-trait-bounds.rs:33:1
    |
 LL | struct TestBox<U,T:Getter<U>+Setter<U>> {
diff --git a/tests/ui/variance/variance-trait-object-bound.rs b/tests/ui/variance/variance-trait-object-bound.rs
index 11303c4652005..ca80c6b6dce22 100644
--- a/tests/ui/variance/variance-trait-object-bound.rs
+++ b/tests/ui/variance/variance-trait-object-bound.rs
@@ -11,7 +11,7 @@ use std::mem;
 trait T { fn foo(&self); }
 
 #[rustc_variance]
-struct TOption<'a> { //~ ERROR [+]
+struct TOption<'a> { //~ ERROR ['a: +]
     v: Option<Box<dyn T + 'a>>,
 }
 
diff --git a/tests/ui/variance/variance-trait-object-bound.stderr b/tests/ui/variance/variance-trait-object-bound.stderr
index f0471a3461925..0af21ec12cc9b 100644
--- a/tests/ui/variance/variance-trait-object-bound.stderr
+++ b/tests/ui/variance/variance-trait-object-bound.stderr
@@ -1,4 +1,4 @@
-error: [+]
+error: ['a: +]
   --> $DIR/variance-trait-object-bound.rs:14:1
    |
 LL | struct TOption<'a> {
diff --git a/tests/ui/variance/variance-types-bounds.rs b/tests/ui/variance/variance-types-bounds.rs
index d1814dd97a0ad..f4738a2dae1ab 100644
--- a/tests/ui/variance/variance-types-bounds.rs
+++ b/tests/ui/variance/variance-types-bounds.rs
@@ -4,24 +4,24 @@
 #![feature(rustc_attrs)]
 
 #[rustc_variance]
-struct TestImm<A, B> { //~ ERROR [+, +]
+struct TestImm<A, B> { //~ ERROR [A: +, B: +]
     x: A,
     y: B,
 }
 
 #[rustc_variance]
-struct TestMut<A, B:'static> { //~ ERROR [+, o]
+struct TestMut<A, B:'static> { //~ ERROR [A: +, B: o]
     x: A,
     y: &'static mut B,
 }
 
 #[rustc_variance]
-struct TestIndirect<A:'static, B:'static> { //~ ERROR [+, o]
+struct TestIndirect<A:'static, B:'static> { //~ ERROR [A: +, B: o]
     m: TestMut<A, B>
 }
 
 #[rustc_variance]
-struct TestIndirect2<A:'static, B:'static> { //~ ERROR [o, o]
+struct TestIndirect2<A:'static, B:'static> { //~ ERROR [A: o, B: o]
     n: TestMut<A, B>,
     m: TestMut<B, A>
 }
@@ -35,7 +35,7 @@ trait Setter<A> {
 }
 
 #[rustc_variance]
-struct TestObject<A, R> { //~ ERROR [o, o]
+struct TestObject<A, R> { //~ ERROR [A: o, R: o]
     n: Box<dyn Setter<A>+Send>,
     m: Box<dyn Getter<R>+Send>,
 }
diff --git a/tests/ui/variance/variance-types-bounds.stderr b/tests/ui/variance/variance-types-bounds.stderr
index bb81644347693..408c2ae8d3682 100644
--- a/tests/ui/variance/variance-types-bounds.stderr
+++ b/tests/ui/variance/variance-types-bounds.stderr
@@ -1,28 +1,28 @@
-error: [+, +]
+error: [A: +, B: +]
   --> $DIR/variance-types-bounds.rs:7:1
    |
 LL | struct TestImm<A, B> {
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: [+, o]
+error: [A: +, B: o]
   --> $DIR/variance-types-bounds.rs:13:1
    |
 LL | struct TestMut<A, B:'static> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+, o]
+error: [A: +, B: o]
   --> $DIR/variance-types-bounds.rs:19:1
    |
 LL | struct TestIndirect<A:'static, B:'static> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, o]
+error: [A: o, B: o]
   --> $DIR/variance-types-bounds.rs:24:1
    |
 LL | struct TestIndirect2<A:'static, B:'static> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o, o]
+error: [A: o, R: o]
   --> $DIR/variance-types-bounds.rs:38:1
    |
 LL | struct TestObject<A, R> {
diff --git a/tests/ui/variance/variance-types.rs b/tests/ui/variance/variance-types.rs
index cfc03b754734d..aa336d1b424c1 100644
--- a/tests/ui/variance/variance-types.rs
+++ b/tests/ui/variance/variance-types.rs
@@ -7,32 +7,32 @@ use std::cell::Cell;
 // not considered bivariant.
 
 #[rustc_variance]
-struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [+, o, o]
+struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR ['a: +, A: o, B: o]
     t: &'a mut (A,B)
 }
 
 #[rustc_variance]
-struct InvariantCell<A> { //~ ERROR [o]
+struct InvariantCell<A> { //~ ERROR [A: o]
     t: Cell<A>
 }
 
 #[rustc_variance]
-struct InvariantIndirect<A> { //~ ERROR [o]
+struct InvariantIndirect<A> { //~ ERROR [A: o]
     t: InvariantCell<A>
 }
 
 #[rustc_variance]
-struct Covariant<A> { //~ ERROR [+]
+struct Covariant<A> { //~ ERROR [A: +]
     t: A, u: fn() -> A
 }
 
 #[rustc_variance]
-struct Contravariant<A> { //~ ERROR [-]
+struct Contravariant<A> { //~ ERROR [A: -]
     t: fn(A)
 }
 
 #[rustc_variance]
-enum Enum<A,B,C> { //~ ERROR [+, -, o]
+enum Enum<A,B,C> { //~ ERROR [A: +, B: -, C: o]
     Foo(Covariant<A>),
     Bar(Contravariant<B>),
     Zed(Covariant<C>,Contravariant<C>)
diff --git a/tests/ui/variance/variance-types.stderr b/tests/ui/variance/variance-types.stderr
index 0fda4b8036e72..f2a6794942553 100644
--- a/tests/ui/variance/variance-types.stderr
+++ b/tests/ui/variance/variance-types.stderr
@@ -1,34 +1,34 @@
-error: [+, o, o]
+error: ['a: +, A: o, B: o]
   --> $DIR/variance-types.rs:10:1
    |
 LL | struct InvariantMut<'a,A:'a,B:'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o]
+error: [A: o]
   --> $DIR/variance-types.rs:15:1
    |
 LL | struct InvariantCell<A> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [o]
+error: [A: o]
   --> $DIR/variance-types.rs:20:1
    |
 LL | struct InvariantIndirect<A> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+]
+error: [A: +]
   --> $DIR/variance-types.rs:25:1
    |
 LL | struct Covariant<A> {
    | ^^^^^^^^^^^^^^^^^^^
 
-error: [-]
+error: [A: -]
   --> $DIR/variance-types.rs:30:1
    |
 LL | struct Contravariant<A> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [+, -, o]
+error: [A: +, B: -, C: o]
   --> $DIR/variance-types.rs:35:1
    |
 LL | enum Enum<A,B,C> {

From 32e34eef576e0fb54cab52e7ba32abe028200377 Mon Sep 17 00:00:00 2001
From: Tshepang Mbambo <tshepang@gmail.com>
Date: Sat, 24 Aug 2024 03:11:00 +0200
Subject: [PATCH 10/12] make text more easy to read

---
 .../rustc/src/platform-support/wasm32-unknown-unknown.md    | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
index ee37e5e90cfb4..dde915f316948 100644
--- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
+++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
@@ -29,10 +29,10 @@ that not all uses of `wasm32-unknown-unknown` are using JavaScript and the web.
 
 ## Target maintainers
 
-When this target was added to the compiler platform-specific documentation here
+When this target was added to the compiler, platform-specific documentation here
 was not maintained at that time. This means that the list below is not
-exhaustive and there are more interested parties in this target. That being
-said since when this document was last updated those interested in maintaining
+exhaustive, and there are more interested parties in this target. That being
+said, when this document was last updated, those interested in maintaining
 this target are:
 
 - Alex Crichton, https://github.com/alexcrichton

From f734f3d8e73f2118fdf4bdaf35e72ace8a442531 Mon Sep 17 00:00:00 2001
From: Tshepang Mbambo <tshepang@gmail.com>
Date: Sat, 24 Aug 2024 05:40:27 +0200
Subject: [PATCH 11/12] remove extraneous text

---
 src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
index dde915f316948..12b7817c38277 100644
--- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
+++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
@@ -32,8 +32,7 @@ that not all uses of `wasm32-unknown-unknown` are using JavaScript and the web.
 When this target was added to the compiler, platform-specific documentation here
 was not maintained at that time. This means that the list below is not
 exhaustive, and there are more interested parties in this target. That being
-said, when this document was last updated, those interested in maintaining
-this target are:
+said, those interested in maintaining this target are:
 
 - Alex Crichton, https://github.com/alexcrichton
 

From 027c47983ee161f3346e6be39c14cfc33d03e169 Mon Sep 17 00:00:00 2001
From: binarycat <binarycat@envs.net>
Date: Sat, 24 Aug 2024 12:35:35 -0400
Subject: [PATCH 12/12] update the doc comment on lintchecker b/c it parses
 html now

---
 src/tools/linkchecker/main.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 72448c1180a97..fa77ab1e011cd 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -6,8 +6,10 @@
 //! script is to check all relative links in our documentation to make sure they
 //! actually point to a valid place.
 //!
-//! Currently this doesn't actually do any HTML parsing or anything fancy like
-//! that, it just has a simple "regex" to search for `href` and `id` tags.
+//! Currently uses a combination of HTML parsing to
+//! extract the `href` and `id` attributes,
+//! and regex search on the orignal markdown to handle intra-doc links.
+//!
 //! These values are then translated to file URLs if possible and then the
 //! destination is asserted to exist.
 //!