unlock unlimited code runs for $79, limited time →
NOSSLETTER.techLIVE
back to OSSpedia
backwards-compatibilityapi-design

Rename #[unroll] => #[rustc_unroll] to mitigate nameres ambiguity

Project: rust-lang/rust | Language: Rust | Concepts: backwards-compatibility, api-design | Difficulty: mid
Link: https://github.com/rust-lang/rust/pull/160211

The problem

The experimental #[unroll] attribute for loop unrolling in Rust created a name resolution (nameres) ambiguity. Since built-in attributes are recognized differently from user-defined or macro attributes, introducing #[unroll] could break existing stable code that defines or imports a macro or proc-macro helper attribute of the same name. This ambiguity could cause accidental breakage when the attribute is stabilized or changed.

Why it's non-trivial

A naive fix might simply rename or remove the attribute, but that risks breaking code in subtle ways, especially as attribute name resolution is complex and interacts with both stable and unstable features. The fix needs to avoid accidental breakage, ensure deliberate (not accidental) stabilization, and maintain backwards compatibility as much as possible. It also needs to update all documentation and tests to match the new attribute name.

The approach

The PR systematically renames the attribute from #[unroll] to #[rustc_unroll] throughout the codebase, with comments explaining the reason for the change.

1. Change the attribute parser to use the new name:

-    const PATH: &[Symbol] = &[sym::unroll];
+    // FIXME(#159429): temporarily renamed to mitigate `#[unroll]` nameres ambiguity.
+    const PATH: &[Symbol] = &[sym::rustc_unroll];

This changes the parser so it only recognizes #[rustc_unroll] instead of #[unroll].

2. Update the list of built-in attributes:

-    // The `#[unroll]` attribute.
+    // The `#[rustc_unroll]` attribute.
     //
     // - https://github.com/rust-lang/rust/pull/156816
-    sym::unroll,
+    //
+    // FIXME(#159429): temporarily renamed to mitigate `#[unroll]` nameres ambiguity
+    sym::rustc_unroll,

This ensures the compiler recognizes only the new attribute name as built-in.

3. Update internal representations and documentation:

-    /// Represents `#[unroll]`
+    /// Represents `#[rustc_unroll]`
+    // FIXME(#159429): temporarily renamed from `#[unroll]` to mitigate nameres ambiguity
     Unroll(UnrollAttr),

This keeps internal data structures and comments in sync with the new name.

4. Remove the old symbol and add the new one:

-        unroll,
+        // FIXME(#159429): temporary rename to avoid `#[unroll]` nameres ambiguity
+        rustc_unroll,

This removes the old symbol from the compiler's symbol table and adds the new one.

5. Update documentation in the unstable book:

-`#[unroll]` will encourage unrolling of a loop.
+`#[rustc_unroll]` will encourage unrolling of a loop.

This ensures users see the correct attribute name in documentation.

6. Update all tests and error messages:

-    #[unroll]
+    #[rustc_unroll]

All tests and error messages are updated to use the new attribute name, ensuring consistency and correct test coverage.

From the review thread

r=me if you want to workaround it ASAP, but IMO we can wait for nightly
As I said on Zulip, merging it for beta is reasonable to me.
— mati865

I will merge / time this around the week before next stable release week, approx. 2026-08-12 or 2026-08-13 ish. If T-lang makes no decision by then, I will merge this PR and tag this beta-accepted.
— jieyouxu

Takeaways

  • Attribute names should be chosen to avoid collisions with user-defined macros or attributes, especially before stabilization.
  • When changing a language feature that could break existing code, prefer deliberate, explicit changes over accidental breakage—communicate and document the rationale.
  • Update all documentation, tests, and error messages when renaming or changing public-facing language features to maintain consistency and avoid confusion.