From: Liam Naddell <liam.nadd...@mail.utoronto.ca>

gcc/rust/ChangeLog:

        * expand/rust-expand-visitor.h:
        remove auto keyword
        * expand/rust-macro-builtins-helpers.cc:
        allow for changing macro invoc types on eager expansions to
        semicoloned macros
        * expand/rust-macro-builtins-helpers.h:
        add default semicoloned argument
        * expand/rust-macro-builtins-include.cc:
        allow for eager expansion for include and include_bytes
        allow for parsing include invocations as items instead of
        expressions, which allows invocations at global scope
        * expand/rust-macro-expand.cc:
        push Expr type for eager invocations

gcc/testsuite/ChangeLog:

        * rust/compile/macros/builtin/include1.rs:
        add basic include test at global scope
        * rust/compile/macros/builtin/include2.rs:
        add basic include test at local scope with expression
        * rust/compile/macros/builtin/include3.rs:
        add eager expansion test at global scope
        * rust/compile/macros/builtin/include4.rs:
        add eager expansion test at local scope with expression
        * rust/compile/macros/builtin/include_bytes.rs:
        add eager expansion test at global scope
        * rust/compile/macros/builtin/include_rs:
        supporting test file with dummy function
        * rust/compile/macros/builtin/include_rs2:
        supporting test file with dummy string
        * rust/compile/macros/builtin/include_str.rs:
        add eager expansion test at global scope
        * rust/execute/torture/builtin_macro_include_bytes.rs:
        clean up old test logic, add permutations for eager expansion
        * rust/execute/torture/builtin_macro_include_str.rs:
        add eager expansion permutations
---
 gcc/rust/expand/rust-expand-visitor.h         |  2 +-
 .../expand/rust-macro-builtins-helpers.cc     |  7 +--
 gcc/rust/expand/rust-macro-builtins-helpers.h |  3 +-
 .../expand/rust-macro-builtins-include.cc     | 54 +++++++++++++++----
 gcc/rust/expand/rust-macro-expand.cc          |  7 ++-
 .../rust/compile/macros/builtin/include1.rs   | 14 +++++
 .../rust/compile/macros/builtin/include2.rs   | 11 ++++
 .../rust/compile/macros/builtin/include3.rs   | 19 +++++++
 .../rust/compile/macros/builtin/include4.rs   | 15 ++++++
 .../compile/macros/builtin/include_bytes.rs   |  8 +++
 .../rust/compile/macros/builtin/include_rs    |  1 +
 .../rust/compile/macros/builtin/include_rs2   |  1 +
 .../compile/macros/builtin/include_str.rs     |  8 +++
 .../torture/builtin_macro_include_bytes.rs    | 49 +++++++++--------
 .../torture/builtin_macro_include_str.rs      | 11 +++-
 15 files changed, 170 insertions(+), 40 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/macros/builtin/include1.rs
 create mode 100644 gcc/testsuite/rust/compile/macros/builtin/include2.rs
 create mode 100644 gcc/testsuite/rust/compile/macros/builtin/include3.rs
 create mode 100644 gcc/testsuite/rust/compile/macros/builtin/include4.rs
 create mode 100644 gcc/testsuite/rust/compile/macros/builtin/include_rs
 create mode 100644 gcc/testsuite/rust/compile/macros/builtin/include_rs2

diff --git a/gcc/rust/expand/rust-expand-visitor.h 
b/gcc/rust/expand/rust-expand-visitor.h
index aca6c93db09..5fc1011e001 100644
--- a/gcc/rust/expand/rust-expand-visitor.h
+++ b/gcc/rust/expand/rust-expand-visitor.h
@@ -140,7 +140,7 @@ public:
            it = values.erase (it);
            for (auto &node : final_fragment.get_nodes ())
              {
-               auto new_node = extractor (node);
+               U new_node = extractor (node);
                if (new_node != nullptr)
                  {
                    it = values.insert (it, std::move (new_node));
diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.cc 
b/gcc/rust/expand/rust-macro-builtins-helpers.cc
index d44efccd195..55d113c81c3 100644
--- a/gcc/rust/expand/rust-macro-builtins-helpers.cc
+++ b/gcc/rust/expand/rust-macro-builtins-helpers.cc
@@ -174,7 +174,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser,
 std::unique_ptr<AST::Expr>
 parse_single_string_literal (BuiltinMacro kind,
                             AST::DelimTokenTree &invoc_token_tree,
-                            location_t invoc_locus, MacroExpander *expander)
+                            location_t invoc_locus, MacroExpander *expander,
+                            bool is_semicoloned)
 {
   MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
   Parser<MacroInvocLexer> parser (lex);
@@ -221,7 +222,7 @@ parse_single_string_literal (BuiltinMacro kind,
            AST::MacroInvocData (AST::SimplePath ({AST::SimplePathSegment (
                                   path_str, invoc_locus)}),
                                 std::move (invoc_token_tree)),
-           {}, invoc_locus, std::move (pending_invocations));
+           {}, invoc_locus, std::move (pending_invocations), is_semicoloned);
        }
       else
        {
@@ -281,4 +282,4 @@ load_file_bytes (location_t invoc_locus, const char 
*filename)
 
   return buf;
 }
