about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs109
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs25
-rw-r--r--compiler/rustc_errors/src/lib.rs30
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs7
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs6
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs4
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_lint/src/expect.rs9
-rw-r--r--compiler/rustc_lint/src/levels.rs36
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs8
-rw-r--r--compiler/rustc_middle/src/lint.rs12
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs23
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs35
-rw-r--r--compiler/rustc_typeck/src/collect.rs2
20 files changed, 251 insertions, 112 deletions
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 4b324740a1f..3ce594b945a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -188,8 +188,6 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
         ("x86", "avx512gfni") => smallvec!["gfni"],
         ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
         ("aarch64", "fp") => smallvec!["fp-armv8"],
-        ("aarch64", "fp16") => smallvec!["fullfp16"],
-        ("aarch64", "fhm") => smallvec!["fp16fml"],
         ("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
         ("aarch64", "dpb") => smallvec!["ccpp"],
         ("aarch64", "dpb2") => smallvec!["ccdp"],
@@ -198,6 +196,19 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
         ("aarch64", "pmuv3") => smallvec!["perfmon"],
         ("aarch64", "paca") => smallvec!["pauth"],
         ("aarch64", "pacg") => smallvec!["pauth"],
+        // Rust ties fp and neon together. In LLVM neon implicitly enables fp,
+        // but we manually enable neon when a feature only implicitly enables fp
+        ("aarch64", "f32mm") => smallvec!["f32mm", "neon"],
+        ("aarch64", "f64mm") => smallvec!["f64mm", "neon"],
+        ("aarch64", "fhm") => smallvec!["fp16fml", "neon"],
+        ("aarch64", "fp16") => smallvec!["fullfp16", "neon"],
+        ("aarch64", "jsconv") => smallvec!["jsconv", "neon"],
+        ("aarch64", "sve") => smallvec!["sve", "neon"],
+        ("aarch64", "sve2") => smallvec!["sve2", "neon"],
+        ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"],
+        ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"],
+        ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"],
+        ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
         (_, s) => smallvec![s],
     }
 }
@@ -490,7 +501,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
         if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
             return SmallVec::<[_; 2]>::new();
         }
-        // ... otherwise though we run through `to_llvm_feature when
+        // ... otherwise though we run through `to_llvm_features` when
         // passing requests down to LLVM. This means that all in-language
         // features also work on the command line instead of having two
         // different names when the LLVM name and the Rust name differ.
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index df011d6ca5f..f37c6751381 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -44,105 +44,108 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
 
 const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     // FEAT_AdvSimd
-    ("neon", Some(sym::aarch64_target_feature)),
+    ("neon", None),
     // FEAT_FP
-    ("fp", Some(sym::aarch64_target_feature)),
+    ("fp", None),
     // FEAT_FP16
-    ("fp16", Some(sym::aarch64_target_feature)),
+    ("fp16", None),
     // FEAT_SVE
-    ("sve", Some(sym::aarch64_target_feature)),
+    ("sve", None),
     // FEAT_CRC
-    ("crc", Some(sym::aarch64_target_feature)),
+    ("crc", None),
     // FEAT_RAS
-    ("ras", Some(sym::aarch64_target_feature)),
+    ("ras", None),
     // FEAT_LSE
-    ("lse", Some(sym::aarch64_target_feature)),
+    ("lse", None),
     // FEAT_RDM
-    ("rdm", Some(sym::aarch64_target_feature)),
+    ("rdm", None),
     // FEAT_RCPC
-    ("rcpc", Some(sym::aarch64_target_feature)),
+    ("rcpc", None),
     // FEAT_RCPC2
-    ("rcpc2", Some(sym::aarch64_target_feature)),
+    ("rcpc2", None),
     // FEAT_DotProd
-    ("dotprod", Some(sym::aarch64_target_feature)),
+    ("dotprod", None),
     // FEAT_TME
-    ("tme", Some(sym::aarch64_target_feature)),
+    ("tme", None),
     // FEAT_FHM
-    ("fhm", Some(sym::aarch64_target_feature)),
+    ("fhm", None),
     // FEAT_DIT
-    ("dit", Some(sym::aarch64_target_feature)),
+    ("dit", None),
     // FEAT_FLAGM
