Skip to content

Commit 46c9e3a

Browse files
committed
Auto merge of rust-lang#133270 - ehuss:fix-attr-item-span, r=<try>
Fix span of unsafe attribute diagnostic This fixes the span of the `unsafe_attr_outside_unsafe` diagnostic when the attribute uses `cfg_attr` and comes from a macro. Previously the span it was pointing to was in the wrong place (offset by 2 bytes in the start, and 1 byte in the end), causing a corrupt suggestion. The problem is that the lint was trying to do manual byte manipulation of the `Attribute` span to get within the `#[` and `]` tokens. However, when the attribute comes from `cfg_attr`, that span starts from the attribute path (like `no_mangle`), not the `#[` of the `cfg_attr`. The solution here is to store the span of the `AttrItem` while parsing, so that we know for sure that it covers the correct range (the path and all args). We could not use `AttrItem::span()` (which is removed in this PR), because that function did not correctly account for the path and arguments coming from separate expansion contexts. For example, in the macro expansion of `#[$p = $a]`, the span would be `$p = ` because you are not allowed to generate a span across expansion contexts. Fixes rust-lang#132908
2 parents a7d9ebd + 92fe744 commit 46c9e3a

File tree

12 files changed

+63
-32
lines changed

12 files changed

+63
-32
lines changed

compiler/rustc_ast/src/ast.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2966,6 +2966,7 @@ impl NormalAttr {
29662966
path: Path::from_ident(ident),
29672967
args: AttrArgs::Empty,
29682968
tokens: None,
2969+
span: DUMMY_SP,
29692970
},
29702971
tokens: None,
29712972
}
@@ -2979,6 +2980,10 @@ pub struct AttrItem {
29792980
pub args: AttrArgs,
29802981
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
29812982
pub tokens: Option<LazyAttrTokenStream>,
2983+
/// The span of the contents of the attribute.
2984+
///
2985+
/// This is the span starting from the path and ending at the end of the args.
2986+
pub span: Span,
29822987
}
29832988

29842989
impl AttrItem {

compiler/rustc_ast/src/attr/mod.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,6 @@ impl Attribute {
241241
}
242242

243243
impl AttrItem {
244-
pub fn span(&self) -> Span {
245-
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
246-
}
247-
248244
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
249245
match &self.args {
250246
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
@@ -633,7 +629,7 @@ pub fn mk_attr(
633629
args: AttrArgs,
634630
span: Span,
635631
) -> Attribute {
636-
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
632+
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None, span }, None, style, span)
637633
}
638634

639635
pub fn mk_attr_from_item(

compiler/rustc_ast/src/mut_visit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
696696
match kind {
697697
AttrKind::Normal(normal) => {
698698
let NormalAttr {
699-
item: AttrItem { unsafety: _, path, args, tokens },
699+
item: AttrItem { unsafety: _, path, args, tokens, span: _ },
700700
tokens: attr_tokens,
701701
} = &mut **normal;
702702
vis.visit_path(path);
@@ -883,7 +883,7 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
883883
token::NtTy(ty) => vis.visit_ty(ty),
884884
token::NtLiteral(expr) => vis.visit_expr(expr),
885885
token::NtMeta(item) => {
886-
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
886+
let AttrItem { unsafety: _, path, args, tokens, span: _ } = item.deref_mut();
887887
vis.visit_path(path);
888888
visit_attr_args(vis, args);
889889
visit_lazy_tts(vis, tokens);

compiler/rustc_ast/src/token.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1161,7 +1161,7 @@ impl Nonterminal {
11611161
NtPat(pat) => pat.span,
11621162
NtExpr(expr) | NtLiteral(expr) => expr.span,
11631163
NtTy(ty) => ty.span,
1164-
NtMeta(attr_item) => attr_item.span(),
1164+
NtMeta(attr_item) => attr_item.span,
11651165
NtPath(path) => path.span,
11661166
NtVis(vis) => vis.span,
11671167
}

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute)
12501250
match kind {
12511251
AttrKind::Normal(normal) => {
12521252
let NormalAttr { item, tokens: _ } = &**normal;
1253-
let AttrItem { unsafety: _, path, args, tokens: _ } = item;
1253+
let AttrItem { unsafety: _, path, args, tokens: _, span: _ } = item;
12541254
try_visit!(visitor.visit_path(path, DUMMY_NODE_ID));
12551255
try_visit!(walk_attr_args(visitor, args));
12561256
}

compiler/rustc_ast_lowering/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
884884
path: normal.item.path.clone(),
885885
args: self.lower_attr_args(&normal.item.args),
886886
tokens: None,
887+
span: normal.item.span,
887888
},
888889
tokens: None,
889890
})),

compiler/rustc_builtin_macros/src/cmdline_attrs.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,16 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
1717
raw_attr.clone(),
1818
));
1919