-} // namespace Rust
\ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.h 
b/gcc/rust/expand/rust-macro-builtins-helpers.h
index bf058df13de..ee5cae76764 100644
--- a/gcc/rust/expand/rust-macro-builtins-helpers.h
+++ b/gcc/rust/expand/rust-macro-builtins-helpers.h
@@ -74,7 +74,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser,
 std::unique_ptr<AST::Expr>
 parse_single_string_literal (BuiltinMacro kind,
                             AST::DelimTokenTree &invoc_token_tree,
-                            location_t invoc_locus, MacroExpander *expander);
+                            location_t invoc_locus, MacroExpander *expander,
+                            bool is_semicoloned = false);
 
 // Treat PATH as a path relative to the source file currently being
 // compiled, and return the absolute path for it.
diff --git a/gcc/rust/expand/rust-macro-builtins-include.cc 
b/gcc/rust/expand/rust-macro-builtins-include.cc
index cf3f93da094..4719b0e268e 100644
--- a/gcc/rust/expand/rust-macro-builtins-include.cc
+++ b/gcc/rust/expand/rust-macro-builtins-include.cc
@@ -40,7 +40,12 @@ MacroBuiltin::include_bytes_handler (location_t invoc_locus,
   if (lit_expr == nullptr)
     return AST::Fragment::create_error ();
 
-  rust_assert (lit_expr->is_literal ());
+  if (!lit_expr->is_literal ())
+    {
+      auto token_tree = invoc.get_delim_tok_tree ();
+      return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))},
+                           token_tree.to_token_stream ());
+    }
 
   std::string target_filename
     = source_relative_path (lit_expr->as_string (), invoc_locus);
@@ -188,16 +193,36 @@ MacroBuiltin::include_handler (location_t invoc_locus,
                               AST::MacroInvocData &invoc,
                               AST::InvocKind semicolon)
 {
+  bool is_semicoloned = semicolon == AST::InvocKind::Semicoloned;
   /* Get target filename from the macro invocation, which is treated as a path
      relative to the include!-ing file (currently being compiled).  */
-  auto lit_expr
+  std::unique_ptr<AST::Expr> lit_expr
     = parse_single_string_literal (BuiltinMacro::Include,
                                   invoc.get_delim_tok_tree (), invoc_locus,
-                                  invoc.get_expander ());
+                                  invoc.get_expander (), is_semicoloned);
   if (lit_expr == nullptr)
     return AST::Fragment::create_error ();
 
-  rust_assert (lit_expr->is_literal ());
+  if (!lit_expr->is_literal ())
+    {
+      // We have to expand an inner macro eagerly
+      auto token_tree = invoc.get_delim_tok_tree ();
+
+      // parse_single_string_literal returned an AST::MacroInvocation, which
+      // can either be an AST::Item or AST::Expr. Depending on the context the
+      // original macro was invoked in, we will set AST::Item or AST::Expr
+      // appropriately.
+      if (is_semicoloned)
+       {
+         std::unique_ptr<AST::Item> lit_item = std::unique_ptr<AST::Item> (
+           static_cast<AST::MacroInvocation *> (lit_expr.release ()));
+         return AST::Fragment ({AST::SingleASTNode (std::move (lit_item))},
+                               token_tree.to_token_stream ());
+       }
+      else
+       return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))},
+                             token_tree.to_token_stream ());
+    }
 
   std::string filename
     = source_relative_path (lit_expr->as_string (), invoc_locus);
