Skip to content

Stop compilation early if macro expansion failed #144409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 27, 2025
Merged
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
8 changes: 8 additions & 0 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,7 @@ pub struct ExtCtxt<'a> {
pub(super) expanded_inert_attrs: MarkedAttrs,
/// `-Zmacro-stats` data.
pub macro_stats: FxHashMap<(Symbol, MacroKind), MacroStat>,
pub nb_macro_errors: usize,
}

impl<'a> ExtCtxt<'a> {
Expand Down Expand Up @@ -1254,6 +1255,7 @@ impl<'a> ExtCtxt<'a> {
expanded_inert_attrs: MarkedAttrs::new(),
buffered_early_lint: vec![],
macro_stats: Default::default(),
nb_macro_errors: 0,
}
}

Expand Down Expand Up @@ -1315,6 +1317,12 @@ impl<'a> ExtCtxt<'a> {
self.current_expansion.id.expansion_cause()
}

/// This method increases the internal macro errors count and then call `trace_macros_diag`.
pub fn macro_error_and_trace_macros_diag(&mut self) {
self.nb_macro_errors += 1;
self.trace_macros_diag();
}

pub fn trace_macros_diag(&mut self) {
for (span, notes) in self.expansions.iter() {
let mut db = self.dcx().create_note(errors::TraceMacro { span: *span });
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
crate_name: self.cx.ecfg.crate_name,
});

self.cx.trace_macros_diag();
self.cx.macro_error_and_trace_macros_diag();
guar
}

Expand All @@ -707,7 +707,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
) -> ErrorGuaranteed {
let guar =
self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path });
self.cx.trace_macros_diag();
self.cx.macro_error_and_trace_macros_diag();
guar
}

Expand Down Expand Up @@ -1048,7 +1048,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
annotate_err_with_kind(&mut err, kind, span);
let guar = err.emit();
self.cx.trace_macros_diag();
self.cx.macro_error_and_trace_macros_diag();
kind.dummy(span, guar)
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/src/mbe/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ enum EofMatcherPositions {
}

