Skip to content

Commit 5bc2d88

Browse files
committed
Auto merge of rust-lang#134478 - compiler-errors:attr-span, r=<try>
Properly record metavar spans for other expansions other than TT This properly records metavar spans for nonterminals other than tokentree. This means that we operations like `span.to(other_span)` work correctly for macros. As you can see, other diagnostics involving metavars have improved as a result. Fixes rust-lang#132908 Alternative to rust-lang#133270 cc `@ehuss` cc `@petrochenkov`
2 parents 4ba4ac6 + 112a3ad commit 5bc2d88

File tree

12 files changed

+111
-29
lines changed

12 files changed

+111
-29
lines changed

compiler/rustc_expand/src/mbe/transcribe.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, T
66
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_data_structures::sync::Lrc;
9+
use rustc_data_structures::unord::UnordMap;
910
use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize};
1011
use rustc_parse::lexer::nfc_normalize;
1112
use rustc_parse::parser::ParseNtResult;
@@ -282,11 +283,17 @@ pub(super) fn transcribe<'a>(
282283
}
283284
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
284285
marker.visit_span(&mut sp);
286+
with_metavar_spans(|mspans| {
287+
mspans.write().insert(ident.span, (sp, false))
288+
});
285289
let kind = token::NtIdent(*ident, *is_raw);
286290
TokenTree::token_alone(kind, sp)
287291
}
288292
MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => {
289293
marker.visit_span(&mut sp);
294+
with_metavar_spans(|mspans| {
295+
mspans.write().insert(ident.span, (sp, false))
296+
});
290297
let kind = token::NtLifetime(*ident, *is_raw);
291298
TokenTree::token_alone(kind, sp)
292299
}
@@ -295,6 +302,10 @@ pub(super) fn transcribe<'a>(
295302
// `Delimiter::Invisible` to maintain parsing priorities.
296303
// `Interpolated` is currently used for such groups in rustc parser.
297304
marker.visit_span(&mut sp);
305+
let use_span = nt.use_span();
306+
with_metavar_spans(|mspans| {
307+
mspans.write().insert(use_span, (sp, false))
308+
});
298309
TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp)
299310
}
300311
MatchedSeq(..) => {
@@ -410,16 +421,17 @@ fn maybe_use_metavar_location(
410421
return orig_tt.clone();
411422
}
412423

413-
let insert = |mspans: &mut FxHashMap<_, _>, s, ms| match mspans.try_insert(s, ms) {
424+
let insert = |mspans: &mut UnordMap<_, _>, s, ms| match mspans.try_insert(s, (ms, false)) {
414425
Ok(_) => true,
415-
Err(err) => *err.entry.get() == ms, // Tried to insert the same span, still success
426+
Err(err) => err.entry.get().0 == ms, // Tried to insert the same span, still success
416427
};
417428
marker.visit_span(&mut metavar_span);
418429
let no_collision = match orig_tt {
419430
TokenTree::Token(token, ..) => {
420-
with_metavar_spans(|mspans| insert(mspans, token.span, metavar_span))
431+
with_metavar_spans(|mspans| insert(&mut mspans.write(), token.span, metavar_span))
421432
}
422433
TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| {
434+
let mspans = &mut mspans.write();
423435
insert(mspans, dspan.open, metavar_span)
424436
&& insert(mspans, dspan.close, metavar_span)
425437
&& insert(mspans, dspan.entire(), metavar_span)
@@ -434,13 +446,14 @@ fn maybe_use_metavar_location(
434446
match orig_tt {
435447
TokenTree::Token(Token { kind, span }, spacing) => {
436448
let span = metavar_span.with_ctxt(span.ctxt());
437-
with_metavar_spans(|mspans| insert(mspans, span, metavar_span));
449+
with_metavar_spans(|mspans| insert(&mut mspans.write(), span, metavar_span));
438450
TokenTree::Token(Token { kind: kind.clone(), span }, *spacing)
439451
}
440452
TokenTree::Delimited(dspan, dspacing, delimiter, tts) => {
441453
let open = metavar_span.with_ctxt(dspan.open.ctxt());
442454
let close = metavar_span.with_ctxt(dspan.close.ctxt());
443455
with_metavar_spans(|mspans| {
456+
let mspans = &mut mspans.write();
444457
insert(mspans, open, metavar_span) && insert(mspans, close, metavar_span)
445458
});
446459
let dspan = DelimSpan::from_pair(open, close);

compiler/rustc_middle/src/hir/map/mod.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
44
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
55
use rustc_data_structures::svh::Svh;
66
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in};
7+
use rustc_data_structures::unord::UnordMap;
78
use rustc_hir::def::{DefKind, Res};
89
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
910
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -12,7 +13,9 @@ use rustc_hir::*;
1213
use rustc_hir_pretty as pprust_hir;
1314
use rustc_middle::hir::nested_filter;
1415
use rustc_span::def_id::StableCrateId;
15-
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
16+
use rustc_span::{
17+
ErrorGuaranteed, Ident, Span, Symbol, freeze_metavar_spans, kw, sym, with_metavar_spans,
18+
};
1619

1720
use crate::hir::ModuleItems;
1821
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
@@ -1087,6 +1090,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
10871090
.map(DebuggerVisualizerFile::path_erased)
10881091
.collect();
10891092

1093+
// Freeze metavars since we do not expect any more expansion after this.
1094+
freeze_metavar_spans();
1095+
10901096
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
10911097
let mut stable_hasher = StableHasher::new();
10921098
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
@@ -1116,6 +1122,16 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
11161122
// the fly in the resolver, storing only their accumulated hash in `ResolverGlobalCtxt`,
11171123
// and combining it with other hashes here.
11181124
resolutions.visibilities_for_hashing.hash_stable(&mut hcx, &mut stable_hasher);
1125+
with_metavar_spans(|mspans| {
1126+
// Only hash the spans we ended up using.
1127+
let filtered_spans: UnordMap<_, _> = mspans
1128+
.read()
1129+
.items()
1130+
.filter(|(_, (_, b))| *b)
1131+
.map(|(s1, (s2, _))| (*s1, *s2))
1132+
.collect();
1133+
filtered_spans.hash_stable(&mut hcx, &mut stable_hasher);
1134+
});
11191135
stable_hasher.finish()
11201136
});
11211137

compiler/rustc_parse/src/validate_attr.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_session::errors::report_lit_error;
1111
use rustc_session::lint::BuiltinLintDiag;
1212
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
1313
use rustc_session::parse::ParseSess;
14-
use rustc_span::{BytePos, Span, Symbol, sym};
14+
use rustc_span::{Span, Symbol, sym};
1515

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

@@ -164,11 +164,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
164164
// wrapping it in `unsafe(...)`. Otherwise, we suggest putting the
165165
// `unsafe(`, `)` right after and right before the opening and closing
166166
// square bracket respectively.
167-
let diag_span = if attr_item.span().can_be_used_for_suggestions() {
168-
attr_item.span()
169-
} else {
170-
attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1))
171-
};
167+
let diag_span = attr_item.span();
172168

173169
if attr.span.at_least_rust_2024() {
174170
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {

compiler/rustc_span/src/lib.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ use std::str::FromStr;
8585
use std::{fmt, iter};
8686

8787
use md5::{Digest, Md5};
88-
use rustc_data_structures::fx::FxHashMap;
8988
use rustc_data_structures::stable_hasher::{Hash64, Hash128, HashStable, StableHasher};
9089
use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
90+
use rustc_data_structures::unord::UnordMap;
9191
use sha1::Sha1;
9292
use sha2::Sha256;
9393

@@ -103,7 +103,7 @@ pub struct SessionGlobals {
103103
span_interner: Lock<span_encoding::SpanInterner>,
104104
/// Maps a macro argument token into use of the corresponding metavariable in the macro body.
105105
/// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis.
106-
metavar_spans: Lock<FxHashMap<Span, Span>>,
106+
metavar_spans: FreezeLock<UnordMap<Span, (Span, bool)>>,
107107
hygiene_data: Lock<hygiene::HygieneData>,
108108

109109
/// The session's source map, if there is one. This field should only be
@@ -178,8 +178,15 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
178178
scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
179179

180180
#[inline]
181-
pub fn with_metavar_spans<R>(f: impl FnOnce(&mut FxHashMap<Span, Span>) -> R) -> R {
182-
with_session_globals(|session_globals| f(&mut session_globals.metavar_spans.lock()))
181+
pub fn with_metavar_spans<R>(f: impl FnOnce(&FreezeLock<UnordMap<Span, (Span, bool)>>) -> R) -> R {
182+
with_session_globals(|session_globals| f(&session_globals.metavar_spans))
183+
}
184+
185+
#[inline]
186+
pub fn freeze_metavar_spans() {
187+
with_session_globals(|session_globals| {
188+
session_globals.metavar_spans.freeze();
189+
});
183190
}
184191

185192
// FIXME: We should use this enum or something like it to get rid of the
@@ -872,7 +879,18 @@ impl Span {
872879

873880
/// Check if you can select metavar spans for the given spans to get matching contexts.
874881
fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) {
875-
let get = |mspans: &FxHashMap<_, _>, s| mspans.get(&s).copied();
882+
let get = |mspans: &FreezeLock<UnordMap<_, _>>, s| {
883+
if let Some(mut mspans) = mspans.try_write() {
884+
if let Some((span, read)) = mspans.get_mut(&s) {
885+
*read = true;
886+
Some(*span)
887+
} else {
888+
None
889+
}
890+
} else {
891+
if let Some((span, true)) = mspans.read().get(&s) { Some(*span) } else { None }
892+
}
893+
};
876894
match with_metavar_spans(|mspans| (get(mspans, a_orig), get(mspans, b_orig))) {
877895
(None, None) => {}
878896
(Some(meta_a), None) => {

tests/ui/drop/lint-if-let-rescope-with-macro.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: `if let` assigns a shorter lifetime since Edition 2024
22
--> $DIR/lint-if-let-rescope-with-macro.rs:12:12
33
|
44
LL | if let $p = $e { $($conseq)* } else { $($alt)* }
5-
| ^^^
5+
| ^^^^^^^^^^^
66
...
77
LL | / edition_2021_if_let! {
88
LL | | Some(_value),

tests/ui/expr/if/if-let.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ warning: irrefutable `if let` pattern
22
--> $DIR/if-let.rs:6:16
33
|
44
LL | if let $p = $e $b
5-
| ^^^
5+
| ^^^^^^^^^^^
66
...
77
LL | / foo!(a, 1, {
88
LL | | println!("irrefutable pattern");
@@ -18,7 +18,7 @@ warning: irrefutable `if let` pattern
1818
--> $DIR/if-let.rs:6:16
1919
|
2020
LL | if let $p = $e $b
21-
| ^^^
21+
| ^^^^^^^^^^^
2222
...
2323
LL | / bar!(a, 1, {
2424
LL | | println!("irrefutable pattern");

tests/ui/for-loop-while/while-let-2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ warning: irrefutable `while let` pattern
22
--> $DIR/while-let-2.rs:7:19
33
|
44
LL | while let $p = $e $b
5-
| ^^^
5+
| ^^^^^^^^^^^
66
...
77
LL | / foo!(_a, 1, {
88
LL | | println!("irrefutable pattern");
@@ -18,7 +18,7 @@ warning: irrefutable `while let` pattern
1818
--> $DIR/while-let-2.rs:7:19
1919
|
2020
LL | while let $p = $e $b
21-
| ^^^
21+
| ^^^^^^^^^^^
2222
...
2323
LL | / bar!(_a, 1, {
2424
LL | | println!("irrefutable pattern");

tests/ui/lint/wide_pointer_comparisons.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi
615615
--> $DIR/wide_pointer_comparisons.rs:169:37
616616
|
617617
LL | ($a:expr, $b:expr) => { $a == $b }
618-
| ^^
618+
| ^^^^^^^^
619619
...
620620
LL | cmp!(&a, &b);
621621
| ------------ in this macro invocation

tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ error: `mut` must be followed by a named binding
3030
--> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13
3131
|
3232
LL | let mut $eval = ();
33-
| ^^^
33+
| ^^^^
3434
...
3535
LL | mac2! { does_not_exist!() }
3636
| --------------------------- in this macro invocation
@@ -40,7 +40,7 @@ LL | mac2! { does_not_exist!() }
4040
help: remove the `mut` prefix
4141
|
4242
LL - let mut $eval = ();
43-
LL + let $eval = ();
43+
LL + let $eval = ();
4444
|
4545

4646
error: cannot find macro `does_not_exist` in this scope

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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html>
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)