Skip to content

Commit 1ee095f

Browse files
committed
make .stash(..) work in macros without ICEing
1 parent a8437cf commit 1ee095f

File tree

4 files changed

+87
-6
lines changed

4 files changed

+87
-6
lines changed

src/librustc_errors/diagnostic_builder.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,28 @@ impl<'a> DiagnosticBuilder<'a> {
115115

116116
/// Stashes diagnostic for possible later improvement in a different,
117117
/// later stage of the compiler. The diagnostic can be accessed with
118-
/// the provided `span` and `key` through `.steal_diagnostic` on `Handler`.
118+
/// the *returned* `span` and `key` through `.steal_diagnostic` on `Handler`.
119+
/// Do not use the `span` passed into this function when calling `.steal_diagnostic`.
119120
///
120121
/// As with `buffer`, this is unless the handler has disabled such buffering.
121-
pub fn stash(self, span: Span, key: StashKey) {
122-
if let Some((diag, handler)) = self.into_diagnostic() {
122+
#[must_use = "`Span` returned by `.stash(...)` must be later used in `.steal_diagnostic(..)`"]
123+
pub fn stash(self, span: Span, key: StashKey) -> Span {
124+
self.into_diagnostic().map_or(span, |(diag, handler)| {
125+
// Before stashing the diagnostic, make sure the `span` is unique so that
126+
// we do not attempt overwriting the key's slot later when dealing with macros.
127+
// If we don't do this, then something like the following...:
128+
// ```
129+
// macro_rules! suite {
130+
// ( $( $fn:ident; )* ) => { $(const A = "A".$fn();)* }
131+
// }
132+
//
133+
// suite! { len; is_empty; }
134+
// ```
135+
// ...would result in overwriting due to using the same `def_site` span for `A`.
136+
let span = span.fresh_expansion(span.ctxt().outer_expn_data());
123137
handler.stash_diagnostic(span, key, diag);
124-
}
138+
span
139+
})
125140
}
126141

127142
/// Converts the builder to a `Diagnostic` for later emission,

src/librustc_parse/parser/item.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -936,11 +936,11 @@ impl<'a> Parser<'a> {
936936
format!("{}: <type>", id),
937937
Applicability::HasPlaceholders,
938938
);
939-
err.stash(id.span, StashKey::ItemNoType);
939+
let span = err.stash(id.span, StashKey::ItemNoType);
940940

941941
// The user intended that the type be inferred,
942942
// so treat this as if the user wrote e.g. `const A: _ = expr;`.
943-
P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID })
943+
P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID })
944944
}
945945

946946
/// Parses an enum declaration.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
macro_rules! suite {
2+
( $( $fn:ident; )* ) => {
3+
$(
4+
const A = "A".$fn();
5+
//~^ ERROR the name `A` is defined multiple times
6+
//~| ERROR missing type for `const` item
7+
//~| ERROR missing type for `const` item
8+
)*
9+
}
10+
}
11+
12+
suite! {
13+
len;
14+
is_empty;
15+
}
16+
17+
fn main() {}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
error[E0428]: the name `A` is defined multiple times
2+
--> $DIR/issue-69396-const-no-type-in-macro.rs:4:13
3+
|
4+
LL | const A = "A".$fn();
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| `A` redefined here
8+
| previous definition of the value `A` here
9+
...
10+
LL | / suite! {
11+
LL | | len;
12+
LL | | is_empty;
13+
LL | | }
14+
| |_- in this macro invocation
15+
|
16+
= note: `A` must be defined only once in the value namespace of this module
17+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
18+
19+
error: missing type for `const` item
20+
--> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
21+
|
22+
LL | const A = "A".$fn();
23+
| ^ help: provide a type for the item: `A: usize`
24+
...
25+
LL | / suite! {
26+
LL | | len;
27+
LL | | is_empty;
28+
LL | | }
29+
| |_- in this macro invocation
30+
|
31+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
32+
33+
error: missing type for `const` item
34+
--> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
35+
|
36+
LL | const A = "A".$fn();
37+
| ^ help: provide a type for the item: `A: bool`
38+
...
39+
LL | / suite! {
40+
LL | | len;
41+
LL | | is_empty;
42+
LL | | }
43+
| |_- in this macro invocation
44+
|
45+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
46+
47+
error: aborting due to 3 previous errors
48+
49+
For more information about this error, try `rustc --explain E0428`.

0 commit comments

Comments
 (0)