aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/expand/rust-macro-builtins.cc69
-rw-r--r--gcc/rust/expand/rust-macro-builtins.h3
-rw-r--r--gcc/rust/util/rust-hir-map.cc1
-rw-r--r--gcc/testsuite/rust/compile/builtin_macro_concat.rs15
-rw-r--r--gcc/testsuite/rust/execute/torture/builtin_macro_concat.rs23
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
+}