Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/path.rs

@jieyouxu jieyouxu Jun 15, 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.

Suggestion: please edit your PR description to more meaningfully reflect what is being changed about the language (reviewers do not need a list of files being changed; they can see that through the diff already). Please describe e.g.:

  • Is this a breaking change?
  • Can you give an example of what previously worked, but now won't after this PR?
  • What are the positions where nonsensical #[path] attributes were being silently allowed, but are now loudly rejected?

For an example, seee #145463 (comment)

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

yes @jieyouxu i have updated the PR description as suggested by you
thanks for the suggestion ,I will take care of it in future

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ impl SingleAttributeParser for PathParser {
let nv = cx.expect_name_value(args, cx.attr_span, None)?;
let path = cx.expect_string_literal(nv)?;

Some(AttributeKind::Path(path))
Some(AttributeKind::Path(path, cx.attr_style))
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,7 @@ pub enum AttributeKind {
},

/// Represents `#[path]`
Path(Symbol),
Path(Symbol, AttrStyle),

/// Represents `#[pattern_complexity_limit]`
PatternComplexityLimit {
Expand Down
40 changes: 39 additions & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
AttributeKind::Optimize(..) => (),
AttributeKind::PanicRuntime => (),
AttributeKind::PatchableFunctionEntry { .. } => (),
AttributeKind::Path(..) => (),
AttributeKind::Path(_, style) => self.check_path_attribute(*style, hir_id, span),
AttributeKind::PatternComplexityLimit { .. } => (),
AttributeKind::PinV2(..) => (),
AttributeKind::PreludeImport => (),
Expand Down Expand Up @@ -942,7 +942,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
}
fn check_path_attribute(&self, style: AttrStyle, hir_id: HirId, span: Span) {
let mod_span = self.tcx.hir_span(hir_id);
if mod_span.from_expansion() {
return;
}

let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
return;
};

let ItemKind::Mod(_, module) = &item.kind else {
return;
};

let is_outer_attr = matches!(style, ast::AttrStyle::Outer);
let is_inner_attr = matches!(style, ast::AttrStyle::Inner);

let is_inline = |item_span: Span, inner_span: Span| -> bool {
self.tcx.sess.source_map().lookup_char_pos(item_span.lo()).file.name
== self.tcx.sess.source_map().lookup_char_pos(inner_span.lo()).file.name
};

let is_inline_module = is_inline(span, module.spans.inner_span);

let has_nested_external_modules = module.item_ids.iter().any(|item_id| {
let nested_item = self.tcx.hir_item(*item_id);
if let ItemKind::Mod(_, nested_mod) = &nested_item.kind {
let nested_item_span = self.tcx.hir_span(nested_item.hir_id());
return !is_inline(nested_item_span, nested_mod.spans.inner_span);
}
false
});

if is_outer_attr && is_inline_module && !has_nested_external_modules {
self.dcx().emit_err(errors::UselessPathAttribute { span });
} else if is_inner_attr && !has_nested_external_modules {
self.dcx().emit_err(errors::UselessInnerPathAttribute { span });
}
}
/// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes.
///
/// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
use crate::check_attr::ProcMacroKind;
use crate::lang_items::Duplicate;