-    ("flagm", Some(sym::aarch64_target_feature)),
+    ("flagm", None),
     // FEAT_SSBS
-    ("ssbs", Some(sym::aarch64_target_feature)),
+    ("ssbs", None),
     // FEAT_SB
-    ("sb", Some(sym::aarch64_target_feature)),
+    ("sb", None),
     // FEAT_PAUTH (address authentication)
-    ("paca", Some(sym::aarch64_target_feature)),
+    ("paca", None),
     // FEAT_PAUTH (generic authentication)
-    ("pacg", Some(sym::aarch64_target_feature)),
+    ("pacg", None),
     // FEAT_DPB
-    ("dpb", Some(sym::aarch64_target_feature)),
+    ("dpb", None),
     // FEAT_DPB2
-    ("dpb2", Some(sym::aarch64_target_feature)),
+    ("dpb2", None),
     // FEAT_SVE2
-    ("sve2", Some(sym::aarch64_target_feature)),
+    ("sve2", None),
     // FEAT_SVE2_AES
-    ("sve2-aes", Some(sym::aarch64_target_feature)),
+    ("sve2-aes", None),
     // FEAT_SVE2_SM4
-    ("sve2-sm4", Some(sym::aarch64_target_feature)),
+    ("sve2-sm4", None),
     // FEAT_SVE2_SHA3
-    ("sve2-sha3", Some(sym::aarch64_target_feature)),
+    ("sve2-sha3", None),
     // FEAT_SVE2_BitPerm
-    ("sve2-bitperm", Some(sym::aarch64_target_feature)),
+    ("sve2-bitperm", None),
     // FEAT_FRINTTS
-    ("frintts", Some(sym::aarch64_target_feature)),
+    ("frintts", None),
     // FEAT_I8MM
-    ("i8mm", Some(sym::aarch64_target_feature)),
+    ("i8mm", None),
     // FEAT_F32MM
-    ("f32mm", Some(sym::aarch64_target_feature)),
+    ("f32mm", None),
     // FEAT_F64MM
-    ("f64mm", Some(sym::aarch64_target_feature)),
+    ("f64mm", None),
     // FEAT_BF16
-    ("bf16", Some(sym::aarch64_target_feature)),
+    ("bf16", None),
     // FEAT_RAND
-    ("rand", Some(sym::aarch64_target_feature)),
+    ("rand", None),
     // FEAT_BTI
-    ("bti", Some(sym::aarch64_target_feature)),
+    ("bti", None),
     // FEAT_MTE
-    ("mte", Some(sym::aarch64_target_feature)),
+    ("mte", None),
     // FEAT_JSCVT
-    ("jsconv", Some(sym::aarch64_target_feature)),
+    ("jsconv", None),
     // FEAT_FCMA
-    ("fcma", Some(sym::aarch64_target_feature)),
+    ("fcma", None),
     // FEAT_AES
-    ("aes", Some(sym::aarch64_target_feature)),
+    ("aes", None),
     // FEAT_SHA1 & FEAT_SHA256
-    ("sha2", Some(sym::aarch64_target_feature)),
+    ("sha2", None),
     // FEAT_SHA512 & FEAT_SHA3
-    ("sha3", Some(sym::aarch64_target_feature)),
+    ("sha3", None),
     // FEAT_SM3 & FEAT_SM4
-    ("sm4", Some(sym::aarch64_target_feature)),
+    ("sm4", None),
     // FEAT_PAN
-    ("pan", Some(sym::aarch64_target_feature)),
+    ("pan", None),
     // FEAT_LOR
-    ("lor", Some(sym::aarch64_target_feature)),
+    ("lor", None),
     // FEAT_VHE
-    ("vh", Some(sym::aarch64_target_feature)),
+    ("vh", None),
     // FEAT_PMUv3
-    ("pmuv3", Some(sym::aarch64_target_feature)),
+    ("pmuv3", None),
     // FEAT_SPE
