about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaio <c410.f3r@gmail.com>2024-07-17 17:00:48 -0300
committerCaio <c410.f3r@gmail.com>2024-07-17 17:00:48 -0300
commit553279b152a9694914dd03e3469f7ef6c01c9e28 (patch)
tree12e561f1665a12c687bae79a2563474a36bdda26
parent6be96e3865c4e59028fd50396f7a46c3498ce91d (diff)
downloadrust-553279b152a9694914dd03e3469f7ef6c01c9e28.tar.gz
rust-553279b152a9694914dd03e3469f7ef6c01c9e28.zip
Add support for literals
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs59
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs61
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs54
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr153
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs11
6 files changed, 302 insertions, 38 deletions
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index dbbd948fd70..2964ac8cc58 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -119,6 +119,8 @@ impl MetaVarExpr {
     }
 }
 
+/// Indicates what is placed in a `concat` parameter. For example, literals
+/// (`${concat("foo", "bar")}`) or adhoc identifiers (`${concat(foo, bar)}`).
 #[derive(Debug, Decodable, Encodable, PartialEq)]
 pub(crate) enum MetaVarExprConcatElem {
     /// Identifier WITHOUT a preceding dollar sign, which means that this identifier should be
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 9b4dc13c703..7e2ea8de5fc 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -6,9 +6,10 @@ use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*};
 use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR};
 use crate::mbe::{self, KleeneOp, MetaVarExpr};
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::token::IdentIsRaw;
-use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{IdentIsRaw, Lit, LitKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
+use rustc_ast::ExprKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult};
 use rustc_parse::lexer::nfc_normalize;
@@ -17,7 +18,7 @@ use rustc_session::parse::ParseSess;
 use rustc_session::parse::SymbolGallery;
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
-use rustc_span::{with_metavar_spans, Span, SyntaxContext};
+use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext};
 use smallvec::{smallvec, SmallVec};
 use std::mem;
 
@@ -691,12 +692,12 @@ fn transcribe_metavar_expr<'a>(
         MetaVarExpr::Concat(ref elements) => {
             let mut concatenated = String::new();
             for element in elements.into_iter() {
-                let string = match element {
-                    MetaVarExprConcatElem::Ident(elem) => elem.to_string(),
-                    MetaVarExprConcatElem::Literal(elem) => elem.as_str().into(),
-                    MetaVarExprConcatElem::Var(elem) => extract_ident(dcx, *elem, interp)?,
+                let symbol = match element {
+                    MetaVarExprConcatElem::Ident(elem) => elem.name,
+                    MetaVarExprConcatElem::Literal(elem) => *elem,
+                    MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?,
                 };
-                concatenated.push_str(&string);
+                concatenated.push_str(symbol.as_str());
             }
             let symbol = nfc_normalize(&concatenated);
             let concatenated_span = visited_span();
@@ -750,32 +751,42 @@ fn transcribe_metavar_expr<'a>(
     Ok(())
 }
 
-/// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree.
-fn extract_ident<'a>(
+/// Extracts an metavariable symbol that can be an identifier, a token tree or a literal.
+fn extract_var_symbol<'a>(
     dcx: DiagCtxtHandle<'a>,
     ident: Ident,
     interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
-) -> PResult<'a, String> {
+) -> PResult<'a, Symbol> {
     if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? {
         if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
             if let IdentIsRaw::Yes = is_raw {
                 return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
             }
-            return Ok(nt_ident.to_string());
+            return Ok(nt_ident.name);
         }
