Skip to content
Open
2 changes: 2 additions & 0 deletions src/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ The following is an index of all built-in attributes.
- [`cold`] --- Hint that a function is unlikely to be called.
- [`naked`] --- Prevent the compiler from emitting a function prologue and epilogue.
- [`no_builtins`] --- Disables use of certain built-in functions.
- [`optimize`] --- Suggest an optimization goal for a function: size, speed, or none.
- [`target_feature`] --- Configure platform-specific code generation.
- [`track_caller`] --- Pass the parent call location to `std::panic::Location::caller()`.
- [`instruction_set`] --- Specify the instruction set used to generate a function's code.
Expand Down Expand Up @@ -328,6 +329,7 @@ The following is an index of all built-in attributes.
[`no_mangle`]: abi.md#the-no_mangle-attribute
[`no_std`]: names/preludes.md#the-no_std-attribute
[`non_exhaustive`]: attributes/type_system.md#the-non_exhaustive-attribute
[`optimize`]: attributes.codegen.optimize
[`panic_handler`]: panic.md#the-panic_handler-attribute
[`path`]: items/modules.md#the-path-attribute
[`proc_macro_attribute`]: procedural-macros.md#the-proc_macro_attribute-attribute
Expand Down
203 changes: 203 additions & 0 deletions src/attributes/codegen.md
Comment thread
veluca93 marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,25 @@ When `inline` is applied to an [async function] or [async closure], it applies o
r[attributes.codegen.inline.externally-exported]
The `inline` attribute is ignored if the function is externally exported with [`no_mangle`] or [`export_name`].

r[attributes.codegen.inline.optimize]
`#[inline]` and `#[inline(always)]` may not be used with `#[optimize(none)]` on the same function. (See [attributes.codegen.optimize.inline].)

```rust,compile_fail
#[optimize(none)]
#[inline] // ERROR: Not allowed.
fn f() {}
```

`#[inline]` and `#[inline(always)]` may still be used on a closure or async block that inherits `optimize(none)`. (See [attributes.codegen.optimize.closures].)

```rust
#[optimize(none)]
pub fn f() {
#[inline] || (); // Inherits `optimize(none)`.
#[inline(always)] async {}; // Inherits `optimize(none)`.
}
```

<!-- template:attributes -->
r[attributes.codegen.cold]
### The `cold` attribute
Expand Down Expand Up @@ -204,6 +223,18 @@ The [testing attributes] cannot be applied to a naked function.
r[attributes.codegen.naked.target_feature]
The [`target_feature` attribute] cannot be applied to a naked function.

r[attributes.codegen.naked.optimize]
The [`optimize` attribute] cannot be applied to a naked function. (See [attributes.codegen.optimize.naked].)

```rust,compile_fail,E0736
# use core::arch::naked_asm;
#[optimize(size)] // ERROR: Not allowed on a naked function.
#[unsafe(naked)]
pub extern "C" fn f() {
naked_asm!("ret")
}
```

<!-- TODO: Reflexive rules? -->

r[attributes.codegen.naked.abi]
Expand Down Expand Up @@ -235,6 +266,175 @@ Only the first use of the `no_builtins` attribute has effect.
> [!NOTE]
> `rustc` lints against any use following the first.

<!-- template:attributes -->
r[attributes.codegen.optimize]
## The `optimize` attribute

r[attributes.codegen.optimize.intro]
The *`optimize` [attribute]* suggests an optimization goal for the attributed function: size, speed, or none.

> [!EXAMPLE]
> ```rust
> #[optimize(size)]
> pub fn example1() {}
>
> #[optimize(speed)]
> pub fn example2() {}
>
> #[optimize(none)]
> pub fn example3() {}
> ```

> [!NOTE]
> For `rustc`, the attribute has no effect when optimizations are disabled (`-C opt-level=0`).

