diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 8bded7662f423..641c50b620ff5 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -696,11 +696,15 @@ impl TtParser { } fn ambiguity_error<'matcher, T: Tracker<'matcher>>( - &self, + &mut self, parser: &Parser<'_>, matcher: &'matcher [MatcherLoc], track: &mut T, ) -> NamedParseResult { + // Use a reasonable and deterministic ordering for data in the error message. + self.bb_mps.sort_unstable_by_key(|mp| mp.idx); + self.next_mps.sort_unstable_by_key(|mp| mp.idx); + let bb_locs = self.bb_mps.iter().map(|mp| &matcher[mp.idx]); let next_locs = self.next_mps.iter().map(|mp| &matcher[mp.idx]); track.ambiguity(parser, bb_locs, next_locs); diff --git a/tests/ui/macros/local-ambiguity-option-ordering.rs b/tests/ui/macros/local-ambiguity-option-ordering.rs new file mode 100644 index 0000000000000..fd9d8e17ef48f --- /dev/null +++ b/tests/ui/macros/local-ambiguity-option-ordering.rs @@ -0,0 +1,49 @@ +// Test the order in which meta-variable options causing ambiguity are presented in error messages. + +#![crate_type = "lib"] + +macro_rules! ambiguity_1 { + ($($i:ident)* $j:ident) => {}; +} + +ambiguity_1!(error); //~ ERROR local ambiguity + +macro_rules! ambiguity_2 { + ( $( $( ; $i:ident )? $( $j:ident )? ; )* ) => {}; +} + +ambiguity_2!( ; error ); //~ ERROR local ambiguity +// +// Parse tree: +// - `$(...)*`: +// - Try one repetition +// - `$(; $i)?`: +// - Try entering +// - Parse `;` +// ----> `$i` can parse `error` +// - Try ignoring +// - `$($j)?`: +// - Try entering +// - `$j` cannot parse `;` +// - failure +// - Try ignoring +// - Parse `;` +// - `$(...)*`: +// - Try another repetition +// - `$(; $i)?`: +// - Try entering +// - Cannot parse `;` +// - failure +// - Try ignoring +// - `$($j)?`: +// - Try entering +// ------------> `$j` can parse `error` +// - Try ignoring +// - Cannot parse `;` +// - failure +// - Try ignoring +// - EOF vs `error` +// - failure +// - Try no repetitions +// - EOF vs `;` +// - failure diff --git a/tests/ui/macros/local-ambiguity-option-ordering.stderr b/tests/ui/macros/local-ambiguity-option-ordering.stderr new file mode 100644 index 0000000000000..a6c79595767a0 --- /dev/null +++ b/tests/ui/macros/local-ambiguity-option-ordering.stderr @@ -0,0 +1,14 @@ +error: local ambiguity when calling macro `ambiguity_1`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). + --> $DIR/local-ambiguity-option-ordering.rs:9:14 + | +LL | ambiguity_1!(error); + | ^^^^^ + +error: local ambiguity when calling macro `ambiguity_2`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). + --> $DIR/local-ambiguity-option-ordering.rs:15:17 + | +LL | ambiguity_2!( ; error ); + | ^^^^^ + +error: aborting due to 2 previous errors +