diff options
author | liushuyu <liushuyu011@gmail.com> | 2022-04-05 01:19:45 -0600 |
---|---|---|
committer | liushuyu <liushuyu011@gmail.com> | 2022-04-11 02:31:17 -0600 |
commit | fed5a41fb1c2c91b77297fdd6d3731078f480441 (patch) | |
tree | ef4ff6dbee0aa56a50dec5fc9aef7df711f577bd /gcc | |
parent | e43a5c5373b341d217d2f5403f31f5174b8c4e2f (diff) | |
download | gcc-fed5a41fb1c2c91b77297fdd6d3731078f480441.zip gcc-fed5a41fb1c2c91b77297fdd6d3731078f480441.tar.gz gcc-fed5a41fb1c2c91b77297fdd6d3731078f480441.tar.bz2 |
macros: add concat! macro
Signed-off-by: Zixing Liu <liushuyu011@gmail.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/expand/rust-macro-builtins.cc | 69 | ||||
-rw-r--r-- | gcc/rust/expand/rust-macro-builtins.h | 3 | ||||
-rw-r--r-- | gcc/rust/util/rust-hir-map.cc | 1 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/builtin_macro_concat.rs | 15 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs | 23 |
5 files changed, 102 insertions, 9 deletions
diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc index 3cd6e43..85520ec 100644 --- a/gcc/rust/expand/rust-macro-builtins.cc +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -34,17 +34,12 @@ make_string (Location locus, std::string value) PrimitiveCoreType::CORETYPE_STR, {}, locus)); } -/* Parse a single string literal from the given delimited token tree, - and return the LiteralExpr for it. Allow for an optional trailing comma, - but otherwise enforce that these are the only tokens. */ +/* Match the end token of a macro given the start delimiter of the macro */ -std::unique_ptr<AST::LiteralExpr> -parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree, - Location invoc_locus) +static inline TokenId +macro_end_token (AST::DelimTokenTree &invoc_token_tree, + Parser<MacroInvocLexer> &parser) { - MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); - Parser<MacroInvocLexer> parser (std::move (lex)); - auto last_token_id = TokenId::RIGHT_CURLY; switch (invoc_token_tree.get_delim_type ()) { @@ -63,6 +58,22 @@ parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree, break; } + return last_token_id; +} + +/* Parse a single string literal from the given delimited token tree, + and return the LiteralExpr for it. Allow for an optional trailing comma, + but otherwise enforce that these are the only tokens. */ + +std::unique_ptr<AST::LiteralExpr> +parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree, + Location invoc_locus) +{ + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser<MacroInvocLexer> parser (std::move (lex)); + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + std::unique_ptr<AST::LiteralExpr> lit_expr = nullptr; if (parser.peek_current_token ()->get_id () == STRING_LITERAL) @@ -252,4 +263,44 @@ MacroBuiltin::compile_error (Location invoc_locus, AST::MacroInvocData &invoc) return AST::ASTFragment::create_error (); } +/* Expand builtin macro concat!(), which joins all the literal parameters + into a string with no delimiter. */ + +AST::ASTFragment +MacroBuiltin::concat (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto invoc_token_tree = invoc.get_delim_tok_tree (); + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser<MacroInvocLexer> parser (std::move (lex)); + auto str = std::string (); + bool has_error = false; + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + + /* NOTE: concat! could accept no argument, so we don't have any checks here */ + while (parser.peek_current_token ()->get_id () != last_token_id) + { + auto lit_expr = parser.parse_literal_expr (); + if (lit_expr) + { + str += lit_expr->as_string (); + } + else + { + rust_error_at (parser.peek_current_token ()->get_locus (), + "argument must be a constant literal"); + has_error = true; + } + parser.maybe_skip_token (COMMA); + } + + parser.skip_token (last_token_id); + + if (has_error) + return AST::ASTFragment::create_error (); + + auto node = AST::SingleASTNode (make_string (invoc_locus, str)); + return AST::ASTFragment ({node}); +} + } // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h index b119466..a581af4 100644 --- a/gcc/rust/expand/rust-macro-builtins.h +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -80,6 +80,9 @@ public: static AST::ASTFragment compile_error (Location invoc_locus, AST::MacroInvocData &invoc); + + static AST::ASTFragment concat (Location invoc_locus, + AST::MacroInvocData &invoc); }; } // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc index 47f9175..7bacc4c 100644 --- a/gcc/rust/util/rust-hir-map.cc +++ b/gcc/rust/util/rust-hir-map.cc @@ -754,6 +754,7 @@ Mappings::insert_macro_def (AST::MacroRulesDefinition *macro) {"include_bytes", MacroBuiltin::include_bytes}, {"include_str", MacroBuiltin::include_str}, {"compile_error", MacroBuiltin::compile_error}, + {"concat", MacroBuiltin::concat}, }; auto builtin = builtin_macros.find (macro->get_rule_name ()); diff --git a/gcc/testsuite/rust/compile/builtin_macro_concat.rs b/gcc/testsuite/rust/compile/builtin_macro_concat.rs new file mode 100644 index 0000000..1fcd65f --- /dev/null +++ b/gcc/testsuite/rust/compile/builtin_macro_concat.rs @@ -0,0 +1,15 @@ +macro_rules! concat { + () => {{}}; +} + +fn main () { + let not_literal = "identifier"; + concat! (); + concat! (,); // { dg-error "argument must be a constant literal" } + concat! (not_literal); // { dg-error "argument must be a constant literal" } + concat! ("message"); + concat! ("message",); + concat! ("message",1, true, false, 1.0, 10usize, 2000u64); + concat! ("message",1, true, false, 1.0, 10usize, 2000u64,); + concat! ("m", not_literal); // { dg-error "argument must be a constant literal" } +} diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs new file mode 100644 index 0000000..ca40585 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs @@ -0,0 +1,23 @@ +// { dg-output "\ntest10btrue2.15\ntest10bfalse2.151\n" } +macro_rules! concat { + () => {{}}; +} + +extern "C" { + fn printf(fmt: *const i8, ...); +} + +fn print(s: &str) { + printf("%s\n" as *const str as *const i8, s as *const str as *const i8); +} + +fn main() -> i32 { + let a = concat!(); + let b = concat!("test", 10, 'b', true, 2.15); + let c = concat!("test", 10, 'b', false, 2.15, 1u64); + print(a); + print(b); + print(c); + + 0 +} |