From 7c085f7ffdf731175430b908bc11bd97282cff9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= <jana@donsz.nl>
Date: Wed, 19 Mar 2025 17:29:31 +0100
Subject: [PATCH 1/4] add rustc_macro_edition_2021

---
 .../src/attributes.rs                         |  1 +
 .../rustc_attr_data_structures/src/lib.rs     | 11 ++++-------
 .../rustc_attr_parsing/src/attributes/mod.rs  |  1 +
 .../src/attributes/rustc.rs                   | 19 +++++++++++++++++++
 compiler/rustc_attr_parsing/src/context.rs    |  2 ++
 compiler/rustc_feature/src/builtin_attrs.rs   |  8 ++++++++
 compiler/rustc_resolve/src/macros.rs          |  6 +++++-
 compiler/rustc_span/src/symbol.rs             |  1 +
 library/core/src/pin.rs                       |  1 +
 library/coretests/tests/pin.rs                | 13 +++++++++++++
 10 files changed, 55 insertions(+), 8 deletions(-)
 create mode 100644 compiler/rustc_attr_parsing/src/attributes/rustc.rs

diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index d2d1285b0756f..969bce7ae20a6 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -191,6 +191,7 @@ pub enum AttributeKind {
     },
     MacroTransparency(Transparency),
     Repr(ThinVec<(ReprAttr, Span)>),
+    RustcMacroEdition2021,
     Stability {
         stability: Stability,
         /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index bbd3308809c33..c61b44b273de5 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -182,21 +182,18 @@ macro_rules! find_attr {
     }};
 
     ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
-        fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator<Item = &'a rustc_hir::Attribute>) {}
-        check_attribute_iterator(&$attributes_list);
-
-        let find_attribute = |iter| {
+        'done: {
             for i in $attributes_list {
+                let i: &rustc_hir::Attribute = i;
                 match i {
                     rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => {
-                        return Some($e);
+                        break 'done Some($e);
                     }
                     _ => {}
                 }
             }
 
             None
-        };
-        find_attribute($attributes_list)
+        }
     }};
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 6ecd6b4d7dbb7..bac111159db53 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -28,6 +28,7 @@ pub(crate) mod cfg;
 pub(crate) mod confusables;
 pub(crate) mod deprecation;
 pub(crate) mod repr;
+pub(crate) mod rustc;
 pub(crate) mod stability;
 pub(crate) mod transparency;
 pub(crate) mod util;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc.rs b/compiler/rustc_attr_parsing/src/attributes/rustc.rs
new file mode 100644
index 0000000000000..bdd3bef2834bb
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc.rs
@@ -0,0 +1,19 @@
+use rustc_attr_data_structures::AttributeKind;
+use rustc_span::sym;
+
+use super::{AcceptContext, SingleAttributeParser};
+use crate::parser::ArgParser;
+
+pub(crate) struct RustcMacroEdition2021Parser;
+
+// FIXME(jdonszelmann): make these proper diagnostics
+impl SingleAttributeParser for RustcMacroEdition2021Parser {
+    const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_edition_2021];
+
+    fn on_duplicate(_cx: &crate::context::AcceptContext<'_>, _first_span: rustc_span::Span) {}
+
+    fn convert(_cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        assert!(args.no_args());
+        Some(AttributeKind::RustcMacroEdition2021)
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 35541bb04bd7b..a68d4578b40f7 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -15,6 +15,7 @@ use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInterna
 use crate::attributes::confusables::ConfusablesParser;
 use crate::attributes::deprecation::DeprecationParser;
 use crate::attributes::repr::ReprParser;
+use crate::attributes::rustc::RustcMacroEdition2021Parser;
 use crate::attributes::stability::{
     BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
 };
@@ -76,6 +77,7 @@ attribute_groups!(
         // tidy-alphabetical-start
         Single<ConstStabilityIndirectParser>,
         Single<DeprecationParser>,
+        Single<RustcMacroEdition2021Parser>,
         Single<TransparencyParser>,
         // tidy-alphabetical-end
     ];
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 40857e0066ee5..2511ae610f8d3 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -661,6 +661,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "`rustc_never_type_options` is used to experiment with never type fallback and work on \
          never type stabilization, and will never be stable"
     ),
+    rustc_attr!(
+        rustc_macro_edition_2021,
+        Normal,
+        template!(Word),
+        ErrorFollowing,
+        EncodeCrossCrate::No,
+        "makes spans in this macro edition 2021"
+    ),
 
     // ==========================================================================
     // Internal attributes: Runtime related:
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 7100d89ad61a8..5bb6ec3e7ced7 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -8,7 +8,7 @@ use std::sync::Arc;
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::{self as ast, Crate, NodeId, attr};
 use rustc_ast_pretty::pprust;
-use rustc_attr_parsing::StabilityLevel;
+use rustc_attr_parsing::{AttributeKind, StabilityLevel, find_attr};
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Applicability, StashKey};
 use rustc_expand::base::{
@@ -1125,6 +1125,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             edition,
         );
 