@@ -218,8 +243,14 @@ MacroBuiltin::include_handler (location_t invoc_locus,
 
   Lexer lex (target_filename, std::move (target_file), linemap);
   Parser<Lexer> parser (lex);
+  std::unique_ptr<AST::Expr> parsed_expr = nullptr;
+  std::vector<std::unique_ptr<AST::Item>> parsed_items{};
+
+  if (is_semicoloned)
+    parsed_items = parser.parse_items ();
+  else
+    parsed_expr = parser.parse_expr ();
 
-  auto parsed_items = parser.parse_items ();
   bool has_error = !parser.get_errors ().empty ();
 
   for (const auto &error : parser.get_errors ())
@@ -233,17 +264,22 @@ MacroBuiltin::include_handler (location_t invoc_locus,
     }
 
   std::vector<AST::SingleASTNode> nodes{};
-  for (auto &item : parsed_items)
+  if (is_semicoloned)
+    for (auto &item : parsed_items)
+      {
+       AST::SingleASTNode node (std::move (item));
+       nodes.push_back (node);
+      }
+  else
     {
-      AST::SingleASTNode node (std::move (item));
+      AST::SingleASTNode node (std::move (parsed_expr));
       nodes.push_back (node);
     }
-
   // FIXME: This returns an empty vector of tokens and works fine, but is that
   // the expected behavior? `include` macros are a bit harder to reason about
   // since they include tokens. Furthermore, our lexer has no easy way to 
return
   // a slice of tokens like the MacroInvocLexer. So it gets even harder to
-  // extrac tokens from here. For now, let's keep it that way and see if it
+  // extract tokens from here. For now, let's keep it that way and see if it
   // eventually breaks, but I don't expect it to cause many issues since the
   // list of tokens is only used when a macro invocation mixes eager
   // macro invocations and already expanded tokens. Think
diff --git a/gcc/rust/expand/rust-macro-expand.cc 
b/gcc/rust/expand/rust-macro-expand.cc
index 4d9cadec53c..e86bfcb9ce1 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -250,7 +250,12 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
     }
 
   if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
