about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/autodiff.rs194
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/define_opaque.rs54
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs19
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs1
14 files changed, 235 insertions, 104 deletions
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 78bf2195975..1c1b2c88f76 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -88,6 +88,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
         generics: Generics::default(),
         contract: None,
         body,
+        define_opaque: None,
     }));
 
     let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)];
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index bb9dc651cec..a949ab94f3a 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::AssignOp(_, _, _)
             | ExprKind::Gen(_, _, _, _)
             | ExprKind::Await(_, _)
+            | ExprKind::Use(_, _)
             | ExprKind::Block(_, _)
             | ExprKind::Break(_, _)
             | ExprKind::Closure(_)
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 6d9c3575657..6591ed151cf 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -8,7 +8,8 @@ mod llvm_enzyme {
     use std::string::String;
 
     use rustc_ast::expand::autodiff_attrs::{
-        AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ty_for_activity,
+        AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
+        valid_ty_for_activity,
     };
     use rustc_ast::ptr::P;
     use rustc_ast::token::{Token, TokenKind};
@@ -25,6 +26,16 @@ mod llvm_enzyme {
 
     use crate::errors;
 
+    pub(crate) fn outer_normal_attr(
+        kind: &P<rustc_ast::NormalAttr>,
+        id: rustc_ast::AttrId,
+        span: Span,
+    ) -> rustc_ast::Attribute {
+        let style = rustc_ast::AttrStyle::Outer;
+        let kind = rustc_ast::AttrKind::Normal(kind.clone());
+        rustc_ast::Attribute { kind, id, style, span }
+    }
+
     // If we have a default `()` return type or explicitley `()` return type,
     // then we often can skip doing some work.
     fn has_ret(ty: &FnRetTy) -> bool {
@@ -223,20 +234,8 @@ mod llvm_enzyme {
             .filter(|a| **a == DiffActivity::Active || **a == DiffActivity::ActiveOnly)
             .count() as u32;
         let (d_sig, new_args, idents, errored) = gen_enzyme_decl(ecx, &sig, &x, span);
-        let new_decl_span = d_sig.span;
         let d_body = gen_enzyme_body(
-            ecx,
-            &x,
-            n_active,
-            &sig,
-            &d_sig,
-            primal,
-            &new_args,
-            span,
-            sig_span,
-            new_decl_span,
-            idents,
-            errored,
+            ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored,
         );
         let d_ident = first_ident(&meta_item_vec[0]);
 
@@ -247,6 +246,7 @@ mod llvm_enzyme {
             generics: Generics::default(),
             contract: None,
             body: Some(d_body),
+            define_opaque: None,
         });
         let mut rustc_ad_attr =
             P(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff)));
@@ -268,36 +268,39 @@ mod llvm_enzyme {
         };
         let inline_never_attr = P(ast::NormalAttr { item: inline_item, tokens: None });
         let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
-        let attr: ast::Attribute = ast::Attribute {
-            kind: ast::AttrKind::Normal(rustc_ad_attr.clone()),
-            id: new_id,
-            style: ast::AttrStyle::Outer,
-            span,
-        };
+        let attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
         let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
-        let inline_never: ast::Attribute = ast::Attribute {
-            kind: ast::AttrKind::Normal(inline_never_attr),
-            id: new_id,
-            style: ast::AttrStyle::Outer,
-            span,
-        };
+        let inline_never = outer_normal_attr(&inline_never_attr, new_id, span);
+
+        // We're avoid duplicating the attributes `#[rustc_autodiff]` and `#[inline(never)]`.
+        fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool {
+            match (attr, item) {
+                (ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => {
+                    let a = &a.item.path;
+                    let b = &b.item.path;
+                    a.segments.len() == b.segments.len()
+                        && a.segments.iter().zip(b.segments.iter()).all(|(a, b)| a.ident == b.ident)
+                }
+                _ => false,
+            }
+        }
 
         // Don't add it multiple times:
         let orig_annotatable: Annotatable = match item {
             Annotatable::Item(ref mut iitem) => {
-                if !iitem.attrs.iter().any(|a| a.id == attr.id) {
-                    iitem.attrs.push(attr.clone());
+                if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
+                    iitem.attrs.push(attr);
                 }
-                if !iitem.attrs.iter().any(|a| a.id == inline_never.id) {
+                if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) {
                     iitem.attrs.push(inline_never.clone());
                 }
                 Annotatable::Item(iitem.clone())
             }
             Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => {
-                if !assoc_item.attrs.iter().any(|a| a.id == attr.id) {
-                    assoc_item.attrs.push(attr.clone());
+                if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
+                    assoc_item.attrs.push(attr);
                 }
-                if !assoc_item.attrs.iter().any(|a| a.id == inline_never.id) {
+                if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) {
                     assoc_item.attrs.push(inline_never.clone());
                 }
                 Annotatable::AssocItem(assoc_item.clone(), i)
@@ -312,17 +315,11 @@ mod llvm_enzyme {
             delim: rustc_ast::token::Delimiter::Parenthesis,
             tokens: ts,
         });
-        let d_attr: ast::Attribute = ast::Attribute {
-            kind: ast::AttrKind::Normal(rustc_ad_attr.clone()),
-            id: new_id,
-            style: ast::AttrStyle::Outer,
-            span,
-        };
-
+        let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
         let d_annotatable = if is_impl {
             let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf);
             let d_fn = P(ast::AssocItem {
-                attrs: thin_vec![d_attr.clone(), inline_never],
+                attrs: thin_vec![d_attr, inline_never],
                 id: ast::DUMMY_NODE_ID,
                 span,
                 vis,
@@ -332,12 +329,8 @@ mod llvm_enzyme {
             });
             Annotatable::AssocItem(d_fn, Impl)
         } else {
-            let mut d_fn = ecx.item(
-                span,
-                d_ident,
-                thin_vec![d_attr.clone(), inline_never],
-                ItemKind::Fn(asdf),
-            );
+            let mut d_fn =
+                ecx.item(span, d_ident, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
             d_fn.vis = vis;
             Annotatable::Item(d_fn)
         };
@@ -363,30 +356,27 @@ mod llvm_enzyme {
         ty
     }
 
-    /// We only want this function to type-check, since we will replace the body
-    /// later on llvm level. Using `loop {}` does not cover all return types anymore,
-    /// so instead we build something that should pass. We also add a inline_asm
-    /// line, as one more barrier for rustc to prevent inlining of this function.
-    /// FIXME(ZuseZ4): We still have cases of incorrect inlining across modules, see
-    /// <https://github.com/EnzymeAD/rust/issues/173>, so this isn't sufficient.
-    /// It also triggers an Enzyme crash if we due to a bug ever try to differentiate
-    /// this function (which should never happen, since it is only a placeholder).
-    /// Finally, we also add back_box usages of all input arguments, to prevent rustc
-    /// from optimizing any arguments away.
-    fn gen_enzyme_body(
+    // Will generate a body of the type:
+    // ```
+    // {
+    //   unsafe {
+    //   asm!("NOP");
+    //   }
+    //   ::core::hint::black_box(primal(args));
+    //   ::core::hint::black_box((args, ret));
+    //   <This part remains to be done by following function>
+    // }
+    // ```
+    fn init_body_helper(
         ecx: &ExtCtxt<'_>,
-        x: &AutoDiffAttrs,
-        n_active: u32,
-        sig: &ast::FnSig,
-        d_sig: &ast::FnSig,
+        span: Span,
         primal: Ident,
         new_names: &[String],
-        span: Span,
         sig_span: Span,
         new_decl_span: Span,
-        idents: Vec<Ident>,
+        idents: &[Ident],
         errored: bool,
-    ) -> P<ast::Block> {
+    ) -> (P<ast::Block>, P<ast::Expr>, P<ast::Expr>, P<ast::Expr>) {
         let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]);
         let noop = ast::InlineAsm {
             asm_macro: ast::AsmMacro::Asm,
@@ -435,6 +425,51 @@ mod llvm_enzyme {
         }
         body.stmts.push(ecx.stmt_semi(black_box_remaining_args));
 
+        (body, primal_call, black_box_primal_call, blackbox_call_expr)
+    }
+
+    /// We only want this function to type-check, since we will replace the body
+    /// later on llvm level. Using `loop {}` does not cover all return types anymore,
+    /// so instead we manually build something that should pass the type checker.
+    /// We also add a inline_asm line, as one more barrier for rustc to prevent inlining
+    /// or const propagation. inline_asm will also triggers an Enzyme crash if due to another
+    /// bug would ever try to accidentially differentiate this placeholder function body.
+    /// Finally, we also add back_box usages of all input arguments, to prevent rustc
+    /// from optimizing any arguments away.
+    fn gen_enzyme_body(
+        ecx: &ExtCtxt<'_>,
+        x: &AutoDiffAttrs,
+        n_active: u32,
+        sig: &ast::FnSig,
+        d_sig: &ast::FnSig,
+        primal: Ident,
+        new_names: &[String],
+        span: Span,
+        sig_span: Span,
+        idents: Vec<Ident>,
+        errored: bool,
+    ) -> P<ast::Block> {
+        let new_decl_span = d_sig.span;
+
+        // Just adding some default inline-asm and black_box usages to prevent early inlining
+        // and optimizations which alter the function signature.
+        //
+        // The bb_primal_call is the black_box call of the primal function. We keep it around,
+        // since it has the convenient property of returning the type of the primal function,
+        // Remember, we only care to match types here.
+        // No matter which return we pick, we always wrap it into a std::hint::black_box call,
+        // to prevent rustc from propagating it into the caller.
+        let (mut body, primal_call, bb_primal_call, bb_call_expr) = init_body_helper(
+            ecx,
+            span,
+            primal,
+            new_names,
+            sig_span,
+            new_decl_span,
+            &idents,
+            errored,
+        );
+
         if !has_ret(&d_sig.decl.output) {
             // there is no return type that we have to match, () works fine.
             return body;
@@ -446,7 +481,7 @@ mod llvm_enzyme {
 
         if primal_ret && n_active == 0 && x.mode.is_rev() {
             // We only have the primal ret.
-            body.stmts.push(ecx.stmt_expr(black_box_primal_call.clone()));
+            body.stmts.push(ecx.stmt_expr(bb_primal_call));
             return body;
         }
 
@@ -471,7 +506,7 @@ mod llvm_enzyme {
         if primal_ret {
             // We have both primal ret and active floats.
             // primal ret is first, by construction.
-            exprs.push(primal_call.clone());
+            exprs.push(primal_call);
         }
 
         // Now construct default placeholder for each active float.
@@ -538,16 +573,11 @@ mod llvm_enzyme {
                 return body;
             }
             [arg] => {
-                ret = ecx.expr_call(
-                    new_decl_span,
-                    blackbox_call_expr.clone(),
-                    thin_vec![arg.clone()],
-                );
+                ret = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![arg.clone()]);
             }
             args => {
                 let ret_tuple: P<ast::Expr> = ecx.expr_tuple(span, args.into());
-                ret =
-                    ecx.expr_call(new_decl_span, blackbox_call_expr.clone(), thin_vec![ret_tuple]);
+                ret = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![ret_tuple]);
             }
         }
         assert!(has_ret(&d_sig.decl.output));
@@ -560,14 +590,14 @@ mod llvm_enzyme {
         ecx: &ExtCtxt<'_>,
         span: Span,
         primal: Ident,
-        idents: Vec<Ident>,
+        idents: &[Ident],
     ) -> P<ast::Expr> {
         let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower;
         if has_self {
             let args: ThinVec<_> =
                 idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect();
             let self_expr = ecx.expr_self(span);
-            ecx.expr_method_call(span, self_expr, primal, args.clone())
+            ecx.expr_method_call(span, self_expr, primal, args)
         } else {
             let args: ThinVec<_> =
                 idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect();
@@ -585,6 +615,8 @@ mod llvm_enzyme {
     //
     // Error handling: If the user provides an invalid configuration (incorrect numbers, types, or
     // both), we emit an error and return the original signature. This allows us to continue parsing.
+    // FIXME(Sa4dUs): make individual activities' span available so errors
+    // can point to only the activity instead of the entire attribute
     fn gen_enzyme_decl(
         ecx: &ExtCtxt<'_>,
         sig: &ast::FnSig,
@@ -632,10 +664,22 @@ mod llvm_enzyme {
                 errors = true;
             }
         }
+
+        if has_ret && !valid_ret_activity(x.mode, x.ret_activity) {
+            dcx.emit_err(errors::AutoDiffInvalidRetAct {
+                span,
+                mode: x.mode.to_string(),
+                act: x.ret_activity.to_string(),
+            });
+            // We don't set `errors = true` to avoid annoying type errors relative
+            // to the expanded macro type signature
+        }
+
         if errors {
             // This is not the right signature, but we can continue parsing.
             return (sig.clone(), new_inputs, idents, true);
         }
+
         let unsafe_activities = x
             .input_activity
             .iter()
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 53c61831b42..5788966b6e7 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -140,8 +140,9 @@ impl CfgEval<'_> {
                     Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
                 }
                 Annotatable::Stmt(_) => {
-                    let stmt =
-                        parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap();
+                    let stmt = parser
+                        .parse_stmt_without_recovery(false, ForceCollect::Yes, false)?
+                        .unwrap();
                     Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap()))
                 }
                 Annotatable::Expr(_) => {
diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs
new file mode 100644
index 00000000000..9777e772cf2
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/define_opaque.rs
@@ -0,0 +1,54 @@
+use rustc_ast::{DUMMY_NODE_ID, ast};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_span::Span;
+
+pub(crate) fn expand(
+    ecx: &mut ExtCtxt<'_>,
+    _expand_span: Span,
+    meta_item: &ast::MetaItem,
+    mut item: Annotatable,
+) -> Vec<Annotatable> {
+    let define_opaque = match &mut item {
+        Annotatable::Item(p) => match &mut p.kind {
+            ast::ItemKind::Fn(f) => Some(&mut f.define_opaque),
+            _ => None,
+        },
+        Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind {
+            ast::AssocItemKind::Fn(func) => Some(&mut func.define_opaque),
+            _ => None,
+        },
+        Annotatable::Stmt(s) => match &mut s.kind {
+            ast::StmtKind::Item(p) => match &mut p.kind {
+                ast::ItemKind::Fn(f) => Some(&mut f.define_opaque),
+                _ => None,
+            },
+            _ => None,
+        },
+        _ => None,
+    };
+
+    let Some(list) = meta_item.meta_item_list() else {
+        ecx.dcx().span_err(meta_item.span, "expected list of type aliases");
+        return vec![item];
+    };
+
+    if let Some(define_opaque) = define_opaque {
+        *define_opaque = Some(
+            list.iter()
+                .filter_map(|entry| match entry {
+                    ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => {
+                        Some((DUMMY_NODE_ID, meta_item.path.clone()))
+                    }
+                    _ => {
+                        ecx.dcx().span_err(entry.span(), "expected path to type alias");
+                        None
+                    }
+                })
+                .collect(),
+        );
+    } else {
+        ecx.dcx().span_err(meta_item.span, "only functions and methods can define opaque types");
+    }
+
+    vec![item]
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 5aed9f76f14..46b79e09780 100644
--- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -300,13 +300,16 @@ pub(crate) fn expand_deriving_coerce_pointee(
                 to_ty: &s_ty,
                 rewritten: false,
             };
-            let mut predicate = ast::WherePredicate {
-                kind: ast::WherePredicateKind::BoundPredicate(bound.clone()),
-                span: predicate.span,
-                id: ast::DUMMY_NODE_ID,
-            };
-            substitution.visit_where_predicate(&mut predicate);
+            let mut kind = ast::WherePredicateKind::BoundPredicate(bound.clone());
+            substitution.visit_where_predicate_kind(&mut kind);
             if substitution.rewritten {
+                let predicate = ast::WherePredicate {
+                    attrs: predicate.attrs.clone(),
+                    kind,
+                    span: predicate.span,
+                    id: ast::DUMMY_NODE_ID,
+                    is_placeholder: false,
+                };
                 impl_generics.where_clause.predicates.push(predicate);
             }
         }
@@ -388,8 +391,8 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
         }
     }
 
-    fn visit_where_predicate(&mut self, where_predicate: &mut ast::WherePredicate) {
-        match &mut where_predicate.kind {
+    fn visit_where_predicate_kind(&mut self, kind: &mut ast::WherePredicateKind) {
+        match kind {
             rustc_ast::WherePredicateKind::BoundPredicate(bound) => {
                 bound
                     .bound_generic_params
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6b59ac25827..03ee59de70e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -687,9 +687,11 @@ impl<'a> TraitDef<'a> {
         // and similarly for where clauses
         where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| {
             ast::WherePredicate {
+                attrs: clause.attrs.clone(),
                 kind: clause.kind.clone(),
                 id: ast::DUMMY_NODE_ID,
                 span: clause.span.with_ctxt(ctxt),
+                is_placeholder: false,
             }
         }));
 
@@ -744,8 +746,13 @@ impl<'a> TraitDef<'a> {
                         };
 
                         let kind = ast::WherePredicateKind::BoundPredicate(predicate);
-                        let predicate =
-                            ast::WherePredicate { kind, id: ast::DUMMY_NODE_ID, span: self.span };
+                        let predicate = ast::WherePredicate {
+                            attrs: ThinVec::new(),
+                            kind,
+                            id: ast::DUMMY_NODE_ID,
+                            span: self.span,
+                            is_placeholder: false,
+                        };
                         where_clause.predicates.push(predicate);
                     }
                 }
@@ -1033,6 +1040,7 @@ impl<'a> MethodDef<'a> {
                 generics: fn_generics,
                 contract: None,
                 body: Some(body_block),
+                define_opaque: None,
             })),
             tokens: None,
         })
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index ab1e0d8ee89..30597944124 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -186,6 +186,15 @@ mod autodiff {
     }
 
     #[derive(Diagnostic)]
+    #[diag(builtin_macros_autodiff_ret_activity)]
+    pub(crate) struct AutoDiffInvalidRetAct {
+        #[primary_span]
+        pub(crate) span: Span,
+        pub(crate) mode: String,
+        pub(crate) act: String,
+    }
+
+    #[derive(Diagnostic)]
     #[diag(builtin_macros_autodiff_mode)]
     pub(crate) struct AutoDiffInvalidMode {
         #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 90447da6680..12654001a1e 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -190,7 +190,8 @@ fn make_format_args(
                                 && let [stmt] = block.stmts.as_slice()
                                 && let StmtKind::Expr(expr) = &stmt.kind
                                 && let ExprKind::Path(None, path) = &expr.kind
-                                && path.is_potential_trivial_const_arg()
+                                && path.segments.len() == 1
+                                && path.segments[0].args.is_none()
                             {
                                 err.multipart_suggestion(
                                     "quote your inlined format argument to use as string literal",
@@ -710,11 +711,9 @@ fn report_missing_placeholders(
                     };
 
                     let pos = sub.position();
-                    let sub = String::from(sub.as_str());
-                    if explained.contains(&sub) {
+                    if !explained.insert(sub.to_string()) {
                         continue;
                     }
-                    explained.insert(sub);
 
                     if !found_foreign {
                         found_foreign = true;
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 866ec72f116..13d5b42942a 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -12,14 +12,16 @@ pub(crate) mod printf {
         Escape((usize, usize)),
     }
 
-    impl<'a> Substitution<'a> {
-        pub(crate) fn as_str(&self) -> &str {
+    impl ToString for Substitution<'_> {
+        fn to_string(&self) -> String {
             match self {
-                Substitution::Format(fmt) => fmt.span,
-                Substitution::Escape(_) => "%%",
+                Substitution::Format(fmt) => fmt.span.into(),
+                Substitution::Escape(_) => "%%".into(),
             }
         }
+    }
 
+    impl Substitution<'_> {
         pub(crate) fn position(&self) -> InnerSpan {
             match self {
                 Substitution::Format(fmt) => fmt.position,
@@ -627,15 +629,17 @@ pub(crate) mod shell {
         Escape((usize, usize)),
     }
 
-    impl Substitution<'_> {
-        pub(crate) fn as_str(&self) -> String {
+    impl ToString for Substitution<'_> {
+        fn to_string(&self) -> String {
             match self {
                 Substitution::Ordinal(n, _) => format!("${n}"),
                 Substitution::Name(n, _) => format!("${n}"),
                 Substitution::Escape(_) => "$$".into(),
             }
         }
+    }
 
+    impl Substitution<'_> {
         pub(crate) fn position(&self) -> InnerSpan {
             let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self;
             InnerSpan::new(pos.0, pos.1)
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 8fdbbf8e704..90d79235820 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -83,6 +83,7 @@ impl AllocFnFactory<'_, '_> {
             generics: Generics::default(),
             contract: None,
             body,
+            define_opaque: None,
         }));
         let item = self.cx.item(
             self.span,
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index ca16583a45d..606e85577f7 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -5,6 +5,7 @@
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(assert_matches)]
@@ -18,11 +19,12 @@
 #![feature(rustdoc_internals)]
 #![feature(string_from_utf8_lossy_owned)]
 #![feature(try_blocks)]
-#![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
 extern crate proc_macro;
 
+use std::sync::Arc;
+
 use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::sym;
@@ -39,6 +41,7 @@ mod compile_error;
 mod concat;
 mod concat_bytes;
 mod concat_idents;
+mod define_opaque;
 mod derive;
 mod deriving;
 mod edition_panic;
@@ -66,13 +69,13 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     let mut register = |name, kind| resolver.register_builtin_macro(name, kind);
     macro register_bang($($name:ident: $f:expr,)*) {
-        $(register(sym::$name, SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)));)*
+        $(register(sym::$name, SyntaxExtensionKind::LegacyBang(Arc::new($f as MacroExpanderFn)));)*
     }
     macro register_attr($($name:ident: $f:expr,)*) {
-        $(register(sym::$name, SyntaxExtensionKind::LegacyAttr(Box::new($f)));)*
+        $(register(sym::$name, SyntaxExtensionKind::LegacyAttr(Arc::new($f)));)*
     }
     macro register_derive($($name:ident: $f:expr,)*) {
-        $(register(sym::$name, SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($f))));)*
+        $(register(sym::$name, SyntaxExtensionKind::LegacyDerive(Arc::new(BuiltinDerive($f))));)*
     }
 
     register_bang! {
@@ -114,6 +117,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
+        define_opaque: define_opaque::expand,
         derive: derive::Expander { is_const: false },
         derive_const: derive::Expander { is_const: true },
         global_allocator: global_allocator::expand,
@@ -137,9 +141,9 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     }
 
     let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
-    register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
-    let requires = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandRequires));
+    register(sym::quote, SyntaxExtensionKind::Bang(Arc::new(BangProcMacro { client })));
+    let requires = SyntaxExtensionKind::Attr(Arc::new(contracts::ExpandRequires));
     register(sym::contracts_requires, requires);
-    let ensures = SyntaxExtensionKind::Attr(Box::new(contracts::ExpandEnsures));
+    let ensures = SyntaxExtensionKind::Attr(Arc::new(contracts::ExpandEnsures));
     register(sym::contracts_ensures, ensures);
 }
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 6933ca09349..ba63b185e09 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -60,6 +60,7 @@ pub fn inject(
             Edition2018 => sym::rust_2018,
             Edition2021 => sym::rust_2021,
             Edition2024 => sym::rust_2024,
+            EditionFuture => sym::rust_future,
         }])
         .map(|&symbol| Ident::new(symbol, span))
         .collect();
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 472e16e62d5..768b459ec5e 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -346,6 +346,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
         generics: ast::Generics::default(),
         contract: None,
         body: Some(main_body),
+        define_opaque: None,
     }));
 
     // Honor the reexport_test_harness_main attribute