about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-02-11 10:17:02 +0000
committerbors <bors@rust-lang.org>2025-02-11 10:17:02 +0000
commit69482e8e5a5fa1441615b015ac2f59178d944696 (patch)
tree5e5c68d395b54b36c7ffbe01aaf5ad71dafdc5d1 /compiler
parentc182ce9cbc8c29ebc1b4559d027df545e6cdd287 (diff)
parent21303103c3eef60e027630cd2aea5f54f868c734 (diff)
Auto merge of #136851 - jhpratt:rollup-ftijn95, r=jhpratt
Rollup of 11 pull requests

Successful merges:

 - #136606 (Fix long lines which rustfmt fails to format)
 - #136663 (Stabilize `NonZero::count_ones`)
 - #136672 (library: doc: core::alloc::Allocator: trivial typo fix)
 - #136704 (Improve examples for file locking)
 - #136721 (cg_llvm: Reduce visibility of some items outside the `llvm` module)
 - #136813 (rustc_target: Add the fp16 target feature for AArch32)
 - #136830 (fix i686-unknown-hurd-gnu x87 footnote)
 - #136832 (Fix platform support table for i686-unknown-uefi)
 - #136835 (Stop using span hack for contracts feature gating)
 - #136837 (Overhaul how contracts are lowered on fn-like bodies)
 - #136839 (fix ensure_monomorphic_enough)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs21
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs166
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/contracts.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs44
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs14
-rw-r--r--compiler/rustc_session/src/parse.rs5
-rw-r--r--compiler/rustc_target/src/target_features.rs1
14 files changed, 119 insertions, 193 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 923fd65dcca..af53c7ec215 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -379,16 +379,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         })
     }
 
-    /// Create an `ExprKind::Ret` that is preceded by a call to check contract ensures clause.
+    /// Create an `ExprKind::Ret` that is optionally wrapped by a call to check
+    /// a contract ensures clause, if it exists.
     fn checked_return(&mut self, opt_expr: Option<&'hir hir::Expr<'hir>>) -> hir::ExprKind<'hir> {
-        let checked_ret = if let Some(Some((span, fresh_ident))) =
-            self.contract.as_ref().map(|c| c.ensures.as_ref().map(|e| (e.expr.span, e.fresh_ident)))
-        {
-            let expr = opt_expr.unwrap_or_else(|| self.expr_unit(span));
-            Some(self.inject_ensures_check(expr, span, fresh_ident.0, fresh_ident.2))
-        } else {
-            opt_expr
-        };
+        let checked_ret =
+            if let Some((check_span, check_ident, check_hir_id)) = self.contract_ensures {
+                let expr = opt_expr.unwrap_or_else(|| self.expr_unit(check_span));
+                Some(self.inject_ensures_check(expr, check_span, check_ident, check_hir_id))
+            } else {
+                opt_expr
+            };
         hir::ExprKind::Ret(checked_ret)
     }
 
@@ -1090,7 +1090,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             } else {
                 None
             };
