Skip to content
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
43 changes: 43 additions & 0 deletions compiler/rustc_expand/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,49 @@ mod metavar_exprs {
pub span: Span,
pub key: MacroRulesNormalizedIdent,
}

#[derive(Diagnostic)]
#[diag(r#"`${"{"}concat(..){"}"}` is not generating a valid identifier"#)]
pub(crate) struct ConcatInvalidIdent {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub reason: InvalidIdentReason,
}

#[derive(Subdiagnostic)]
pub(crate) enum InvalidIdentReason {
#[note(r#"this `${"{"}concat(..){"}"}` invocation generated an empty ident"#)]
Empty,
#[note(r#"this `${"{"}concat(..){"}"}` invocation generated `{$symbol}`, but {$start} is neither '_' nor XID_Start"#)]
#[note(
"see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers"
)]
InvalidStart { symbol: Symbol, start: char },
#[note(r#"this `${"{"}concat(..){"}"}` invocation generated `{$symbol}`, but {$not_continue} is not XID_Continue"#)]
#[note(
"see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers"
)]
InvalidContinue { symbol: Symbol, not_continue: char },
}

impl InvalidIdentReason {
pub(crate) fn new(symbol: Symbol) -> Self {
let mut chars = symbol.as_str().chars();
if let Some(start) = chars.next() {
if rustc_lexer::is_id_start(start) {
let not_continue = chars
.find(|c| !rustc_lexer::is_id_continue(*c))
.expect("InvalidIdentReason: cannot find invalid ident reason");
InvalidIdentReason::InvalidContinue { symbol, not_continue }
} else {
InvalidIdentReason::InvalidStart { symbol, start }
}
} else {
InvalidIdentReason::Empty
}
}
}
}

#[derive(Diagnostic)]
Expand Down
15 changes: 8 additions & 7 deletions compiler/rustc_expand/src/mbe/transcribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ use rustc_span::{
use smallvec::{SmallVec, smallvec};

use crate::errors::{
CountRepetitionMisplaced, MacroVarStillRepeating, MetaVarsDifSeqMatchers, MustRepeatOnce,
MveUnrecognizedVar, NoRepeatableVar, NoSyntaxVarsExprRepeat, VarNoTypo,
VarTypoSuggestionRepeatable, VarTypoSuggestionUnrepeatable, VarTypoSuggestionUnrepeatableLabel,
ConcatInvalidIdent, CountRepetitionMisplaced, InvalidIdentReason, MacroVarStillRepeating,
MetaVarsDifSeqMatchers, MustRepeatOnce, MveUnrecognizedVar, NoRepeatableVar,
NoSyntaxVarsExprRepeat, VarNoTypo, VarTypoSuggestionRepeatable, VarTypoSuggestionUnrepeatable,
VarTypoSuggestionUnrepeatableLabel,
};
use crate::mbe::macro_parser::NamedMatch;
use crate::mbe::macro_parser::NamedMatch::*;
Expand Down Expand Up @@ -656,10 +657,10 @@ fn metavar_expr_concat<'tx>(
let symbol = nfc_normalize(&concatenated);
let concatenated_span = tscx.visited_dspan(dspan);
if !rustc_lexer::is_ident(symbol.as_str()) {
return Err(dcx.struct_span_err(
concatenated_span,
"`${concat(..)}` is not generating a valid identifier",
));
return Err(dcx.create_err(ConcatInvalidIdent {
span: concatenated_span,
reason: InvalidIdentReason::new(symbol),
}));
}
tscx.psess.symbol_gallery.insert(symbol, concatenated_span);

Expand Down
10 changes: 10 additions & 0 deletions tests/ui/macros/metavar-expressions/concat-trace-errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,28 @@ macro_rules! post_expansion {
($a:literal) => {
const _: () = ${concat("hi", $a, "bye")};
//~^ ERROR is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `hi!bye`, but '!' is not XID_Continue
//~| NOTE see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
}
}

post_expansion!("!");
//~^ NOTE in this expansion of post_expansion!
//~| NOTE in this expansion of post_expansion!
//~| NOTE in this expansion of post_expansion!

macro_rules! post_expansion_many {
($a:ident, $b:ident, $c:ident, $d:literal, $e:ident) => {
const _: () = ${concat($a, $b, $c, $d, $e)};
//~^ ERROR is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `abc.de`, but '.' is not XID_Continue
//~| NOTE see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
}
}

post_expansion_many!(a, b, c, ".d", e);
//~^ NOTE in this expansion of post_expansion_many!
//~| NOTE in this expansion of post_expansion_many!
//~| NOTE in this expansion of post_expansion_many!

fn main() {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@ LL | const _: () = ${concat("hi", $a, "bye")};
LL | post_expansion!("!");
| -------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `hi!bye`, but '!' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `post_expansion` (in Nightly builds, run with -Z macro-backtrace for more info)

error: `${concat(..)}` is not generating a valid identifier
--> $DIR/concat-trace-errors.rs:26:24
--> $DIR/concat-trace-errors.rs:31:24
|
LL | const _: () = ${concat($a, $b, $c, $d, $e)};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | post_expansion_many!(a, b, c, ".d", e);
| -------------------------------------- in this macro invocation
|
= note: this `${concat(..)}` invocation generated `abc.de`, but '.' is not XID_Continue
= note: see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
= note: this error originates in the macro `post_expansion_many` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors
Expand Down
8 changes: 8 additions & 0 deletions tests/ui/macros/metavar-expressions/concat-usage-errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ edition: 2021
//@ dont-require-annotations: NOTE

#![feature(macro_metavar_expr_concat)]

Expand Down Expand Up @@ -43,6 +44,7 @@ macro_rules! starting_number {
($ident:ident) => {{
let ${concat("1", $ident)}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `1_abc`, but '1' is neither '_' nor XID_Start
}};
}

Expand All @@ -56,6 +58,8 @@ macro_rules! starting_invalid_unicode {
($ident:ident) => {{
let ${concat("\u{00BD}", $ident)}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `\u{00BD}_abc`, but '\' is neither '_' nor XID_Start
//~| NOTE see <https://doc.rust-lang.org/reference/identifiers.html> for the definition of valid identifiers
}};
}

Expand All @@ -75,13 +79,15 @@ macro_rules! ending_invalid_unicode {
($ident:ident) => {{
let ${concat($ident, "\u{00BD}")}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `_abc\u{00BD}`, but '\' is not XID_Continue
}};
}

macro_rules! empty {
() => {{
let ${concat("", "")}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated an empty ident
}};
}

Expand Down Expand Up @@ -130,6 +136,8 @@ macro_rules! bad_literal_string {
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| NOTE this `${concat(..)}` invocation generated `_foo🤷`, but '🤷' is not XID_Continue
//~| NOTE this `${concat(..)}` invocation generated `_foo-1`, but '-' is not XID_Continue
}
}

Expand Down
Loading
Loading