From: Pierre-Emmanuel Patry <[email protected]>

It is often required to inject some inner attributes to a crate from the
CLI. It has been required recently for fuzzing the compiler easily.

gcc/rust/ChangeLog:

        * ast/rust-ast.cc (Crate::inject_inner_attribute): Add member function
        to inject an inner attribute.
        * ast/rust-ast.h: Add function prototype.
        * lang.opt: Add frust-crate-attr argument to the compiler CLI.
        * rust-lang.cc: Remove unused attribute on  option handler.
        * rust-session-manager.cc (Session::handle_crate_name): Collect CLI
        additional inner attributes.
        (Session::compile_crate): Parse the additional inner attributes and
        inject them.
        * rust-session-manager.h (struct CompileOptions): Add collection of
        additional inner attributes.

gcc/testsuite/ChangeLog:

        * rust/compile/cli_inner_attribute_injection.rs: New test.

Signed-off-by: Pierre-Emmanuel Patry <[email protected]>
---
 gcc/rust/ast/rust-ast.cc                      |  6 +++
 gcc/rust/ast/rust-ast.h                       |  1 +
 gcc/rust/lang.opt                             |  4 ++
 gcc/rust/rust-lang.cc                         |  3 +-
 gcc/rust/rust-session-manager.cc              | 43 ++++++++++++++++++-
 gcc/rust/rust-session-manager.h               | 18 ++++++++
 .../compile/cli_inner_attribute_injection.rs  |  2 +
 7 files changed, 74 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/cli_inner_attribute_injection.rs

diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc
index d9a383675cf..004e2760372 100644
--- a/gcc/rust/ast/rust-ast.cc
+++ b/gcc/rust/ast/rust-ast.cc
@@ -243,6 +243,12 @@ Crate::inject_extern_crate (std::string name)
                      {}, UNKNOWN_LOCATION)));
 }
 
+void
+Crate::inject_inner_attribute (Attribute attribute)
+{
+  inner_attrs.push_back (attribute);
+}
+
 std::string
 Attribute::as_string () const
 {
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index 350eb2afdb1..b82a8cbd7a7 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -2123,6 +2123,7 @@ public:
   }
 
   void inject_extern_crate (std::string name);
+  void inject_inner_attribute (Attribute attribute);
 
   NodeId get_node_id () const { return node_id; }
   const std::vector<Attribute> &get_inner_attrs () const { return inner_attrs; 
}
diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt
index 270a57c04ea..aa8e9b1b42e 100644
--- a/gcc/rust/lang.opt
+++ b/gcc/rust/lang.opt
@@ -62,6 +62,10 @@ frust-crate=
 Rust Joined RejectNegative
 -frust-crate=<name>             Set the crate name for the compilation.
 
+frust-crate-attr=
+Rust Joined RejectNegative
+-frust-crate-attr=<attr>        Inject an attribute within the current crate.
+
 frust-extern=
 Rust RejectNegative Joined
 -frust-extern=              Specify where an external library is located.
diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc
index e83bcd72a5d..dde3ef204ce 100644
--- a/gcc/rust/rust-lang.cc
+++ b/gcc/rust/rust-lang.cc
@@ -269,8 +269,7 @@ grs_langhook_getdecls (void)
 static bool
 grs_langhook_handle_option (
   size_t scode, const char *arg, HOST_WIDE_INT value, int kind 
ATTRIBUTE_UNUSED,
-  location_t loc ATTRIBUTE_UNUSED,
-  const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+  location_t loc, const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
 {
   // Convert integer code to lang.opt enum codes with names.
   enum opt_code code = (enum opt_code) scode;
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 97300e4a17f..0c88e894ef0 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -208,7 +208,7 @@ Session::init_options ()
 bool
 Session::handle_option (
   enum opt_code code, const char *arg, HOST_WIDE_INT value ATTRIBUTE_UNUSED,
-  int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED,
+  int kind ATTRIBUTE_UNUSED, location_t loc,
   const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
 {
   // used to store whether results of various stuff are successful
@@ -252,6 +252,12 @@ Session::handle_option (
        ret = false;
       break;
 
+    case OPT_frust_crate_attr_:
+      if (arg != nullptr)
+       {
+         options.addional_attributes.emplace_back (arg, loc);
+       }
+      break;
     case OPT_frust_dump_:
       // enable dump and return whether this was successful
       if (arg != nullptr)
@@ -536,6 +542,36 @@ Session::handle_crate_name (const char *filename,
   mappings.set_current_crate (crate_num);
 }
 
+/** Parse additional attributes injected from the command line
+ *
+ */
+AST::AttrVec
+parse_cli_attributes (
+  std::vector<CompileOptions::CliAttributeContent> attributes)
+{
+  AST::AttrVec result;
+  result.reserve (attributes.size ());
+
+  for (auto attribute : attributes)
+    {
+      Session::get_instance ().linemap->start_file ("cli", 1);
+      Lexer lex (attribute.content, Session::get_instance ().linemap);
+      Parser<Lexer> parser (lex);
+
+      if (auto attr_body = parser.parse_attribute_body ())
+       {
+         auto body = std::move (attr_body.value ());
+         result.push_back (AST::Attribute (std::move (body.path),
+                                           std::move (body.input), body.locus,
+                                           true));
+       }
+
+      for (auto error : parser.get_errors ())
+       error.emit ();
+    }
+  return result;
+}
+
 // Parses a single file with filename filename.
 void
 Session::compile_crate (const char *filename)
@@ -587,6 +623,8 @@ Session::compile_crate (const char *filename)
       dump_lex_opt = dump_lex_stream;
     }
 
+  auto cli_attributes = parse_cli_attributes (options.addional_attributes);
+
   Lexer lex (filename, std::move (file_wrap), linemap, dump_lex_opt);
 
   if (!lex.input_source_is_valid_utf8 ())
@@ -628,6 +666,9 @@ Session::compile_crate (const char *filename)
   AST::Crate &parsed_crate
     = mappings.insert_ast_crate (std::move (ast_crate), current_crate);
 
+  for (auto attribute : cli_attributes)
+    parsed_crate.inject_inner_attribute (attribute);
+
   /* basic pipeline:
    *  - lex
    *  - parse
diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h
index 3a0d7f064ab..4e30ac6580e 100644
--- a/gcc/rust/rust-session-manager.h
+++ b/gcc/rust/rust-session-manager.h
@@ -242,6 +242,24 @@ struct CompileOptions
   bool debug_assertions = false;
   std::string metadata_output_path;
 
+  /** Structure containing additional attributes to be injected within the
+   * compiled crate from the command line instead of the source code.
+   *
+   * To make things a bit easier with rustc, we're trying to use the same
+   * format accepted by -Zcrate-attr. This means the CLI accepts the text
+   * content of the attribute and not text of the whole attribute itself.
+   */
+  struct CliAttributeContent
+  {
+    CliAttributeContent (std::string content, location_t locus)
+      : content (content), locus (locus)
+    {}
+    /* Content of the attribute*/
+    std::string content;
+    location_t locus;
+  };
+  std::vector<CliAttributeContent> addional_attributes;
+
   enum class Edition
   {
     E2015 = 0,
diff --git a/gcc/testsuite/rust/compile/cli_inner_attribute_injection.rs 
b/gcc/testsuite/rust/compile/cli_inner_attribute_injection.rs
new file mode 100644
index 00000000000..fda695d4b0f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/cli_inner_attribute_injection.rs
@@ -0,0 +1,2 @@
+// { dg-additional-options "-frust-crate-attr=feature(no_core)" }
+#![no_core]
-- 
2.50.1

Reply via email to