public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] macros: add concat! macro
@ 2022-06-08 12:27 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:27 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fed5a41fb1c2c91b77297fdd6d3731078f480441

commit fed5a41fb1c2c91b77297fdd6d3731078f480441
Author: liushuyu <liushuyu011@gmail.com>
Date:   Tue Apr 5 01:19:45 2022 -0600

    macros: add concat! macro
    
    Signed-off-by: Zixing Liu <liushuyu011@gmail.com>

Diff:
---
 gcc/rust/expand/rust-macro-builtins.cc             | 69 +++++++++++++++++++---
 gcc/rust/expand/rust-macro-builtins.h              |  3 +
 gcc/rust/util/rust-hir-map.cc                      |  1 +
 gcc/testsuite/rust/compile/builtin_macro_concat.rs | 15 +++++
 .../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 3cd6e43d160..85520ec60a4 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 b119466ac66..a581af4c9ab 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 47f91751aaf..7bacc4c0f01 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 00000000000..1fcd65fd648
--- /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 00000000000..ca405857320
--- /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
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 12:27 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:27 [gcc/devel/rust/master] macros: add concat! macro Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).