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