1. Symptoms
When you attempt to compile Rust code with an attribute incorrectly placed after a use statement, the compiler immediately halts and produces error E0775. This error is unambiguous and typically appears during the parsing phase before any actual compilation begins.
You will see an error message similar to the following:
error[E0775]: attribute must be placed before `use`
--> src/main.rs:6:1
|
5 | use std::collections::HashMap;
6 | #[deprecated]
7 | use std::hash::Hash;
| ^^^^^^^^^^^^^^^^^^^^ help: place attribute before the item: `#[deprecated] use std::hash::Hash;`
The compiler points directly to the problematic use statement and suggests the correct placement. The error occurs at the line where the attribute is incorrectly positioned, and the caret (^) aligns with the use keyword following the attribute.
Common scenarios where this error appears:
- Moving a
#[derive]attribute after ausestatement by mistake - Incorrectly formatting conditional compilation attributes like
#[cfg()] - Mixing up the order during refactoring
- Copy-pasting attributes from struct or function definitions without adjusting placement
2. Root Cause
The root cause of E0775 is a violation of Rust’s syntactic rules regarding attribute placement. In Rust, attributes attached to an item must precede that item’s declaration. When you write a use statement, any attributes meant to annotate that import must come before the use keyword, not after it.
Rust’s grammar specifies that attributes are placed in a position where they apply to the immediately following item. For use statements, the attribute must precede the use keyword:
Attribute* Visibility? use Item ;
The attribute belongs to the item being imported. Placing it after the use keyword breaks this relationship because the parser has already processed the use keyword and associated it with whatever follows.
This is different from some other languages where attributes might be placed after the declaration. Rust chose a consistent pattern where attributes always precede the item they modify, whether that item is a function, struct, module, or import statement.
Another subtle cause involves whitespace and newlines. If you have:
use std::fmt::Debug; #[allow(unused)]
The attribute still appears after the semicolon, which terminates the statement. The parser sees the use statement as complete at the semicolon, so the subsequent attribute has nothing to attach to.
3. Step-by-Step Fix
The fix requires moving the attribute to appear before the use statement it should annotate. Follow these steps:
Step 1: Locate the exact line where the error occurs. The compiler output includes the file name and line number.
Step 2: Identify the attribute that is incorrectly positioned. Look for any lines immediately above the problematic use statement.
Step 3: Move the attribute to the line directly above the use statement, ensuring there is no intervening code or comments that break the association.
Step 4: Verify that no semicolons or other statement terminators appear between the attribute and the use keyword.
Example 1: Simple correction
Before:
use std::collections::HashMap;
#[deprecated]
use std::hash::Hash;
After:
use std::collections::HashMap;
#[deprecated]
use std::hash::Hash;
Example 2: Attribute after semicolon
Before:
use std::io::Read;
#[cfg(unix)]
use std::os::unix::Fs;
After:
use std::io::Read;
#[cfg(unix)]
use std::os::unix::Fs;
Example 3: Multiple attributes
Before:
use std::sync::Arc;
#[allow(unused)]
#[deprecated]
use std::old::Legacy;
After:
use std::sync::Arc;
#[allow(unused)]
#[deprecated]
use std::old::Legacy;
Example 4: Inline attributes with visibility
Before:
pub use std::collections::HashMap;
#[doc(hidden)]
use std::internal::Private;
After:
pub use std::collections::HashMap;
#[doc(hidden)]
use std::internal::Private;
When you have visibility modifiers like pub or pub(crate), the attribute still goes before the visibility keyword:
Before:
pub #[deprecated] use std::hash::Hash;
After:
#[deprecated]
pub use std::hash::Hash;
4. Verification
After applying the fix, verify that the error is resolved by recompiling your code:
cargo build
If the fix is correct, you should see successful compilation output:
Compiling my_project v0.1.0 (file:///path/to/my_project)
Finished dev [unoptimized + debuginfo] target(s) in 0.32s
Alternatively, use cargo check for faster validation without producing binary artifacts:
cargo check
Checking my_project v0.1.0
Finished dev [unoptimized + debuginfo] target(s) in 0.24s
Run your test suite to ensure the change hasn’t introduced regressions:
cargo test
Check the entire project for similar issues by using grep or searching your editor:
rg '#\[.*\].*use ' --type rust
This search pattern looks for attributes followed by use statements on the same or subsequent lines, helping you identify any other occurrences.
5. Common Pitfalls
Several common mistakes can cause E0775 or similar errors:
Pitfall 1: Semicolon before attribute
Placing a semicolon at the end of a use statement before an attribute is a frequent mistake. The semicolon terminates the import statement, so the attribute has no item to attach to.
use std::fmt::Debug; // Semicolon ends the statement
#[allow(unused)] // Error: nothing to attach to
use std::hash::Hash;
Always place attributes before the use keyword, never after the semicolon.
Pitfall 2: Attributes on external crates
You cannot apply attributes to imports from external crates in your source code. The #[allow()] attribute on a third-party import only works in your own code:
// This is fine
#[allow(unused)]
use std::collections::HashMap;
// ⚠️ Unverified: This may not work as intended for extern crate items
use some_crate::thing;
#[deprecated] // This attribute applies to your code, not the crate's export
Pitfall 3: Confusing struct and use attribute placement
When migrating code from struct definitions to use statements, developers sometimes forget that use statements have different rules:
// Struct attribute placement (correct)
#[derive(Debug)]
struct MyStruct;
// Use statement attribute placement (correct)
#[derive(Clone)]
use std::sync::Arc;
Pitfall 4: Multi-line formatting
If you split use statements across multiple lines, ensure attributes remain on lines before the entire statement:
// Correct multi-line format
#[cfg(feature = "advanced")]
use crate::{
module_a,
module_b,
module_c,
};
Pitfall 5: Mixing inline and block comments
Comments between the attribute and use statement are generally fine, but comments before the attribute can obscure the relationship:
// Be careful with misleading comments
// This is a deprecated import
#[deprecated] // Marks this as deprecated
use old_module::LegacyItem; // Error if attribute is after semicolon
6. Related Errors
Several other Rust error codes relate to attribute placement and usage:
E0517: Attribute does not apply to this item
This error occurs when an attribute is syntactically placed correctly but semantically cannot apply to the target item type. For example, #[repr(C)] on a use statement is invalid.
error[E0517]: attribute does not apply to `use`
--> src/main.rs:5:1
|
5 | #[repr(C)] use std::fmt::Debug;
| ^^^^^^^^^ this attribute does not apply to `use`
E0730: Attribute must be placed before = in const generic parameter
Similar to E0775, this error enforces attribute ordering rules in const generic contexts.
error[E0730]: attribute must be placed before `=`
--> src/main.rs:3:1
|
3 | const N: usize = 10 #[derive(Debug)];
| ^^^^^^^^^ help: place attribute before `=`: `#[derive(Debug)] const N: usize = 10;`
E0603: Unresolved import followed by attribute When an import fails to resolve and an attribute follows it, you may see this error combined with E0603.
error[E0603]: unresolved import `nonexistent`
--> src/lib.rs:3:5
|
3 | use nonexistent::Module;
| ^^^^^^^^^^^^
help: an attribute was parsed here, but it belongs to an item before
|
5 | #[deprecated]
| ^
E0747: Attribute used after item This error indicates that an attribute appears after the item it should annotate, which is the inverse of E0775.
Understanding these related errors helps you navigate Rust’s attribute system and avoid similar mistakes in the future. The consistent rule across Rust is: attributes precede the item they modify.