#[derive(Diagnostic)]
#[diag("attribute `#[path]` is useless on inline modules")]
pub(crate) struct UselessPathAttribute {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag("attribute `#[path]` is useless here as there are no nested external modules")]
pub(crate) struct UselessInnerPathAttribute {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("`#[loop_match]` should be applied to a loop")]
pub(crate) struct LoopMatchAttr {
Expand Down
24 changes: 24 additions & 0 deletions tests/ui/attributes/path-inline-module.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// ERROR: #[path] on inline module with NO external submodules
#[path = "foo.rs"]
mod inline_module {} //~ ERROR attribute `#[path]` is useless on inline modules

// ERROR: #[path] on inline module with only inline submodules
#[path = "foo.rs"]
mod inline_with_inline_sub { //~ ERROR attribute `#[path]` is useless on inline modules
mod inner {} // inline, not external
}

// ERROR: #![path] inside module with no external submodules
mod useless_inner { //~ ERROR attribute `#[path]` is useless here as there are no nested external modules
#![path = "some_dir"]
// no external submodules
}

// ERROR: #![path] inside module where submodule is inline (has body)
mod thread_inline_sub { //~ ERROR attribute `#[path]` is useless here as there are no nested external modules
#![path = "thread_files"]
#[path = "tls.rs"]
mod local_data {} //~ ERROR attribute `#[path]` is useless on inline modules
}
Comment on lines +17 to +22

@theemathas theemathas Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You claim at #157260 (comment) that this code will not produce a warning. This test shows that the code produces a hard error instead. Could you explain?

View changes since the review

@krishkumarwork3-beep krishkumarwork3-beep Jun 15, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

mod thread_inline_sub { //~ ERROR attribute #[path] is useless here as there are no nested external modules
#![path = "thread_files"]
#[path = "tls.rs"]
mod local_data {} //~ ERROR attribute #[path] is useless on inline modules
} is different from
mod thread_inline_sub {
#![path = "thread_files"]
#[path = "tls.rs"]
mod local_data;
} what @JonathanBrouwer asked for
in the case 1
mod local_data {} has a body {} → it's inline → compiler already knows its content, #[path] is meaningless ,since local_data is inline (not external), thread_inline_sub has no external submodules → #![path] is also meaningless so a hard error is produced
and
in case 2
mod local_data; has a semicolon → it's external → compiler needs #[path = "tls.rs"] to find the file,since local_data is external, thread_inline_sub has an external submodule → #![path = "thread_files"] is meaningful as a directory hint so no error should come


fn main() {}
41 changes: 41 additions & 0 deletions tests/ui/attributes/path-inline-module.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
error: attribute `#[path]` is useless on inline modules
--> $DIR/path-inline-module.rs:3:1
|
LL | mod inline_module {}
| ^^^^^^^^^^^^^^^^^^^^

error: attribute `#[path]` is useless on inline modules
--> $DIR/path-inline-module.rs:7:1
|
LL | / mod inline_with_inline_sub {
LL | | mod inner {} // inline, not external
LL | | }
| |_^

error: attribute `#[path]` is useless here as there are no nested external modules
--> $DIR/path-inline-module.rs:12:1
|
LL | / mod useless_inner {
LL | | #![path = "some_dir"]
LL | | // no external submodules
LL | | }
| |_^

error: attribute `#[path]` is useless here as there are no nested external modules
--> $DIR/path-inline-module.rs:18:1
|
LL | / mod thread_inline_sub {
LL | | #![path = "thread_files"]
LL | | #[path = "tls.rs"]
LL | | mod local_data {}
LL | | }
| |_^

error: attribute `#[path]` is useless on inline modules
--> $DIR/path-inline-module.rs:21:5
|
LL | mod local_data {}
| ^^^^^^^^^^^^^^^^^

error: aborting due to 5 previous errors

28 changes: 0 additions & 28 deletions tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,34 +252,6 @@ mod macro_export {
//~| HELP remove the attribute
}

#[path = "3800"]
mod path {
mod inner { #![path="3800"] }

#[path = "3800"] fn f() { }
//~^ WARN attribute cannot be used on
//~| WARN previously accepted
//~| HELP can only be applied to
//~| HELP remove the attribute

#[path = "3800"] struct S;
//~^ WARN attribute cannot be used on
//~| WARN previously accepted
//~| HELP can only be applied to
//~| HELP remove the attribute

#[path = "3800"] type T = S;
//~^ WARN attribute cannot be used on
//~| WARN previously accepted
//~| HELP can only be applied to
//~| HELP remove the attribute

#[path = "3800"] impl S { }
//~^ WARN attribute cannot be used on
//~| WARN previously accepted
//~| HELP can only be applied to
//~| HELP remove the attribute
}

#[automatically_derived]
//~^ WARN attribute cannot be used on
Expand Down
Loading