@RalfJung RalfJung Oct 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did someone check this against the implementation?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked this on Godbolt when you initially raised the point in the stabilization PR, but I did not check the code directly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean when -Copt-level is not passed at all, or specifically when you pass -Copt-level=0? I thought some of the purpose of this attribute was to be able to enable optimizations regardless of opt level.


r[attributes.codegen.optimize.syntax]
The syntax for the `optimize` attribute is:

```grammar,attributes
@root OptimizeAttribute ->
`optimize` `(` ( `size` | `speed` | `none` ) `)`
```

r[attributes.codegen.optimize.allowed-positions]
The `optimize` attribute may only be applied to functions with [bodies] --- [closures], [async blocks], [free functions], [associated functions] in an [inherent impl] or [trait impl], and associated functions in a [trait definition] when those functions have a [default definition].

```rust
// A free function.
#[optimize(size)]
pub fn f() {
#[optimize(speed)] || (); // A closure.
#[optimize(none)] async {}; // An async block.
}

pub struct S;
impl S {
// An associated function in an inherent impl.
#[optimize(size)]
pub fn f(&self) {}
}

pub trait Tr {
// An associated function in a trait with a default definition.
#[optimize(speed)]
fn f(&self) {}
}

impl Tr for S {
// An associated function in a trait impl.
#[optimize(none)]
fn f(&self) {}
}
```

The attribute is rejected on a function without a body.

```rust,compile_fail
trait Tr {
#[optimize(size)] // ERROR: Not allowed without a body.
fn f();
}

unsafe extern "C" {
#[optimize(size)] // ERROR: Not allowed without a body.
fn g();
}
```

r[attributes.codegen.optimize.duplicates]
The `optimize` attribute may be used only once on a function.

```rust,compile_fail
#[optimize(size)]
#[optimize(speed)] // ERROR: Multiple `optimize` attributes.
fn f() {}
```

r[attributes.codegen.optimize.modes]
The `optimize` attribute supports these modes:

- `#[optimize(size)]` suggests optimizing for smaller code, even at the cost of execution speed.
- `#[optimize(speed)]` suggests optimizing for faster execution, even at the cost of code size.
- `#[optimize(none)]` suggests compiling the function as though no optimization had been requested for it, whatever was requested for the crate as a whole.

@RalfJung RalfJung Oct 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `#[optimize(none)]` suggests compiling the function as though no optimization had been requested for it, whatever was requested for the crate as a whole.
- `#[optimize(none)]` suggests compiling the function as though no optimization had been requested for it, disregarding what was requested for the crate as a whole.

View changes since the review


> [!NOTE]
> In every form the attribute is a hint. The compiler may ignore it.

> [!WARNING]
> `#[optimize(none)]` does not make the function opaque to the optimizer. In addition to ignoring the attribute, the compiler may still optimize the function's callers using what it knows about the function and may still change the function itself in other ways, so the attribute cannot be relied on to keep a computation from being optimized away.

> [!NOTE]
> `rustc` currently optimizes a function with `#[optimize(none)]` much as it would at `-C opt-level=0`, regardless of the crate's optimization level, and does not inline it into its callers.
>
> Settings that base their defaults on the optimization level, such as debug assertions and overflow checks, ignore this attribute and use the crate's optimization level.
Comment thread
traviscross marked this conversation as resolved.
Resolved

r[attributes.codegen.optimize.inline]
`#[optimize(none)]` may not be used with `#[inline]` or `#[inline(always)]` on the same function. It may be used with `#[inline(never)]`. (See [attributes.codegen.inline.optimize].)

```rust,compile_fail
#[optimize(none)]
#[inline] // ERROR: Not allowed.
fn f() {}
```

A closure or async block that inherits `optimize(none)` may still be marked with `#[inline]` or `#[inline(always)]`. (See [attributes.codegen.optimize.closures].)

```rust
#[optimize(none)]
pub fn f() {
#[inline] || (); // Inherits `optimize(none)`.
#[inline(always)] async {}; // Inherits `optimize(none)`.
}
```