-            let body_id = this.lower_fn_body(decl, |this| {
+            // FIXME(contracts): Support contracts on closures?
+            let body_id = this.lower_fn_body(decl, None, |this| {
                 this.coroutine_kind = coroutine_kind;
                 let e = this.lower_expr_mut(body);
                 coroutine_kind = this.coroutine_kind;
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 75b08e16cdb..85642c8ccb5 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -211,36 +211,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ..
             }) => {
                 self.with_new_scopes(*fn_sig_span, |this| {
-                    assert!(this.contract.is_none());
-                    if let Some(contract) = contract {
-                        let requires = contract.requires.clone();
-                        let ensures = contract.ensures.clone();
-                        let ensures = ensures.map(|ens| {
-                            // FIXME: this needs to be a fresh (or illegal) identifier to prevent
-                            // accidental capture of a parameter or global variable.
-                            let checker_ident: Ident =
-                                Ident::from_str_and_span("__ensures_checker", ens.span);
-                            let (checker_pat, checker_hir_id) = this.pat_ident_binding_mode_mut(
-                                ens.span,
-                                checker_ident,
-                                hir::BindingMode::NONE,
-                            );
-
-                            crate::FnContractLoweringEnsures {
-                                expr: ens,
-                                fresh_ident: (checker_ident, checker_pat, checker_hir_id),
-                            }
-                        });
-
-                        // Note: `with_new_scopes` will reinstall the outer
-                        // item's contract (if any) after its callback finishes.
-                        this.contract.replace(crate::FnContractLoweringInfo {
-                            span,
-                            requires,
-                            ensures,
-                        });
-                    }
-
                     // Note: we don't need to change the return type from `T` to
                     // `impl Future<Output = T>` here because lower_body
                     // only cares about the input argument patterns in the function
@@ -254,6 +224,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         coroutine_kind,
                         body.as_deref(),
                         attrs,
+                        contract.as_deref(),
                     );
 
                     let itctx = ImplTraitContext::Universal;
@@ -803,6 +774,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 (generics, kind, expr.is_some())
             }
             AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
+                // FIXME(contracts): Deny contract here since it won't apply to
+                // any impl method or callees.
                 let names = self.lower_fn_params_to_names(&sig.decl);
                 let (generics, sig) = self.lower_method_sig(
                     generics,
@@ -814,7 +787,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
-            AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => {
+            AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), contract, .. }) => {
                 let body_id = self.lower_maybe_coroutine_body(
                     sig.span,
                     i.span,
@@ -823,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     sig.header.coroutine_kind,
                     Some(body),
                     attrs,
+                    contract.as_deref(),
                 );
                 let (generics, sig) = self.lower_method_sig(
                     generics,
@@ -931,7 +905,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ImplItemKind::Const(ty, body)
                 },
             ),
-            AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
+            AssocItemKind::Fn(box Fn { sig, generics, body, contract, .. }) => {
                 let body_id = self.lower_maybe_coroutine_body(
                     sig.span,
                     i.span,
@@ -940,6 +914,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     sig.header.coroutine_kind,
                     body.as_deref(),
                     attrs,
+                    contract.as_deref(),
                 );
                 let (generics, sig) = self.lower_method_sig(
                     generics,
@@ -1088,72 +1063,89 @@ impl<'hir> LoweringContext<'_, 'hir> {
     pub(super) fn lower_fn_body(
         &mut self,
         decl: &FnDecl,
+        contract: Option<&FnContract>,
         body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
     ) -> hir::BodyId {
         self.lower_body(|this| {
             let params =
                 this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
-            let result = body(this);
-
-            let opt_contract = this.contract.take();
 
+            // Optionally lower the fn contract, which turns:
+            //
             // { body }
-            // ==>
-            // { contract_requires(PRECOND); { body } }
-            let Some(contract) = opt_contract else { return (params, result) };
-            let result_ref = this.arena.alloc(result);
-            let lit_unit = |this: &mut LoweringContext<'_, 'hir>| {
-                this.expr(contract.span, hir::ExprKind::Tup(&[]))
-            };
-
-            let precond: hir::Stmt<'hir> = if let Some(req) = contract.requires {
-                let lowered_req = this.lower_expr_mut(&req);
-                let precond = this.expr_call_lang_item_fn_mut(
-                    req.span,
-                    hir::LangItem::ContractCheckRequires,
-                    &*arena_vec![this; lowered_req],
-                );
-                this.stmt_expr(req.span, precond)
-            } else {
-                let u = lit_unit(this);
-                this.stmt_expr(contract.span, u)
-            };
-
-            let (postcond_checker, result) = if let Some(ens) = contract.ensures {
-                let crate::FnContractLoweringEnsures { expr: ens, fresh_ident } = ens;
-                let lowered_ens: hir::Expr<'hir> = this.lower_expr_mut(&ens);
-                let postcond_checker = this.expr_call_lang_item_fn(
-                    ens.span,
-                    hir::LangItem::ContractBuildCheckEnsures,
-                    &*arena_vec![this; lowered_ens],
-                );
-                let checker_binding_pat = fresh_ident.1;
-                (
-                    this.stmt_let_pat(
+            //
+            // into:
+            //
+            // { contract_requires(PRECOND); let __postcond = |ret_val| POSTCOND; postcond({ body }) }
+            if let Some(contract) = contract {
+                let precond = if let Some(req) = &contract.requires {
+                    // Lower the precondition check intrinsic.
+                    let lowered_req = this.lower_expr_mut(&req);
+                    let precond = this.expr_call_lang_item_fn_mut(
+                        req.span,
+                        hir::LangItem::ContractCheckRequires,
+                        &*arena_vec![this; lowered_req],
+                    );
+                    Some(this.stmt_expr(req.span, precond))
+                } else {
+                    None
+                };
+                let (postcond, body) = if let Some(ens) = &contract.ensures {
+                    let ens_span = this.lower_span(ens.span);
+                    // Set up the postcondition `let` statement.
+                    let check_ident: Ident =
+                        Ident::from_str_and_span("__ensures_checker", ens_span);
+                    let (checker_pat, check_hir_id) = this.pat_ident_binding_mode_mut(
+                        ens_span,
+                        check_ident,
+                        hir::BindingMode::NONE,
+                    );
+                    let lowered_ens = this.lower_expr_mut(&ens);
+                    let postcond_checker = this.expr_call_lang_item_fn(
+                        ens_span,
+                        hir::LangItem::ContractBuildCheckEnsures,
+                        &*arena_vec![this; lowered_ens],
+                    );
+                    let postcond = this.stmt_let_pat(
                         None,
-                        ens.span,
+                        ens_span,
                         Some(postcond_checker),
-                        this.arena.alloc(checker_binding_pat),
+                        this.arena.alloc(checker_pat),
                         hir::LocalSource::Contract,
-                    ),
-                    this.inject_ensures_check(result_ref, ens.span, fresh_ident.0, fresh_ident.2),
-                )
-            } else {
-                let u = lit_unit(this);
-                (this.stmt_expr(contract.span, u), &*result_ref)
-            };
+                    );
 
-            let block = this.block_all(
-                contract.span,
-                arena_vec![this; precond, postcond_checker],
-                Some(result),
-            );
-            (params, this.expr_block(block))
+                    // Install contract_ensures so we will intercept `return` statements,
+                    // then lower the body.
+                    this.contract_ensures = Some((ens_span, check_ident, check_hir_id));
+                    let body = this.arena.alloc(body(this));
+
+                    // Finally, inject an ensures check on the implicit return of the body.
+                    let body = this.inject_ensures_check(body, ens_span, check_ident, check_hir_id);
+                    (Some(postcond), body)
+                } else {
+                    let body = &*this.arena.alloc(body(this));
+                    (None, body)
+                };
+                // Flatten the body into precond, then postcond, then wrapped body.
+                let wrapped_body = this.block_all(
+                    body.span,
+                    this.arena.alloc_from_iter([precond, postcond].into_iter().flatten()),
+                    Some(body),
+                );
+                (params, this.expr_block(wrapped_body))
+            } else {
+                (params, body(this))
+            }
         })
     }
 
-    fn lower_fn_body_block(&mut self, decl: &FnDecl, body: &Block) -> hir::BodyId {
-        self.lower_fn_body(decl, |this| this.lower_block_expr(body))
+    fn lower_fn_body_block(
+        &mut self,
+        decl: &FnDecl,
+        body: &Block,
+        contract: Option<&FnContract>,
+    ) -> hir::BodyId {
+        self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body))
     }
 
     pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
@@ -1179,12 +1171,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         coroutine_kind: Option<CoroutineKind>,
         body: Option<&Block>,
         attrs: &'hir [hir::Attribute],
+        contract: Option<&FnContract>,
     ) -> hir::BodyId {
         let Some(body) = body else {
             // Functions without a body are an error, except if this is an intrinsic. For those we
             // create a fake body so that the entire rest of the compiler doesn't have to deal with
             // this as a special case.
-            return self.lower_fn_body(decl, |this| {
+            return self.lower_fn_body(decl, contract, |this| {
                 if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) {
                     let span = this.lower_span(span);
                     let empty_block = hir::Block {
@@ -1209,8 +1202,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
         };
         let Some(coroutine_kind) = coroutine_kind else {
             // Typical case: not a coroutine.
-            return self.lower_fn_body_block(decl, body);
+            return self.lower_fn_body_block(decl, body, contract);
         };
+        // FIXME(contracts): Support contracts on async fn.
         self.lower_body(|this| {
             let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
                 decl,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 3fecb9e9c7e..facc9414b20 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -88,19 +88,6 @@ pub mod stability;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
-#[derive(Debug, Clone)]
-struct FnContractLoweringInfo<'hir> {
-    pub span: Span,
-    pub requires: Option<ast::ptr::P<ast::Expr>>,
-    pub ensures: Option<FnContractLoweringEnsures<'hir>>,
-}
-
-#[derive(Debug, Clone)]
-struct FnContractLoweringEnsures<'hir> {
-    expr: ast::ptr::P<ast::Expr>,
-    fresh_ident: (Ident, hir::Pat<'hir>, HirId),
-}
-
 struct LoweringContext<'a, 'hir> {
     tcx: TyCtxt<'hir>,
     resolver: &'a mut ResolverAstLowering,
@@ -115,7 +102,7 @@ struct LoweringContext<'a, 'hir> {
     /// Collect items that were created by lowering the current owner.
     children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>,
 
-    contract: Option<FnContractLoweringInfo<'hir>>,
+    contract_ensures: Option<(Span, Ident, HirId)>,
 
     coroutine_kind: Option<hir::CoroutineKind>,
 
@@ -165,7 +152,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             bodies: Vec::new(),
             attrs: SortedMap::default(),
             children: Vec::default(),
-            contract: None,
+            contract_ensures: None,
             current_hir_id_owner: hir::CRATE_OWNER_ID,
             item_local_id_counter: hir::ItemLocalId::ZERO,
             ident_and_label_to_local_id: Default::default(),
@@ -852,7 +839,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let was_in_loop_condition = self.is_in_loop_condition;
         self.is_in_loop_condition = false;
 
-        let old_contract = self.contract.take();
+        let old_contract = self.contract_ensures.take();
 
         let catch_scope = self.catch_scope.take();
         let loop_scope = self.loop_scope.take();
@@ -860,7 +847,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.catch_scope = catch_scope;
         self.loop_scope = loop_scope;
 
-        self.contract = old_contract;
+        self.contract_ensures = old_contract;
 
         self.is_in_loop_condition = was_in_loop_condition;
 
diff --git a/compiler/rustc_builtin_macros/src/contracts.rs b/compiler/rustc_builtin_macros/src/contracts.rs
index 85a30f7bdc9..6a24af361fe 100644
--- a/compiler/rustc_builtin_macros/src/contracts.rs
+++ b/compiler/rustc_builtin_macros/src/contracts.rs
@@ -1,11 +1,9 @@
-#![allow(unused_imports, unused_variables)]
-
 use rustc_ast::token;
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_errors::ErrorGuaranteed;
 use rustc_expand::base::{AttrProcMacro, ExtCtxt};
 use rustc_span::Span;
-use rustc_span::symbol::{Ident, Symbol, kw, sym};
+use rustc_span::symbol::{Ident, Symbol, kw};
 
 pub(crate) struct ExpandRequires;
 
@@ -121,23 +119,19 @@ fn expand_contract_clause(
         }
     }
 
-    // Record the span as a contract attribute expansion.
-    // This is used later to stop users from using the extended syntax directly
-    // which is gated via `contracts_internals`.
-    ecx.psess().contract_attribute_spans.push(attr_span);
-
     Ok(new_tts)
 }
 
 fn expand_requires_tts(
-    _ecx: &mut ExtCtxt<'_>,
+    ecx: &mut ExtCtxt<'_>,
     attr_span: Span,
     annotation: TokenStream,
     annotated: TokenStream,
 ) -> Result<TokenStream, ErrorGuaranteed> {
-    expand_contract_clause(_ecx, attr_span, annotated, |new_tts| {
+    let feature_span = ecx.with_def_site_ctxt(attr_span);
+    expand_contract_clause(ecx, attr_span, annotated, |new_tts| {
         new_tts.push_tree(TokenTree::Token(
-            token::Token::from_ast_ident(Ident::new(kw::ContractRequires, attr_span)),
+            token::Token::from_ast_ident(Ident::new(kw::ContractRequires, feature_span)),
             Spacing::Joint,
         ));
         new_tts.push_tree(TokenTree::Token(
@@ -155,14 +149,15 @@ fn expand_requires_tts(
 }
 
 fn expand_ensures_tts(
-    _ecx: &mut ExtCtxt<'_>,
+    ecx: &mut ExtCtxt<'_>,
     attr_span: Span,
     annotation: TokenStream,
     annotated: TokenStream,
 ) -> Result<TokenStream, ErrorGuaranteed> {
-    expand_contract_clause(_ecx, attr_span, annotated, |new_tts| {
+    let feature_span = ecx.with_def_site_ctxt(attr_span);
+    expand_contract_clause(ecx, attr_span, annotated, |new_tts| {
         new_tts.push_tree(TokenTree::Token(
-            token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, attr_span)),
+            token::Token::from_ast_ident(Ident::new(kw::ContractEnsures, feature_span)),
             Spacing::Joint,
         ));
         new_tts.push_tree(TokenTree::Delimited(
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 685b2f37c9c..13846c8ab4b 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -664,7 +664,7 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
 }
 
 impl llvm::CallConv {
-    pub fn from_conv(conv: Conv, arch: &str) -> Self {
+    pub(crate) fn from_conv(conv: Conv, arch: &str) -> Self {
         match conv {
             Conv::C
             | Conv::Rust
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 8bad437eeb7..7262fce4911 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -642,7 +642,7 @@ unsafe impl Send for ModuleBuffer {}
 unsafe impl Sync for ModuleBuffer {}
 
 impl ModuleBuffer {
-    pub fn new(m: &llvm::Module) -> ModuleBuffer {
+    pub(crate) fn new(m: &llvm::Module) -> ModuleBuffer {
         ModuleBuffer(unsafe { llvm::LLVMRustModuleBufferCreate(m) })
     }
 }
@@ -684,7 +684,7 @@ unsafe impl Send for ThinBuffer {}
 unsafe impl Sync for ThinBuffer {}
 
 impl ThinBuffer {
-    pub fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer {
+    pub(crate) fn new(m: &llvm::Module, is_thin: bool, emit_summary: bool) -> ThinBuffer {
         unsafe {
             let buffer = llvm::LLVMRustThinLTOBufferCreate(m, is_thin, emit_summary);
             ThinBuffer(buffer)
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
index 4cbd49aa44d..f075f332462 100644
--- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -17,7 +17,7 @@ pub struct OwnedTargetMachine {
 }
 
 impl OwnedTargetMachine {
-    pub fn new(
+    pub(crate) fn new(
         triple: &CStr,
         cpu: &CStr,
         features: &CStr,
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index f0d04b2b644..bcb1cc72b56 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -30,7 +30,7 @@ use std::mem::ManuallyDrop;
 use back::owned_target_machine::OwnedTargetMachine;
 use back::write::{create_informational_target_machine, create_target_machine};
 use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig};
-pub use llvm_util::target_features_cfg;
+pub(crate) use llvm_util::target_features_cfg;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 53611c746a7..b4b5d6a5b19 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -271,6 +271,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         ("aarch64", "fp16") => Some(LLVMFeature::new("fullfp16")),
         // Filter out features that are not supported by the current LLVM version
         ("aarch64", "fpmr") if get_version().0 != 18 => None,
+        ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")),
         // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single
         // feature called `fast-unaligned-access`. In LLVM 19, it was split back out.
         ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
@@ -303,7 +304,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
 /// Must express features in the way Rust understands them.
 ///
 /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
-pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
+pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
     let mut features: FxHashSet<Symbol> = Default::default();
 
     // Add base features for the target.
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 34cede54aaf..d61ce417562 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -237,11 +237,11 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
 impl Type {
     /// Creates an integer type with the given number of bits, e.g., i24
-    pub fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type {
+    pub(crate) fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type {
         unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) }
     }
 
-    pub fn ptr_llcx(llcx: &llvm::Context) -> &Type {
+    pub(crate) fn ptr_llcx(llcx: &llvm::Context) -> &Type {
         unsafe { llvm::LLVMPointerTypeInContext(llcx, AddressSpace::DATA.0) }
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index eb98e3b5380..ba579e25f03 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,12 +1,8 @@
-use std::ops::ControlFlow;
-
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer};
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
-};
+use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt};
 use tracing::debug;
 
 use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval};
@@ -20,44 +16,10 @@ where
     T: TypeVisitable<TyCtxt<'tcx>>,
 {
     debug!("ensure_monomorphic_enough: ty={:?}", ty);
-    if !ty.has_param() {
-        return interp_ok(());
-    }
-
-    struct FoundParam;
-    struct UsedParamsNeedInstantiationVisitor {}
-
-    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor {
-        type Result = ControlFlow<FoundParam>;
-
-        fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-            if !ty.has_param() {
-                return ControlFlow::Continue(());
-            }
-
-            match *ty.kind() {
-                ty::Param(_) => ControlFlow::Break(FoundParam),
-                ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::FnDef(..) => {
-                    ControlFlow::Continue(())
-                }
-                _ => ty.super_visit_with(self),
-            }
-        }
-
-        fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
-            match c.kind() {
-                ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
-                _ => c.super_visit_with(self),
-            }
-        }
-    }
-
-    let mut vis = UsedParamsNeedInstantiationVisitor {};
-    if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
+    if ty.has_param() {
         throw_inval!(TooGeneric);
-    } else {
-        interp_ok(())
     }
+    interp_ok(())
 }
 
 impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> {
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 86816819be2..11f0e579de5 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -302,26 +302,16 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_contract(
         &mut self,
     ) -> PResult<'a, Option<rustc_ast::ptr::P<ast::FnContract>>> {
-        let gate = |span| {
-            if self.psess.contract_attribute_spans.contains(span) {
-                // span was generated via a builtin contracts attribute, so gate as end-user visible
-                self.psess.gated_spans.gate(sym::contracts, span);
-            } else {
-                // span was not generated via a builtin contracts attribute, so gate as internal machinery
-                self.psess.gated_spans.gate(sym::contracts_internals, span);
-            }
-        };
-
         let requires = if self.eat_keyword_noexpect(exp!(ContractRequires).kw) {
+            self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
             let precond = self.parse_expr()?;
-            gate(precond.span);
             Some(precond)
         } else {
             None
         };
         let ensures = if self.eat_keyword_noexpect(exp!(ContractEnsures).kw) {
+            self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
             let postcond = self.parse_expr()?;
-            gate(postcond.span);
             Some(postcond)
         } else {
             None
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index d4db05ce139..e0405a71f65 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -208,10 +208,6 @@ pub struct ParseSess {
     pub config: Cfg,
     pub check_config: CheckCfg,
     pub edition: Edition,
-    /// Places where contract attributes were expanded into unstable AST forms.
-    /// This is used to allowlist those spans (so that we only check them against the feature
-    /// gate for the externally visible interface, and not internal implmentation machinery).
-    pub contract_attribute_spans: AppendOnlyVec<Span>,
     /// Places where raw identifiers were used. This is used to avoid complaining about idents
     /// clashing with keywords in new editions.
     pub raw_identifier_spans: AppendOnlyVec<Span>,
@@ -260,7 +256,6 @@ impl ParseSess {
             config: Cfg::default(),
             check_config: CheckCfg::default(),
             edition: ExpnId::root().expn_data().edition,
-            contract_attribute_spans: Default::default(),
             raw_identifier_spans: Default::default(),
             bad_unicode_identifiers: Lock::new(Default::default()),
             source_map,
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index ea7c15a3595..1ba8defedae 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -145,6 +145,7 @@ static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
     ("dsp", Unstable(sym::arm_target_feature), &[]),
     ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]),
+    ("fp16", Unstable(sym::arm_target_feature), &["neon"]),
     ("fpregs", Unstable(sym::arm_target_feature), &[]),
     ("i8mm", Unstable(sym::arm_target_feature), &["neon"]),
     ("mclass", Unstable(sym::arm_target_feature), &[]),