rust-lang/rust · critical
file modules must have an attribute to exclude
Error message
file modules must have an attribute to exclude
What it means
Internal panic in `fake_token_stream_for_file_mod`, used to reconstruct a `TokenStream` for a file-based module item (one declared via `mod foo;` and loaded from a separate file, i.e. `ModKind::Loaded(_, Inline::No, ..)`). Such modules are required to carry the inner attribute the caller wants stripped, so `attr_to_exclude` must be `Some`. Passing `None` for a file module violates the function's contract and triggers `.expect`.
Source
Thrown at compiler/rustc_parse/src/lib.rs:316
}
let source = pprust::item_to_string(item);
let filename = FileName::macro_expansion_source_code(&source);
unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span)))
}
fn fake_token_stream_for_file_mod(
psess: &ParseSess,
item: &ast::Item,
attr_to_exclude: Option<&ast::Attribute>,
) -> Option<TokenStream> {
let ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::No { .. }, spans)) =
&item.kind
else {
return None;
};
let attr = attr_to_exclude.expect("file modules must have an attribute to exclude");
assert_eq!(attr.style, ast::AttrStyle::Inner);
let mut body_tts = Vec::new();
body_tts.extend(lex_token_trees_for_span(psess, spans.inner_span.until(attr.span))?);
body_tts.extend(lex_token_trees_for_span(
psess,
attr.span.between(spans.inner_span.shrink_to_hi()),
)?);
let mut wrapper_tts = Vec::new();
for attr in item.attrs.iter().filter(|attr| attr.style == ast::AttrStyle::Outer) {
wrapper_tts.extend(attr.token_trees());
}
wrapper_tts.extend(lex_token_trees_for_span(psess, item.span)?);
let Some(TokenTree::Token(semi, _)) = wrapper_tts.pop() else {
return None;
};
if semi.kind != token::Semi {View on GitHub (pinned to 22057b88b0)
Solutions
- Report as a rustc ICE with the crate and the specific file module (`mod foo;`) that triggers it
- As a workaround, inline the module (`mod foo { ... }`) to take the `Inline::Yes` path that bypasses this function
- Bisect nightly toolchains to locate the introducing commit
Example fix
// before: file module triggers the path
mod foo;
// after: inline the module to sidestep file-mod token reconstruction
mod foo {
// ...
} Defensive patterns
Strategy: validation
Validate before calling
use rustc_ast::ast;
fn module_has_exclude_attr(item: &ast::Item) -> bool {
item.attrs.iter().any(|a| {
matches!(a.kind, ast::AttrKind::Normal(ref n)
if matches!(n.item.path.segments.iter().last().map(|s| s.ident.as_str()), Some("no_implicit_prelude") | Some("cfg")))
})
}
if !module_has_exclude_attr(&mod_item) { return Err("file module lacks exclude attribute"); } Prevention
- Before asking the parser to exclude a file module, attach the exclusion attribute (e.g. #![cfg(...)] / #![no_implicit_prelude]) in the same pass.
- Track whether a module came from a `mod.rs`/file path; file modules are the ones that require the attribute.
- Keep attribute insertion atomic with module registration so an exclude request never reaches the parser without its attribute.
- Reject exclude requests for inline modules early — they don't need the attribute and will trip the assertion.
When it happens
Trigger: The attribute/macros infrastructure calls `fake_token_stream_for_item` (or `fake_token_stream_for_file_mod`) on a file-module item while passing `attr_to_exclude: None`.
Common situations: Compiler regression in attribute expansion or cfg-attribute processing applied to `mod foo;` file modules; usually after changes to inner-attribute handling.
Related errors
- because the current token is a '{'
- This method is not called in free functions, as patterns are
- layout decided on a larger discriminant type ({min_ity:?}) t
- encountered a non-arbitrary layout during enum layout
- obj_size_bound: unknown pointer bit size {bits}
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/10fec6dd85a8110f.json.
Report an issue: GitHub.