20-
let start_span = parser.token.span;
21-
let AttrItem { unsafety, path, args, tokens: _ } =
20+
let AttrItem { unsafety, path, args, tokens: _, span } =
2221
match parser.parse_attr_item(ForceCollect::No) {
2322
Ok(ai) => ai,
2423
Err(err) => {
2524
err.emit();
2625
continue;
2726
}
2827
};
29-
let end_span = parser.token.span;
3028
if parser.token != token::Eof {
31-
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
29+
psess.dcx().emit_err(errors::InvalidCrateAttr { span });
3230
continue;
3331
}
3432

@@ -38,7 +36,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
3836
unsafety,
3937
path,
4038
args,
41-
start_span.to(end_span),
39+
span,
4240
));
4341
}
4442
}

compiler/rustc_parse/src/parser/attr.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ impl<'a> Parser<'a> {
276276

277277
// Attr items don't have attributes.
278278
self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| {
279+
let lo = this.token.span;
279280
let is_unsafe = this.eat_keyword(kw::Unsafe);
280281
let unsafety = if is_unsafe {
281282
let unsafe_span = this.prev_token.span;
@@ -290,8 +291,9 @@ impl<'a> Parser<'a> {
290291
if is_unsafe {
291292
this.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
292293
}
294+
let span = lo.to(this.prev_token.span);
293295
Ok((
294-
ast::AttrItem { unsafety, path, args, tokens: None },
296+
ast::AttrItem { unsafety, path, args, tokens: None, span },
295297
Trailing::No,
296298
UsePreAttrPos::No,
297299
))

compiler/rustc_parse/src/validate_attr.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_session::errors::report_lit_error;
1212
use rustc_session::lint::BuiltinLintDiag;
1313
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
1414
use rustc_session::parse::ParseSess;
15-
use rustc_span::{BytePos, Span, Symbol, sym};
15+
use rustc_span::{Span, Symbol, sym};
1616

1717
use crate::{errors, parse_in};
1818

@@ -161,17 +161,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
161161
if safety == AttributeSafety::Unsafe {
162162
if let ast::Safety::Default = attr_item.unsafety {
163163
let path_span = attr_item.path.span;
164-
165-
// If the `attr_item`'s span is not from a macro, then just suggest
166-
// wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
167-
// `unsafe(`, `)` right after and right before the opening and closing
168-
// square bracket respectively.
169-
let diag_span = if attr_item.span().can_be_used_for_suggestions() {
170-
attr_item.span()
171-
} else {
172-
attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1))
173-
};
174-
164+
let diag_span = attr_item.span;
175165
if attr.span.at_least_rust_2024() {
176166
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
177167
span: path_span,

tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ macro_rules! meta2 {
4040
}
4141
}
4242

43+
macro_rules! with_cfg_attr {
44+
() => {
45+
#[cfg_attr(all(), unsafe(link_section = ".custom_section"))]
46+
//~^ ERROR: unsafe attribute used without unsafe
47+
//~| WARN this is accepted in the current edition
48+
pub extern "C" fn abc() {}
49+
};
50+
}
51+
4352
tt!([unsafe(no_mangle)]);
4453
//~^ ERROR: unsafe attribute used without unsafe
4554
//~| WARN this is accepted in the current edition
@@ -52,6 +61,8 @@ meta2!(unsafe(export_name = "baw"));
5261
//~| WARN this is accepted in the current edition
5362
ident2!(export_name, "bars");
5463

64+
with_cfg_attr!();
65+
5566
#[unsafe(no_mangle)]
5667
//~^ ERROR: unsafe attribute used without unsafe
5768
//~| WARN this is accepted in the current edition

tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ macro_rules! meta2 {
4040
}
4141
}
4242

43+
macro_rules! with_cfg_attr {
44+
() => {
45+
#[cfg_attr(all(), link_section = ".custom_section")]
46+
//~^ ERROR: unsafe attribute used without unsafe
47+
//~| WARN this is accepted in the current edition
48+
pub extern "C" fn abc() {}
49+
};
50+
}
51+
4352
tt!([no_mangle]);
4453
//~^ ERROR: unsafe attribute used without unsafe
4554
//~| WARN this is accepted in the current edition
@@ -52,6 +61,8 @@ meta2!(export_name = "baw");
5261
//~| WARN this is accepted in the current edition
5362
ident2!(export_name, "bars");
5463

64+
with_cfg_attr!();
65+
5566
#[no_mangle]
5667
//~^ ERROR: unsafe attribute used without unsafe
5768
//~| WARN this is accepted in the current edition

tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr

+22-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: unsafe attribute used without unsafe
2-
--> $DIR/unsafe-attributes-fix.rs:43:6
2+
--> $DIR/unsafe-attributes-fix.rs:52:6
33
|
44
LL | tt!([no_mangle]);
55
| ^^^^^^^^^ usage of unsafe attribute
@@ -34,7 +34,7 @@ LL | #[unsafe($e)]
3434
| +++++++ +
3535

3636
error: unsafe attribute used without unsafe
37-
--> $DIR/unsafe-attributes-fix.rs:47:7
37+
--> $DIR/unsafe-attributes-fix.rs:56:7
3838
|
3939
LL | meta!(no_mangle);
4040
| ^^^^^^^^^ usage of unsafe attribute
@@ -47,7 +47,7 @@ LL | meta!(unsafe(no_mangle));
4747
| +++++++ +
4848

4949
error: unsafe attribute used without unsafe
50-
--> $DIR/unsafe-attributes-fix.rs:50:8
50+
--> $DIR/unsafe-attributes-fix.rs:59:8
5151
|
5252
LL | meta2!(export_name = "baw");
5353
| ^^^^^^^^^^^ usage of unsafe attribute
@@ -77,7 +77,24 @@ LL | #[unsafe($e = $l)]
7777
| +++++++ +
7878

7979
error: unsafe attribute used without unsafe
80-
--> $DIR/unsafe-attributes-fix.rs:55:3
80+
--> $DIR/unsafe-attributes-fix.rs:45:27
81+
|
82+
LL | #[cfg_attr(all(), link_section = ".custom_section")]
83+
| ^^^^^^^^^^^^ usage of unsafe attribute
84+
...
85+
LL | with_cfg_attr!();
86+
| ---------------- in this macro invocation
87+
|
88+
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
89+
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
90+
= note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
91+
help: wrap the attribute in `unsafe(...)`
92+
|
93+
LL | #[cfg_attr(all(), unsafe(link_section = ".custom_section"))]
94+
| +++++++ +
95+
96+
error: unsafe attribute used without unsafe
97+
--> $DIR/unsafe-attributes-fix.rs:66:3
8198
|
8299
LL | #[no_mangle]
83100
| ^^^^^^^^^ usage of unsafe attribute
@@ -89,5 +106,5 @@ help: wrap the attribute in `unsafe(...)`
89106
LL | #[unsafe(no_mangle)]
90107
| +++++++ +
91108

92-
error: aborting due to 6 previous errors
109+
error: aborting due to 7 previous errors
93110

0 commit comments

Comments
 (0)