-        if let ParseNtResult::Tt(TokenTree::Token(
-            Token { kind: TokenKind::Ident(token_ident, is_raw), .. },
-            _,
-        )) = pnr
-        {
-            if let IdentIsRaw::Yes = is_raw {
-                return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
+
+        if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr {
+            if let TokenKind::Ident(symbol, is_raw) = kind {
+                if let IdentIsRaw::Yes = is_raw {
+                    return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
+                }
+                return Ok(*symbol);
             }
-            return Ok(token_ident.to_string());
+
+            if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind {
+                return Ok(*symbol);
+            }
+        }
+
+        if let ParseNtResult::Nt(nt) = pnr
+            && let Nonterminal::NtLiteral(expr) = &**nt
+            && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind
+        {
+            return Ok(*symbol);
         }
     }
-    Err(dcx.struct_span_err(
-        ident.span,
-        "`${concat(..)}` currently only accepts identifiers or meta-variables as parameters",
-    ))
+    Err(dcx
+        .struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`")
+        .with_note("currently only string literals are supported")
+        .with_span(ident.span))
 }
diff --git a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs
index 1acefa314aa..695a752fe17 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs
+++ b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs
@@ -1,6 +1,6 @@
 //@ run-pass
 
-#![allow(dead_code, non_camel_case_types, non_upper_case_globals)]
+#![allow(dead_code, non_camel_case_types, non_upper_case_globals, unused_variables)]
 #![feature(macro_metavar_expr_concat)]
 
 macro_rules! create_things {
@@ -37,13 +37,58 @@ macro_rules! without_dollar_sign_is_an_ident {
     };
 }
 
-macro_rules! literals {
-    ($ident:ident) => {{
-        let ${concat(_a, "_b")}: () = ();
-        let ${concat("_b", _a)}: () = ();
+macro_rules! combinations {
+    ($ident:ident, $literal:literal, $tt_ident:tt, $tt_literal:tt) => {{
+        // tt ident
+        let ${concat($tt_ident, b)} = ();
+        let ${concat($tt_ident, _b)} = ();
+        let ${concat($tt_ident, "b")} = ();
+        let ${concat($tt_ident, $tt_ident)} = ();
+        let ${concat($tt_ident, $tt_literal)} = ();
+        let ${concat($tt_ident, $ident)} = ();
+        let ${concat($tt_ident, $literal)} = ();
+        // tt literal
+        let ${concat($tt_literal, b)} = ();
+        let ${concat($tt_literal, _b)} = ();
+        let ${concat($tt_literal, "b")} = ();
+        let ${concat($tt_literal, $tt_ident)} = ();
+        let ${concat($tt_literal, $tt_literal)} = ();
+        let ${concat($tt_literal, $ident)} = ();
+        let ${concat($tt_literal, $literal)} = ();
 
-        let ${concat($ident, "_b")}: () = ();
-        let ${concat("_b", $ident)}: () = ();
+        // ident (adhoc)
+        let ${concat(_b, b)} = ();
+        let ${concat(_b, _b)} = ();
+        let ${concat(_b, "b")} = ();
+        let ${concat(_b, $tt_ident)} = ();
+        let ${concat(_b, $tt_literal)} = ();
+        let ${concat(_b, $ident)} = ();
+        let ${concat(_b, $literal)} = ();
+        // ident (param)
+        let ${concat($ident, b)} = ();
+        let ${concat($ident, _b)} = ();
+        let ${concat($ident, "b")} = ();
+        let ${concat($ident, $tt_ident)} = ();
+        let ${concat($ident, $tt_literal)} = ();
+        let ${concat($ident, $ident)} = ();
+        let ${concat($ident, $literal)} = ();
+
+        // literal (adhoc)
+        let ${concat("a", b)} = ();
+        let ${concat("a", _b)} = ();
+        let ${concat("a", "b")} = ();
+        let ${concat("a", $tt_ident)} = ();
+        let ${concat("a", $tt_literal)} = ();
+        let ${concat("a", $ident)} = ();
+        let ${concat("a", $literal)} = ();
+        // literal (param)
+        let ${concat($literal, b)} = ();
+        let ${concat($literal, _b)} = ();
+        let ${concat($literal, "b")} = ();
+        let ${concat($literal, $tt_ident)} = ();
+        let ${concat($literal, $tt_literal)} = ();
+        let ${concat($literal, $ident)} = ();
+        let ${concat($literal, $literal)} = ();
     }};
 }
 
@@ -66,5 +111,5 @@ fn main() {
     assert_eq!(VARident, 1);
     assert_eq!(VAR_123, 2);
 
-    literals!(_hello);
+    combinations!(_hello, "a", b, "b");
 }
diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs
index b2845c8d1c1..7673bd3200f 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs
+++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs
@@ -20,7 +20,7 @@ macro_rules! wrong_concat_declarations {
         //~^ ERROR `concat` must have at least two elements
 
         ${concat($ex, aaaa)}
-        //~^ ERROR `${concat(..)}` currently only accepts identifiers
+        //~^ ERROR metavariables of `${concat(..)}` must be of type
 
         ${concat($ex, aaaa 123)}
         //~^ ERROR expected comma
@@ -98,6 +98,39 @@ macro_rules! unsupported_literals {
     }};
 }
 
+macro_rules! bad_literal_string {
+    ($literal:literal) => {
+        const ${concat(_foo, $literal)}: () = ();
+        //~^ ERROR `${concat(..)}` is not generating a valid identifier
+        //~| ERROR `${concat(..)}` is not generating a valid identifier
+        //~| ERROR `${concat(..)}` is not generating a valid identifier
+        //~| ERROR `${concat(..)}` is not generating a valid identifier
+        //~| ERROR `${concat(..)}` is not generating a valid identifier
+        //~| ERROR `${concat(..)}` is not generating a valid identifier
+        //~| ERROR `${concat(..)}` is not generating a valid identifier
+    }
+}
+
+macro_rules! bad_literal_non_string {
+    ($literal:literal) => {
+        const ${concat(_foo, $literal)}: () = ();
+        //~^ ERROR metavariables of `${concat(..)}` must be of type
+        //~| ERROR metavariables of `${concat(..)}` must be of type
+        //~| ERROR metavariables of `${concat(..)}` must be of type
+        //~| ERROR metavariables of `${concat(..)}` must be of type
+        //~| ERROR metavariables of `${concat(..)}` must be of type
+    }
+}
+
+macro_rules! bad_tt_literal {
+    ($tt:tt) => {
+        const ${concat(_foo, $tt)}: () = ();
+        //~^ ERROR metavariables of `${concat(..)}` must be of type
+        //~| ERROR metavariables of `${concat(..)}` must be of type
+        //~| ERROR metavariables of `${concat(..)}` must be of type
+    }
+}
+
 fn main() {
     wrong_concat_declarations!(1);
 
@@ -113,4 +146,23 @@ fn main() {
     unsupported_literals!(_abc);
 
     empty!();
+
+    bad_literal_string!("\u{00BD}");
+    bad_literal_string!("\x41");
+    bad_literal_string!("🤷");
+    bad_literal_string!("d[-_-]b");
+
+    bad_literal_string!("-1");
+    bad_literal_string!("1.0");
+    bad_literal_string!("'1'");
+
+    bad_literal_non_string!(1);
+    bad_literal_non_string!(-1);
+    bad_literal_non_string!(1.0);
+    bad_literal_non_string!('1');
+    bad_literal_non_string!(false);
+
+    bad_tt_literal!(1);
+    bad_tt_literal!(1.0);
+    bad_tt_literal!('1');
 }
diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr
index 2fe5842b39e..2de6d2b3ce3 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr
+++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr
@@ -64,11 +64,13 @@ error: expected identifier or string literal
 LL |         let ${concat($ident, 1)}: () = ();
    |                              ^
 
-error: `${concat(..)}` currently only accepts identifiers or meta-variables as parameters
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
   --> $DIR/syntax-errors.rs:22:19
    |
 LL |         ${concat($ex, aaaa)}
    |                   ^^
+   |
+   = note: currently only string literals are supported
 
 error: variable `foo` is not recognized in meta-variable expression
   --> $DIR/syntax-errors.rs:35:30
@@ -131,5 +133,152 @@ LL |     empty!();
    |
    = note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 18 previous errors
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:103:16
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     bad_literal_string!("\u{00BD}");
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:103:16
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     bad_literal_string!("\x41");
+   |     --------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:103:16
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     bad_literal_string!("🤷");
+   |     ------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:103:16
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     bad_literal_string!("d[-_-]b");
+   |     ------------------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:103:16
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     bad_literal_string!("-1");
+   |     ------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:103:16
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     bad_literal_string!("1.0");
+   |     -------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `${concat(..)}` is not generating a valid identifier
+  --> $DIR/syntax-errors.rs:103:16
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     bad_literal_string!("'1'");
+   |     -------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:116:31
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                               ^^^^^^^
+   |
+   = note: currently only string literals are supported
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:116:31
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                               ^^^^^^^
+   |
+   = note: currently only string literals are supported
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:116:31
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                               ^^^^^^^
+   |
+   = note: currently only string literals are supported
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:116:31
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                               ^^^^^^^
+   |
+   = note: currently only string literals are supported
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:116:31
+   |
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                               ^^^^^^^
+   |
+   = note: currently only string literals are supported
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:127:31
+   |
+LL |         const ${concat(_foo, $tt)}: () = ();
+   |                               ^^
+   |
+   = note: currently only string literals are supported
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:127:31
+   |
+LL |         const ${concat(_foo, $tt)}: () = ();
+   |                               ^^
+   |
+   = note: currently only string literals are supported
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+  --> $DIR/syntax-errors.rs:127:31
+   |
+LL |         const ${concat(_foo, $tt)}: () = ();
+   |                               ^^
+   |
+   = note: currently only string literals are supported
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 33 previous errors
 
diff --git a/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs
index b2cfb211e2d..4eeb2384deb 100644
--- a/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs
+++ b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs
@@ -3,12 +3,17 @@
 #![feature(macro_metavar_expr_concat)]
 
 macro_rules! turn_to_page {
-    ($ident:ident) => {
+    ($ident:ident, $literal:literal, $tt:tt) => {
         const ${concat("Ḧ", $ident)}: i32 = 394;
+        const ${concat("Ḧ", $literal)}: i32 = 394;
+        const ${concat("Ḧ", $tt)}: i32 = 394;
     };
 }
 
 fn main() {
-    turn_to_page!(P);
-    assert_eq!(ḦP, 394);
+    turn_to_page!(P1, "á¹”2", á¹”);
+    assert_eq!(ḦṔ, 394);
+    assert_eq!(ḦP1, 394);
+    assert_eq!(ḦṔ2, 394);
+
 }