r[attributes.codegen.optimize.naked]
The `optimize` attribute cannot be applied to a [naked function]. (See [attributes.codegen.naked.optimize].)

```rust,compile_fail,E0736
# use core::arch::naked_asm;
#[optimize(size)] // ERROR: Not allowed on a naked function.
#[unsafe(naked)]
pub extern "C" fn f() {
naked_asm!("ret")
}
```

r[attributes.codegen.optimize.closures]
Closures and [async blocks] without an `optimize` attribute of their own inherit the attribute in effect on the innermost enclosing function, closure, or async block, which may itself be one inherited rather than one written directly. The body of an [async function] inherits the attribute in effect on the function, and the body of an [async closure] inherits the attribute in effect on the closure. Items and [const blocks] within a function do not inherit the attribute in effect on the function, nor do the closures and async blocks within them.

@RalfJung RalfJung Oct 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did someone check this against the implementation?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an UI test about it applying to closures (and explicit code I wrote for it). Async block I guess are a side-effect of that code; I don't remember if I added a test for nested items but them not inheriting the attribute was IIRC intentional; I imagine const blocks are a consequence of that (I assume @traviscross checked the behaviour, although possibly for const blocks it would be somewhat surprising)


```rust
#[optimize(none)]
pub fn f() {
// This closure has no `optimize` attribute of its own, so its
// body inherits `optimize(none)` from `f`.
let c = || 1 + 2;
c();
}

#[optimize(size)]
pub async fn g() {
// This body inherits `optimize(size)` from `g`.
}
```

r[attributes.codegen.optimize.trait]
When `optimize` is applied to a function in a [trait], it applies only to the code of the [default definition].

```rust
pub trait Tr {
// The default definition is optimized for size.
#[optimize(size)]
fn f(&self) {}
}

pub struct S;
impl Tr for S {
// This implementation of `Tr::f` does not inherit the trait's
// `optimize(size)`; it uses the crate's optimization level.
fn f(&self) {}
}
```

r[attributes.codegen.target_feature]
## The `target_feature` attribute

Expand Down Expand Up @@ -916,6 +1116,7 @@ If the address of the function is taken as a function pointer, the low bit of th
[`Location`]: core::panic::Location
[`naked_asm!`]: asm
[`no_mangle`]: abi.no_mangle
[`optimize` attribute]: attributes.codegen.optimize
[`target_feature` attribute]: attributes.codegen.target_feature
[`target_feature` conditional compilation option]: ../conditional-compilation.md#target_feature
[`track_caller` attribute]: attributes.codegen.track_caller
Expand All @@ -928,11 +1129,13 @@ If the address of the function is taken as a function pointer, the low bit of th
[attributes]: ../attributes.md
[bodies]: items.fn.body
[closures]: expr.closure
[const blocks]: expr.block.const
[default definition]: items.traits.associated-item-decls
[free functions]: items.fn
[function body]: items.fn.body
[functions]: ../items/functions.md
[inherent impl]: items.impl.inherent
[naked function]: attributes.codegen.naked
["Rust" ABI]: items.extern.abi.rust
[rust-abi]: ../items/external-blocks.md#abi
[target architecture]: ../conditional-compilation.md#target_arch
Expand Down
2 changes: 2 additions & 0 deletions src/items/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ The attributes that have meaning on a function are:
- [`link_section`]
- [`must_use`]
- [`no_mangle`]
- [`optimize`]
- [Lint check attributes]
- [Procedural macro attributes]
- [Testing attributes]
Expand Down Expand Up @@ -764,6 +765,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) {
[`export_name`]: ../abi.md#the-export_name-attribute
[`link_section`]: ../abi.md#the-link_section-attribute
[`no_mangle`]: ../abi.md#the-no_mangle-attribute
[`optimize`]: attributes.codegen.optimize
[built-in attributes]: ../attributes.md#built-in-attributes-index
[trait item]: traits.md
[method]: associated-items.md#methods
Expand Down
Loading