/// Represents the possible results of an attempted parse.
#[derive(Debug)]
pub(crate) enum ParseResult<T, F> {
/// Parsed successfully.
Success(T),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ fn expand_macro<'cx>(
// Retry and emit a better error.
let (span, guar) =
diagnostics::failed_to_match_macro(cx.psess(), sp, def_span, name, arg, rules);
cx.trace_macros_diag();
cx.macro_error_and_trace_macros_diag();
DummyResult::any(span, guar)
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ fn configure_and_expand(
// Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));

if ecx.nb_macro_errors > 0 {
sess.dcx().abort_if_errors();
}

// The rest is error reporting and stats

sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| {
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/const-generics/min_const_generics/macro-fail-const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
trait Marker<const N: usize> {}
struct Example<const N: usize>;
impl<const N: usize> Marker<N> for Example<N> {}

fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
//~^ ERROR: type provided when a constant was expected
//~| ERROR: type provided when a constant was expected
Example::<gimme_a_const!(marker)>
//~^ ERROR: type provided when a constant was expected
}

fn main() {
let _ok = Example::<{
#[macro_export]
macro_rules! gimme_a_const {
($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
//~^ ERROR expected type
//~| ERROR expected type
}
gimme_a_const!(run)
}>;
let _ok = Example::<{gimme_a_const!(marker)}>;
}
51 changes: 51 additions & 0 deletions tests/ui/const-generics/min_const_generics/macro-fail-const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
error: expected type, found `{`
--> $DIR/macro-fail-const.rs:16:27
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ----------------------
| |
| this macro call doesn't expand to a type
| in this macro invocation
...
LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
| ^ expected type
|
= note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected type, found `{`
--> $DIR/macro-fail-const.rs:16:27
|
LL | Example::<gimme_a_const!(marker)>
| ----------------------
| |
| this macro call doesn't expand to a type
| in this macro invocation
...
LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
| ^ expected type
|
= note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail-const.rs:5:33
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail-const.rs:5:33
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail-const.rs:8:13
|
LL | Example::<gimme_a_const!(marker)>
| ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0747`.
7 changes: 1 addition & 6 deletions tests/ui/const-generics/min_const_generics/macro-fail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ trait Marker<const N: usize> {}
impl<const N: usize> Marker<N> for Example<N> {}

fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
//~^ ERROR: type provided when a constant was expected
//~| ERROR: type provided when a constant was expected
Example::<gimme_a_const!(marker)>
//~^ ERROR: type provided when a constant was expected
}

fn from_marker(_: impl Marker<{
Expand All @@ -35,9 +32,7 @@ fn main() {
}>;

let _fail = Example::<external_macro!()>;
//~^ ERROR: type provided when a constant

let _fail = Example::<gimme_a_const!()>;
//~^ ERROR unexpected end of macro invocation
//~| ERROR: type provided when a constant was expected
//~^ ERROR: unexpected end of macro invocation
}
43 changes: 5 additions & 38 deletions tests/ui/const-generics/min_const_generics/macro-fail.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: expected type, found `{`
--> $DIR/macro-fail.rs:30:27
--> $DIR/macro-fail.rs:27:27
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ----------------------
Expand All @@ -13,7 +13,7 @@ LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
= note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected type, found `{`
--> $DIR/macro-fail.rs:30:27
--> $DIR/macro-fail.rs:27:27
|
LL | Example::<gimme_a_const!(marker)>
| ----------------------
Expand Down Expand Up @@ -41,7 +41,7 @@ LL | let _fail = Example::<external_macro!()>;
= note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info)

error: unexpected end of macro invocation
--> $DIR/macro-fail.rs:40:25
--> $DIR/macro-fail.rs:36:25
|
LL | macro_rules! gimme_a_const {
| -------------------------- when calling this macro
Expand All @@ -50,43 +50,10 @@ LL | let _fail = Example::<gimme_a_const!()>;
| ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
|
note: while trying to match meta-variable `$rusty:ident`
--> $DIR/macro-fail.rs:30:8
--> $DIR/macro-fail.rs:27:8
|
LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
| ^^^^^^^^^^^^^

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail.rs:14:33
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail.rs:14:33
|
LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail.rs:17:13
|
LL | Example::<gimme_a_const!(marker)>
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail.rs:37:25
|
LL | let _fail = Example::<external_macro!()>;
| ^^^^^^^^^^^^^^^^^

error[E0747]: type provided when a constant was expected
--> $DIR/macro-fail.rs:40:25
|
LL | let _fail = Example::<gimme_a_const!()>;
| ^^^^^^^^^^^^^^^^

error: aborting due to 9 previous errors
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0747`.
2 changes: 1 addition & 1 deletion tests/ui/editions/edition-keywords-2018-2015-parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn check_async() {
module::async(); //~ ERROR expected identifier, found keyword `async`
module::r#async(); // OK

let _recovery_witness: () = 0; //~ ERROR mismatched types
let _recovery_witness: () = 0; // not emitted because of the macro parsing error
}

//~? ERROR macro expansion ends with an incomplete expression
11 changes: 1 addition & 10 deletions tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,5 @@ error: macro expansion ends with an incomplete expression: expected one of `move
LL | if passes_tt!(async) == 1 {}
| ^ expected one of `move`, `use`, `{`, `|`, or `||`

error[E0308]: mismatched types
--> $DIR/edition-keywords-2018-2015-parsing.rs:29:33
|
LL | let _recovery_witness: () = 0;
| -- ^ expected `()`, found integer
| |
| expected due to this

error: aborting due to 7 previous errors
error: aborting due to 6 previous errors

For more information about this error, try `rustc --explain E0308`.
2 changes: 0 additions & 2 deletions tests/ui/editions/edition-keywords-2018-2018-parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ pub fn check_async() {
if local_passes_tt!(r#async) == 1 {} // OK
module::async(); //~ ERROR expected identifier, found keyword `async`
module::r#async(); // OK

let _recovery_witness: () = 0; //~ ERROR mismatched types
}

//~? ERROR macro expansion ends with an incomplete expression
11 changes: 1 addition & 10 deletions tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,5 @@ error: macro expansion ends with an incomplete expression: expected one of `move
LL | if local_passes_tt!(async) == 1 {}
| ^ expected one of `move`, `use`, `{`, `|`, or `||`

error[E0308]: mismatched types
--> $DIR/edition-keywords-2018-2018-parsing.rs:40:33
|
LL | let _recovery_witness: () = 0;
| -- ^ expected `()`, found integer
| |
| expected due to this

error: aborting due to 9 previous errors
error: aborting due to 8 previous errors

For more information about this error, try `rustc --explain E0308`.
3 changes: 3 additions & 0 deletions tests/ui/macros/trace-macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@

fn main() {
println!("Hello, World!");
//~^ NOTE trace_macro
//~| NOTE expanding `println!
//~| NOTE to `{
}
22 changes: 22 additions & 0 deletions tests/ui/offset-of/offset-of-tuple-field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#![feature(builtin_syntax)]

use std::mem::offset_of;

fn main() {
offset_of!((u8, u8), _0); //~ ERROR no field `_0`
offset_of!((u8, u8), 01); //~ ERROR no field `01`
offset_of!((u8, u8), 1e2); //~ ERROR no field `1e2`
offset_of!((u8, u8), 1_u8); //~ ERROR no field `1_`
//~| ERROR suffixes on a tuple index

builtin # offset_of((u8, u8), 1e2); //~ ERROR no field `1e2`
builtin # offset_of((u8, u8), _0); //~ ERROR no field `_0`
builtin # offset_of((u8, u8), 01); //~ ERROR no field `01`
builtin # offset_of((u8, u8), 1_u8); //~ ERROR no field `1_`
//~| ERROR suffixes on a tuple index

offset_of!(((u8, u16), (u32, u16, u8)), 0.2); //~ ERROR no field `2`
offset_of!(((u8, u16), (u32, u16, u8)), 0.1e2); //~ ERROR no field `1e2`
offset_of!(((u8, u16), (u32, u16, u8)), 1.2);
offset_of!(((u8, u16), (u32, u16, u8)), 1.2.0); //~ ERROR no field `0`
}
Loading
Loading