-    ("spe", Some(sym::aarch64_target_feature)),
-    ("v8.1a", Some(sym::aarch64_target_feature)),
-    ("v8.2a", Some(sym::aarch64_target_feature)),
-    ("v8.3a", Some(sym::aarch64_target_feature)),
-    ("v8.4a", Some(sym::aarch64_target_feature)),
-    ("v8.5a", Some(sym::aarch64_target_feature)),
-    ("v8.6a", Some(sym::aarch64_target_feature)),
-    ("v8.7a", Some(sym::aarch64_target_feature)),
+    ("spe", None),
+    ("v8.1a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.2a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.3a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.4a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.5a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.6a", Some(sym::aarch64_ver_target_feature)),
+    ("v8.7a", Some(sym::aarch64_ver_target_feature)),
 ];
 
-const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]];
+const AARCH64_TIED_FEATURES: &[&[&str]] = &[
+    &["fp", "neon"],   // Silicon always has both, so avoid needless complications
+    &["paca", "pacg"], // Together these represent `pauth` in LLVM
+];
 
 const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("adx", Some(sym::adx_target_feature)),
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 39ebd57b4b2..5c36c3c55b5 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -5,7 +5,8 @@ use crate::Substitution;
 use crate::SubstitutionPart;
 use crate::SuggestionStyle;
 use crate::ToolMetadata;
-use rustc_lint_defs::Applicability;
+use rustc_data_structures::stable_map::FxHashMap;
+use rustc_lint_defs::{Applicability, LintExpectationId};
 use rustc_serialize::json::Json;
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
@@ -138,6 +139,28 @@ impl Diagnostic {
         }
     }
 
+    pub fn update_unstable_expectation_id(
+        &mut self,
+        unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
+    ) {
+        if let Level::Expect(expectation_id) = &mut self.level {
+            if expectation_id.is_stable() {
+                return;
+            }
+
+            // The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
+            // The lint index inside the attribute is manually transferred here.
+            let lint_index = expectation_id.get_lint_index();
+            expectation_id.set_lint_index(None);
+            let mut stable_id = *unstable_to_stable
+                .get(&expectation_id)
+                .expect("each unstable `LintExpectationId` must have a matching stable id");
+
+            stable_id.set_lint_index(lint_index);
+            *expectation_id = stable_id;
+        }
+    }
+
     pub fn has_future_breakage(&self) -> bool {
         match self.code {
             Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 3641c38f9dc..345247b0700 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -522,6 +522,11 @@ impl Drop for HandlerInner {
                 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
             );
         }
+
+        assert!(
+            self.unstable_expect_diagnostics.is_empty(),
+            "all diagnostics with unstable expectations should have been converted",
+        );
     }
 }
 
