Attributes and Conditional Compilation
Inner and Outer Attributes
Rust distinguishes between two attribute placement forms based on the presence or absence of an exclamation mark !:
- Outer attributes (
#[...]— no!) apply to the item, field, variant, or expression that immediately follows the attribute. - Inner attributes (
#![...]— with!) apply to the enclosing scope (the crate root file, module block, or function body) inside which the attribute is placed.
Outer Attribute (`#[...]` — applies to what FOLLOWS it):
#[allow(dead_code)] ---+
struct Helper { | <-- Applies only to `struct Helper`
id: u32, |
} ---+
Inner Attribute (`#![...]` — applies to the ENCLOSING container):
mod internal { <--+
#![allow(dead_code)] ---+ <-- Applies to the entire `mod internal` block!
struct HelperA;
struct HelperB;
}
Comparing Inner (#![...]) and Outer (#[...]) Placement
| Target Scope | Inner Attribute Form (#![...]) |
Equivalent Outer Attribute Form (#[...]) |
|---|---|---|
Entire crate (src/lib.rs / src/main.rs) |
#![forbid(unsafe_code)] at top of root file |
None (the crate root has no enclosing file outside it!) |
Inline module (mod foo { ... }) |
mod foo { #![allow(unused)] ... } |
#[allow(unused)] mod foo { ... } |
File module (src/foo.rs) |
#![allow(unused)] at top of src/foo.rs |
#[allow(unused)] mod foo; in parent file |
Function body (fn f() { ... }) |
fn f() { #![allow(unused_variables)] ... } |
#[allow(unused_variables)] fn f() { ... } |
| Struct / Enum / Field / Variant | Not applicable | #[derive(Debug)] struct S { #[serde(skip)] f: u8 } |
Crate-Level Inner Attributes
Crate-wide configuration—such as #![no_std], #![forbid(unsafe_code)], #![warn(missing_docs)], and crate-level doc comments //!—can only be written as inner attributes at the very top of the crate root (src/lib.rs or src/main.rs), before any items are declared:
//! Crate-level inner doc comment (equivalent to `#![doc = "..."]`).
#![warn(unused_must_use)]
mod legacy_subsystem {
// Inner attribute applying to everything inside `legacy_subsystem`:
#![allow(dead_code)]
pub struct ActiveRecord {
pub id: u64,
}
// No warning emitted for `UnusedRecord` because of `#![allow(dead_code)]` above:
struct UnusedRecord {
tag: u8,
}
}
// Outer attribute applying ONLY to `compute_checksum`:
#[inline]
fn compute_checksum(data: &[u8]) -> u32 {
data.iter().map(|&b| u32::from(b)).sum()
}
fn main() {
let rec = legacy_subsystem::ActiveRecord { id: 7 };
println!(
"record id = {}, checksum = {}",
rec.id,
compute_checksum(b"rust")
);
}
record id = 7, checksum = 450
Doc Comments Desugar to Inner and Outer doc Attributes
Rust's doc comment syntax follows the exact same outer vs. inner convention:
/// ...(or/** ... */) is an outer doc comment that desugars to#[doc = "..."]on the following item.//! ...(or/*! ... */) is an inner doc comment that desugars to#![doc = "..."]on the enclosing module or crate.