+        if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021 {}) {
+            ext.edition = Edition::Edition2021;
+        }
+
         if let Some(builtin_name) = ext.builtin_name {
             // The macro was marked with `#[rustc_builtin_macro]`.
             if let Some(builtin_macro) = self.builtin_macros.get_mut(&builtin_name) {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8a8bec35d8194..31d9ad104386f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1793,6 +1793,7 @@ symbols! {
         rustc_lint_opt_ty,
         rustc_lint_query_instability,
         rustc_lint_untracked_query_information,
+        rustc_macro_edition_2021,
         rustc_macro_transparency,
         rustc_main,
         rustc_mir,
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 7fcd19f67ee2d..bc097bf198d03 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -1943,6 +1943,7 @@ unsafe impl<T: ?Sized> PinCoerceUnsized for *mut T {}
 #[stable(feature = "pin_macro", since = "1.68.0")]
 #[rustc_macro_transparency = "semitransparent"]
 #[allow_internal_unstable(unsafe_pin_internals)]
+#[cfg_attr(not(bootstrap), rustc_macro_edition_2021)]
 pub macro pin($value:expr $(,)?) {
     // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's
     // review such a hypothetical macro (that any user-code could define):
diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs
index b3fb06e710d44..d31b24144e2ac 100644
--- a/library/coretests/tests/pin.rs
+++ b/library/coretests/tests/pin.rs
@@ -81,3 +81,16 @@ mod pin_coerce_unsized {
         arg
     }
 }
+
+#[test]
+fn spans_2021() {
+    // Check that we accept a Rust 2024 $expr.
+    std::pin::pin!(const { 1 });
+
+    // Check that temporary lifetimes work as in Rust 2021.
+    match std::pin::pin!(foo(&mut 0)) {
+        _f => {}
+    }
+}
+
+async fn foo(_: &mut usize) {}

From 93d5ca82b0b1e9cb3aff5939b2a10731caea32f1 Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Wed, 19 Mar 2025 17:42:43 +0100
Subject: [PATCH 2/4] Pin tests.

---
 library/coretests/tests/pin.rs | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs
index d31b24144e2ac..43f0448f00641 100644
--- a/library/coretests/tests/pin.rs
+++ b/library/coretests/tests/pin.rs
@@ -34,6 +34,9 @@ fn pin_const() {
     }
 
     pin_mut_const();
+
+    // Check that we accept a Rust 2024 $expr.
+    std::pin::pin!(const { 1 });
 }
 
 #[allow(unused)]
@@ -83,14 +86,11 @@ mod pin_coerce_unsized {
 }
 
 #[test]
-fn spans_2021() {
-    // Check that we accept a Rust 2024 $expr.
-    std::pin::pin!(const { 1 });
-
+fn temp_lifetime() {
     // Check that temporary lifetimes work as in Rust 2021.
+    // Regression test for https://github.com/rust-lang/rust/issues/138596
     match std::pin::pin!(foo(&mut 0)) {
-        _f => {}
+        _ => {}
     }
+    async fn foo(_: &mut usize) {}
 }
-
-async fn foo(_: &mut usize) {}

From 25896cc668ebb652d38e0a1d69a0f983e0b3408e Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Wed, 19 Mar 2025 18:08:23 +0100
Subject: [PATCH 3/4] Add cfg(not(bootstrap)) for new test.

---
 library/coretests/tests/pin.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/coretests/tests/pin.rs b/library/coretests/tests/pin.rs
index 43f0448f00641..a866cf12a3bbf 100644
--- a/library/coretests/tests/pin.rs
+++ b/library/coretests/tests/pin.rs
@@ -86,6 +86,7 @@ mod pin_coerce_unsized {
 }
 
 #[test]
+#[cfg(not(bootstrap))]
 fn temp_lifetime() {
     // Check that temporary lifetimes work as in Rust 2021.
     // Regression test for https://github.com/rust-lang/rust/issues/138596

From 0577300b414f43f2384fd4f29cd1f3ed0d406169 Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Wed, 19 Mar 2025 21:51:03 +0100
Subject: [PATCH 4/4] Address review comments.

---
 compiler/rustc_resolve/src/macros.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 5bb6ec3e7ced7..a7cbc816b8361 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1125,7 +1125,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             edition,
         );
 
-        if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021 {}) {
+        // The #[rustc_macro_edition_2021] attribute is used by the pin!() macro
+        // as a temporary workaround for a regression in expressiveness in Rust 2024.
+        // See https://github.com/rust-lang/rust/issues/138718.
+        if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021) {
             ext.edition = Edition::Edition2021;
         }