@@ -942,29 +947,30 @@ impl Handler {
 
         let mut inner = self.inner.borrow_mut();
         for mut diag in diags.into_iter() {
-            let mut unstable_id = diag
+            diag.update_unstable_expectation_id(unstable_to_stable);
+
+            let stable_id = diag
                 .level
                 .get_expectation_id()
                 .expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`");
-
-            // The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
-            // The lint index inside the attribute is manually transferred here.
-            let lint_index = unstable_id.get_lint_index();
-            unstable_id.set_lint_index(None);
-            let mut stable_id = *unstable_to_stable
-                .get(&unstable_id)
-                .expect("each unstable `LintExpectationId` must have a matching stable id");
-
-            stable_id.set_lint_index(lint_index);
-            diag.level = Level::Expect(stable_id);
             inner.fulfilled_expectations.insert(stable_id);
 
             (*TRACK_DIAGNOSTICS)(&diag);
         }
+
+        inner
+            .stashed_diagnostics
+            .values_mut()
+            .for_each(|diag| diag.update_unstable_expectation_id(unstable_to_stable));
+        inner
+            .future_breakage_diagnostics
+            .iter_mut()
+            .for_each(|diag| diag.update_unstable_expectation_id(unstable_to_stable));
     }
 
     /// This methods steals all [`LintExpectationId`]s that are stored inside
     /// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
+    #[must_use]
     pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
         assert!(
             self.inner.borrow().unstable_expect_diagnostics.is_empty(),
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 88e11693220..f18cf95a2bf 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -337,8 +337,12 @@ fn check_occurrences(
             let name = MacroRulesNormalizedIdent::new(name);
             check_ops_is_prefix(sess, node_id, macros, binders, ops, span, name);
         }
-        // FIXME(c410-f3r) Check token (https://github.com/rust-lang/rust/issues/93902)
-        TokenTree::MetaVarExpr(..) => {}
+        TokenTree::MetaVarExpr(dl, ref mve) => {
+            let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else {
+                return;
+            };
+            check_ops_is_prefix(sess, node_id, macros, binders, ops, dl.entire(), name);
+        }
         TokenTree::Delimited(_, ref del) => {
             check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid);
         }
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index dedfd779bb4..07081c75d46 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -324,8 +324,11 @@ pub(super) fn count_names(ms: &[TokenTree]) -> usize {
                 TokenTree::Delimited(_, ref delim) => count_names(&delim.tts),
                 TokenTree::MetaVar(..) => 0,
                 TokenTree::MetaVarDecl(..) => 1,
-                // FIXME(c410-f3r) MetaVarExpr should be handled instead of being ignored
-                // https://github.com/rust-lang/rust/issues/9390
+                // Panicking here would abort execution because `parse_tree` makes use of this
+                // function. In other words, RHS meta-variable expressions eventually end-up here.
+                //
+                // `0` is still returned to inform that no meta-variable was found. `Meta-variables
+                // != Meta-variable expressions`
                 TokenTree::MetaVarExpr(..) => 0,
                 TokenTree::Sequence(_, ref seq) => seq.num_captures,
                 TokenTree::Token(..) => 0,
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 6c5a755da6f..2949ca716b2 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -62,9 +62,9 @@ impl MetaVarExpr {
         Ok(rslt)
     }
 
-    crate fn ident(&self) -> Option<&Ident> {
-        match self {
-            MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(&ident),
+    crate fn ident(&self) -> Option<Ident> {
+        match *self {
+            MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
             MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
         }
     }
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 387d5895e24..5ec63739cf5 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -399,7 +399,7 @@ fn lockstep_iter_size(
         TokenTree::MetaVarExpr(_, ref expr) => {
             let default_rslt = LockstepIterSize::Unconstrained;
             let Some(ident) = expr.ident() else { return default_rslt; };
-            let name = MacroRulesNormalizedIdent::new(ident.clone());
+            let name = MacroRulesNormalizedIdent::new(ident);
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(MatchedSeq(ref ads)) => {
                     default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
@@ -479,7 +479,7 @@ fn count_repetitions<'a>(
     count(cx, 0, depth_opt, matched, sp)
 }
 
-/// Returns a `NamedMatch` item declared on the RHS given an arbitrary [Ident]
+/// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident]
 fn matched_from_ident<'ctx, 'interp, 'rslt>(
     cx: &ExtCtxt<'ctx>,
     ident: Ident,
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index fc2ac75d609..e49f40ff1a1 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -46,6 +46,8 @@ declare_features! (
     // feature-group-start: accepted features
     // -------------------------------------------------------------------------
 
+    /// Allows `#[target_feature(...)]` on aarch64 platforms
+    (accepted, aarch64_target_feature, "1.61.0", Some(44839), None),
     /// Allows the sysV64 ABI to be specified on all platforms
     /// instead of just the platforms on which it is the C ABI.
     (accepted, abi_sysv64, "1.24.0", Some(36167), None),
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index ccd296c3da1..d9748b19e13 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -243,7 +243,7 @@ declare_features! (
     // FIXME: Document these and merge with the list below.
 
     // Unstable `#[target_feature]` directives.
-    (active, aarch64_target_feature, "1.27.0", Some(44839), None),
+    (active, aarch64_ver_target_feature, "1.27.0", Some(44839), None),
     (active, adx_target_feature, "1.32.0", Some(44839), None),
     (active, arm_target_feature, "1.27.0", Some(44839), None),
     (active, avx512_target_feature, "1.27.0", Some(44839), None),
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index e6c9d0b0ab0..74fef0be9e9 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -30,10 +30,6 @@ fn emit_unfulfilled_expectation_lint(
     hir_id: HirId,
     expectation: &LintExpectation,
 ) {
-    // FIXME: The current implementation doesn't cover cases where the
-    // `unfulfilled_lint_expectations` is actually expected by another lint
-    // expectation. This can be added here by checking the lint level and
-    // retrieving the `LintExpectationId` if it was expected.
     tcx.struct_span_lint_hir(
         builtin::UNFULFILLED_LINT_EXPECTATIONS,
         hir_id,
@@ -43,6 +39,11 @@ fn emit_unfulfilled_expectation_lint(
             if let Some(rationale) = expectation.reason {
                 diag.note(&rationale.as_str());
             }
+
+            if expectation.is_unfulfilled_lint_expectations {
+                diag.note("the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message");
+            }
+
             diag.emit();
         },
     );
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 7b018e7f75f..47899f8625d 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -14,7 +14,7 @@ use rustc_middle::lint::{
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
 use rustc_session::lint::{
-    builtin::{self, FORBIDDEN_LINT_GROUPS},
+    builtin::{self, FORBIDDEN_LINT_GROUPS, UNFULFILLED_LINT_EXPECTATIONS},
     Level, Lint, LintExpectationId, LintId,
 };
 use rustc_session::parse::{add_feature_diagnostics, feature_err};
@@ -218,6 +218,14 @@ impl<'s> LintLevelsBuilder<'s> {
                 }
             }
         }
+
+        // The lint `unfulfilled_lint_expectations` can't be expected, as it would suppress itself.
+        // Handling expectations of this lint would add additional complexity with little to no
+        // benefit. The expect level for this lint will therefore be ignored.
+        if let Level::Expect(_) = level && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS) {
+            return;
+        }
+
         if let Level::ForceWarn = old_level {
             self.current_specs_mut().insert(id, (old_level, old_src));
         } else {
@@ -350,6 +358,22 @@ impl<'s> LintLevelsBuilder<'s> {
                     self.store.check_lint_name(&name, tool_name, self.registered_tools);
                 match &lint_result {
                     CheckLintNameResult::Ok(ids) => {
+                        // This checks for instances where the user writes `#[expect(unfulfilled_lint_expectations)]`
+                        // in that case we want to avoid overriding the lint level but instead add an expectation that
+                        // can't be fulfilled. The lint message will include an explanation, that the
+                        // `unfulfilled_lint_expectations` lint can't be expected.
+                        if let Level::Expect(expect_id) = level {
+                            // The `unfulfilled_lint_expectations` lint is not part of any lint groups. Therefore. we
+                            // only need to check the slice if it contains a single lint.
+                            let is_unfulfilled_lint_expectations = match ids {
+                                [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
+                                _ => false,
+                            };
+                            self.lint_expectations.push((
+                                expect_id,
+                                LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations),
+                            ));
+                        }
                         let src = LintLevelSource::Node(
                             meta_item.path.segments.last().expect("empty lint name").ident.name,
                             sp,
@@ -360,10 +384,6 @@ impl<'s> LintLevelsBuilder<'s> {
                                 self.insert_spec(id, (level, src));
                             }
                         }
-                        if let Level::Expect(expect_id) = level {
-                            self.lint_expectations
-                                .push((expect_id, LintExpectation::new(reason, sp)));
-                        }
                     }
 
                     CheckLintNameResult::Tool(result) => {
@@ -381,7 +401,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
-                                        .push((expect_id, LintExpectation::new(reason, sp)));
+                                        .push((expect_id, LintExpectation::new(reason, sp, false)));
                                 }
                             }
                             Err((Some(ids), ref new_lint_name)) => {
@@ -425,7 +445,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
-                                        .push((expect_id, LintExpectation::new(reason, sp)));
+                                        .push((expect_id, LintExpectation::new(reason, sp, false)));
                                 }
                             }
                             Err((None, _)) => {
@@ -531,7 +551,7 @@ impl<'s> LintLevelsBuilder<'s> {
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
-                                .push((expect_id, LintExpectation::new(reason, sp)));
+                                .push((expect_id, LintExpectation::new(reason, sp, false)));
                         }
                     } else {
                         panic!("renamed lint does not exist: {}", new_name);
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index cd328b08735..4842f7ef4b9 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -54,7 +54,7 @@ pub enum Applicability {
 /// Expected `Diagnostic`s get the lint level `Expect` which stores the `LintExpectationId`
 /// to match it with the actual expectation later on.
 ///
-/// The `LintExpectationId` has to be has stable between compilations, as diagnostic
+/// The `LintExpectationId` has to be stable between compilations, as diagnostic
 /// instances might be loaded from cache. Lint messages can be emitted during an
 /// `EarlyLintPass` operating on the AST and during a `LateLintPass` traversing the
 /// HIR tree. The AST doesn't have enough information to create a stable id. The
@@ -71,7 +71,7 @@ pub enum Applicability {
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, Encodable, Decodable)]
 pub enum LintExpectationId {
     /// Used for lints emitted during the `EarlyLintPass`. This id is not
-    /// has stable and should not be cached.
+    /// hash stable and should not be cached.
     Unstable { attr_id: AttrId, lint_index: Option<u16> },
     /// The [`HirId`] that the lint expectation is attached to. This id is
     /// stable and can be cached. The additional index ensures that nodes with
@@ -113,7 +113,9 @@ impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
                 lint_index.hash_stable(hcx, hasher);
             }
             _ => {
-                unreachable!("HashStable should only be called for a filled `LintExpectationId`")
+                unreachable!(
+                    "HashStable should only be called for filled and stable `LintExpectationId`"
+                )
             }
         }
     }
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 894947fa70d..1b301629b9c 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -204,11 +204,19 @@ pub struct LintExpectation {
     pub reason: Option<Symbol>,
     /// The [`Span`] of the attribute that this expectation originated from.
     pub emission_span: Span,
+    /// Lint messages for the `unfulfilled_lint_expectations` lint will be
+    /// adjusted to include an additional note. Therefore, we have to track if
+    /// the expectation is for the lint.
+    pub is_unfulfilled_lint_expectations: bool,
 }
 
 impl LintExpectation {
-    pub fn new(reason: Option<Symbol>, attr_span: Span) -> Self {
-        Self { reason, emission_span: attr_span }
+    pub fn new(
+        reason: Option<Symbol>,
+        emission_span: Span,
+        is_unfulfilled_lint_expectations: bool,
+    ) -> Self {
+        Self { reason, emission_span, is_unfulfilled_lint_expectations }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a49189ae92a..e89f68fd0ea 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2252,12 +2252,13 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
-    /// Returns the type of metadata for (potentially fat) pointers to this type.
+    /// Returns the type of metadata for (potentially fat) pointers to this type,
+    /// and a boolean signifying if this is conditional on this type being `Sized`.
     pub fn ptr_metadata_ty(
         self,
         tcx: TyCtxt<'tcx>,
         normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
-    ) -> Ty<'tcx> {
+    ) -> (Ty<'tcx>, bool) {
         let tail = tcx.struct_tail_with_normalize(self, normalize);
         match tail.kind() {
             // Sized types
@@ -2277,28 +2278,30 @@ impl<'tcx> Ty<'tcx> {
             | ty::Closure(..)
             | ty::Never
             | ty::Error(_)
+            // Extern types have metadata = ().
             | ty::Foreign(..)
             // If returned by `struct_tail_without_normalization` this is a unit struct
             // without any fields, or not a struct, and therefore is Sized.
             | ty::Adt(..)
             // If returned by `struct_tail_without_normalization` this is the empty tuple,
             // a.k.a. unit type, which is Sized
-            | ty::Tuple(..) => tcx.types.unit,
+            | ty::Tuple(..) => (tcx.types.unit, false),
 
-            ty::Str | ty::Slice(_) => tcx.types.usize,
+            ty::Str | ty::Slice(_) => (tcx.types.usize, false),
             ty::Dynamic(..) => {
                 let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
-                tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
+                (tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]), false)
             },
 
-            ty::Projection(_)
-            | ty::Param(_)
-            | ty::Opaque(..)
-            | ty::Infer(ty::TyVar(_))
+            // type parameters only have unit metadata if they're sized, so return true
+            // to make sure we double check this during confirmation
+            ty::Param(_) |  ty::Projection(_) | ty::Opaque(..) => (tcx.types.unit, true),
+
+            ty::Infer(ty::TyVar(_))
             | ty::Bound(..)
             | ty::Placeholder(..)
             | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
-                bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
+                bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail)
             }
         }
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 967eb3cc22a..4dd1c3fed6b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -278,6 +278,7 @@ symbols! {
         _task_context,
         a32,
         aarch64_target_feature,
+        aarch64_ver_target_feature,
         abi,
         abi_amdgpu_kernel,
         abi_avr_interrupt,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index ca5f2b4af8a..4f0c3bec1ee 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -975,6 +975,7 @@ supported_targets! {
     ("x86_64-unknown-none-hermitkernel", x86_64_unknown_none_hermitkernel),
 
     ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
+    ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf),
     ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
     ("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
     ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
diff --git a/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
new file mode 100644
index 00000000000..0357a94914f
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv32im_unknown_none_elf.rs
@@ -0,0 +1,26 @@
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+        llvm_target: "riscv32".to_string(),
+        pointer_width: 32,
+        arch: "riscv32".to_string(),
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+            linker: Some("rust-lld".to_string()),
+            cpu: "generic-rv32".to_string(),
+            max_atomic_width: Some(0),
+            atomic_cas: false,
+            features: "+m".to_string(),
+            executables: true,
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index ea48fab1ceb..11f0507d6fd 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1469,6 +1469,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
 
                 let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
+                    // We throw away any obligations we get from this, since we normalize
+                    // and confirm these obligations once again during confirmation
                     normalize_with_depth(
                         selcx,
                         obligation.param_env,
@@ -1485,7 +1487,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     | ty::Int(_)
                     | ty::Uint(_)
                     | ty::Float(_)
-                    | ty::Foreign(_)
                     | ty::Str
                     | ty::Array(..)
                     | ty::Slice(_)
@@ -1498,6 +1499,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     | ty::Generator(..)
                     | ty::GeneratorWitness(..)
                     | ty::Never
+                    // Extern types have unit metadata, according to RFC 2850
+                    | ty::Foreign(_)
                     // If returned by `struct_tail_without_normalization` this is a unit struct
                     // without any fields, or not a struct, and therefore is Sized.
                     | ty::Adt(..)
@@ -1506,9 +1509,18 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     // Integers and floats are always Sized, and so have unit type metadata.
                     | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
 
-                    ty::Projection(..)
+                    // type parameters, opaques, and unnormalized projections have pointer
+                    // metadata if they're known (e.g. by the param_env) to be sized
+                    ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
+                        if tail.is_sized(selcx.tcx().at(obligation.cause.span), obligation.param_env) =>
+                    {
+                        true
+                    }
+
+                    // FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
+                    ty::Param(_)
+                    | ty::Projection(..)
                     | ty::Opaque(..)
-                    | ty::Param(..)
                     | ty::Bound(..)
                     | ty::Placeholder(..)
                     | ty::Infer(..)
@@ -1517,7 +1529,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                             candidate_set.mark_ambiguous();
                         }
                         false
-                    },
+                    }
                 }
             }
             super::ImplSource::Param(..) => {
@@ -1727,7 +1739,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
     let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
 
     let mut obligations = vec![];
-    let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
+    let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
         normalize_with_depth_to(
             selcx,
             obligation.param_env,
@@ -1737,6 +1749,19 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
             &mut obligations,
         )
     });
+    if check_is_sized {
+        let sized_predicate = ty::Binder::dummy(ty::TraitRef::new(
+            tcx.require_lang_item(LangItem::Sized, None),
+            tcx.mk_substs_trait(self_ty, &[]),
+        ))
+        .without_const()
+        .to_predicate(tcx);
+        obligations.push(Obligation::new(
+            obligation.cause.clone(),
+            obligation.param_env,
+            sized_predicate,
+        ));
+    }
 
     let substs = tcx.mk_substs([self_ty.into()].iter());
     let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index cabdcdc214b..16e72d0c2c5 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2680,7 +2680,6 @@ fn from_target_feature(
             // Only allow features whose feature gates have been enabled.
             let allowed = match feature_gate.as_ref().copied() {
                 Some(sym::arm_target_feature) => rust_features.arm_target_feature,
-                Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature,
                 Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
                 Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
                 Some(sym::mips_target_feature) => rust_features.mips_target_feature,
@@ -2696,6 +2695,7 @@ fn from_target_feature(
                 Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
                 Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
                 Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
+                Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
                 Some(name) => bug!("unknown target feature gate {}", name),
                 None => true,
             };