-    expand_eager_invocations (invoc);
+    {
+      // Eager expansions are always expressions
+      push_context (ContextType::EXPR);
+      expand_eager_invocations (invoc);
+      pop_context ();
+    }
 
   AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
 
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include1.rs 
b/gcc/testsuite/rust/compile/macros/builtin/include1.rs
new file mode 100644
index 00000000000..3ad64b7c96b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include1.rs
@@ -0,0 +1,14 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+    () => {};
+}
+
+include!("include_rs");
+
+fn main() -> i32 {
+    b();
+
+    0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include2.rs 
b/gcc/testsuite/rust/compile/macros/builtin/include2.rs
new file mode 100644
index 00000000000..d2344ac7a27
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include2.rs
@@ -0,0 +1,11 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+    () => {};
+}
+
+fn main() -> i32 {
+    let _ = include!("include_rs2");
+    0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include3.rs 
b/gcc/testsuite/rust/compile/macros/builtin/include3.rs
new file mode 100644
index 00000000000..62c0e521bb3
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include3.rs
@@ -0,0 +1,19 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+    () => {};
+}
+
+macro_rules! my_file {
+    () => {"include_rs"};
+}
+
+
+include!(my_file!());
+
+fn main() -> i32 {
+    b();
+
+    0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include4.rs 
b/gcc/testsuite/rust/compile/macros/builtin/include4.rs
new file mode 100644
index 00000000000..c2450fc975c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include4.rs
@@ -0,0 +1,15 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+    () => {};
+}
+
+macro_rules! my_file {
+    () => {"include_rs2"};
+}
+fn main() -> i32 {
+    let _ = include!(my_file!());
+
+    0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs 
b/gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs
index 88ceaf18aa4..3ea28133871 100644
--- a/gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs
@@ -5,6 +5,12 @@ macro_rules! include_bytes {
     () => {{}};
 }
 
+macro_rules! file1 {
+    () => {"file"};
+}
+
+static MY_FILE: &[u32;16] = include_bytes!(file!());
+
 fn main() {
     let file = "include.txt";
     include_bytes!(file); // { dg-error "argument must be a string literal" "" 
}
@@ -12,4 +18,6 @@ fn main() {
     include_bytes!("foo.txt", "bar.txt"); // { dg-error "macro takes 1 
argument" "" }
     include_bytes!("include_bytes.rs"); // ok
     include_bytes!("include_bytes.rs",); // trailing comma ok
+    include_bytes! (file1!());
+    include_bytes! (file1!(),); // trailing comma ok
 }
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_rs 
b/gcc/testsuite/rust/compile/macros/builtin/include_rs
new file mode 100644
index 00000000000..77c3e260bee
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_rs
@@ -0,0 +1 @@
+fn b() {}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_rs2 
b/gcc/testsuite/rust/compile/macros/builtin/include_rs2
new file mode 100644
index 00000000000..31b272a7c10
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_rs2
@@ -0,0 +1 @@
+"Gccrs is GREAT!"
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_str.rs 
b/gcc/testsuite/rust/compile/macros/builtin/include_str.rs
index 37a7218556a..eda04ac1252 100644
--- a/gcc/testsuite/rust/compile/macros/builtin/include_str.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_str.rs
@@ -5,6 +5,12 @@ macro_rules! include_str {
     () => {{}};
 }
 
+macro_rules! my_file {
+    () => {"include.txt"}
+}
+
+static G_STR:[u8;16] = include_str!(my_file!());
+
 fn main() {
     let file = "include.txt";
     include_str!(file); // { dg-error "argument must be a string literal" "" }
@@ -13,4 +19,6 @@ fn main() {
     include_str!("include_str.rs"); // ok
     include_str!("include_str.rs",); // trailing comma ok
     include_str!("invalid_utf8"); // { dg-error "invalid_utf8 was not a valid 
utf-8 file" "" }
+    include_str!(my_file!());
+    include_str!(my_file!(),);
 }
diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs 
b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
index 19a1faff11c..6aec417e94f 100644
--- a/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
+++ b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
@@ -1,4 +1,5 @@
-// { dg-output "104\r*\n33\r*\n1\r*\n" }
+// { dg-output "1\r*\n1\r*\n1\r*\n" }
+
 #![feature(rustc_attrs)]
 
 #[rustc_builtin_macro]
@@ -6,6 +7,10 @@ macro_rules! include_bytes {
     () => {{}};
 }
 
+macro_rules! my_file {
+    () => {"include.txt"};
+}
+
 extern "C" {
     fn printf(s: *const i8, ...);
 }
@@ -17,32 +22,30 @@ fn print_int(value: i32) {
     }
 }
 
-fn main() -> i32 {
-    let bytes = include_bytes!("include.txt");
-
-    print_int(bytes[0] as i32);
-    print_int(bytes[14] as i32);
-
+fn check_bytes(bytes: &[u8; 16]) {
     let the_bytes = b"hello, include!\n";
 
-    let x = bytes[0] == the_bytes[0]
-        && bytes[1] == the_bytes[1]
-        && bytes[2] == the_bytes[2]
-        && bytes[3] == the_bytes[3]
-        && bytes[4] == the_bytes[4]
-        && bytes[5] == the_bytes[5]
-        && bytes[6] == the_bytes[6]
-        && bytes[7] == the_bytes[7]
-        && bytes[8] == the_bytes[8]
-        && bytes[9] == the_bytes[9]
-        && bytes[10] == the_bytes[10]
-        && bytes[11] == the_bytes[11]
-        && bytes[12] == the_bytes[12]
-        && bytes[13] == the_bytes[13]
-        && bytes[14] == the_bytes[14]
-        && bytes[15] == the_bytes[15];
+    let x = true;
+    let mut i = 0;
+
+    // X is true iff bytes == the_bytes
+    while i < 16 {
+        x = x && (bytes[i] == the_bytes[i]);
+        i += 1;
+    }
 
     print_int(x as i32);
+}
+
+fn main() -> i32 {
+    let bytes1: &'static [u8; 16] = include_bytes!("include.txt");
+    check_bytes(bytes1);
+
+    let bytes2: &'static [u8; 16] = include_bytes!(my_file!());
+    check_bytes(bytes2);
+
+    let bytes3 = include_bytes!(my_file!(),);
+    check_bytes(bytes3);
 
     0
 }
diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs 
b/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs
index a65639dcba1..b5454db2a5a 100644
--- a/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs
+++ b/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs
@@ -1,4 +1,4 @@
-// { dg-output "hello, include!\r*\n" }
+// { dg-output "hello, include!\r*\nhello, include!\r*\nhello, include!\r*\n" }
 #![feature(rustc_attrs)]
 
 #[rustc_builtin_macro]
@@ -6,6 +6,10 @@ macro_rules! include_str {
     () => {{}};
 }
 
+macro_rules! my_file {
+    () => {"include.txt"};
+}
+
 extern "C" {
     fn printf(fmt: *const i8, ...);
 }
@@ -22,7 +26,10 @@ fn print(s: &str) {
 fn main() -> i32 {
     // include_str! (and include_bytes!) allow for an optional trailing comma.
     let my_str = include_str!("include.txt",);
-
+    print(my_str);
+    let my_str = include_str!(my_file!());
+    print(my_str);
+    let my_str = include_str!(my_file!(),);
     print(my_str);
 
     0
-- 
2.45.2

Reply via email to