From: Pierre-Emmanuel Patry <[email protected]>
Some nightly features change the parser's behavior, it may accepts syntax
that should be rejected when the feature is missing. But the complete
list of enabled features can only be found once the parsing is complete.
We should therefore not emit any error at parse time and instead collect
a potential error and emit it later during the feature gating step.
gcc/rust/ChangeLog:
* checks/errors/feature/rust-feature-gate.cc (FeatureGate::check):
Check all parse time errors.
* checks/errors/feature/rust-feature-gate.h: Update function prototype
with parse time errors.
* parse/rust-parse-impl-attribute.hxx: Collect potential gating error
with non literal attribute values. Remove error emission.
* parse/rust-parse.h: Add a function to gather potential feature gating
errors as well as a getter for collected errors.
* rust-session-manager.cc (Session::compile_crate): Retrieve potential
feature gating errors and check them later during the feature gating
step.
* util/rust-attributes.cc (check_export_name_attribute): Change
attribute checking error emission to prevent errors with macro inputs.
gcc/testsuite/ChangeLog:
* rust/compile/doc_macro.rs: Enable feature to use a macro within an
attribute input.
* rust/compile/parse_time_feature_gate.rs: New test.
Signed-off-by: Pierre-Emmanuel Patry <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/855e7d78877ad6c4164e7058d5f3dbaf8c7c16bc
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4425
.../errors/feature/rust-feature-gate.cc | 6 +++-
.../checks/errors/feature/rust-feature-gate.h | 4 ++-
gcc/rust/parse/rust-parse-impl-attribute.hxx | 31 ++++++++---------
gcc/rust/parse/rust-parse.h | 20 +++++++++++
gcc/rust/rust-session-manager.cc | 3 +-
gcc/rust/util/rust-attributes.cc | 33 +++++++++++++++++--
gcc/testsuite/rust/compile/doc_macro.rs | 2 +-
.../rust/compile/parse_time_feature_gate.rs | 6 ++++
8 files changed, 83 insertions(+), 22 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/parse_time_feature_gate.rs
diff --git a/gcc/rust/checks/errors/feature/rust-feature-gate.cc
b/gcc/rust/checks/errors/feature/rust-feature-gate.cc
index 515b753a4..2c0ee08e4 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-gate.cc
+++ b/gcc/rust/checks/errors/feature/rust-feature-gate.cc
@@ -27,8 +27,12 @@
namespace Rust {
void
-FeatureGate::check (AST::Crate &crate)
+FeatureGate::check (
+ AST::Crate &crate,
+ std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors)
{
+ for (auto &pair : parsing_feature_gate_errors)
+ gate (pair.first, pair.second.locus, pair.second.message);
visit (crate);
}
diff --git a/gcc/rust/checks/errors/feature/rust-feature-gate.h
b/gcc/rust/checks/errors/feature/rust-feature-gate.h
index 120808339..33cb2758a 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-gate.h
+++ b/gcc/rust/checks/errors/feature/rust-feature-gate.h
@@ -32,7 +32,9 @@ public:
using AST::DefaultASTVisitor::visit;
- void check (AST::Crate &crate);
+ void check (
+ AST::Crate &crate,
+ std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors);
void visit (AST::Crate &crate) override;
void visit (AST::LifetimeParam &lifetime_param) override;
diff --git a/gcc/rust/parse/rust-parse-impl-attribute.hxx
b/gcc/rust/parse/rust-parse-impl-attribute.hxx
index 85fab52c9..5c7bd99bf 100644
--- a/gcc/rust/parse/rust-parse-impl-attribute.hxx
+++ b/gcc/rust/parse/rust-parse-impl-attribute.hxx
@@ -293,6 +293,16 @@ Parser<ManagedTokenSource>::parse_attr_input ()
t = lexer.peek_token ();
+ /* Ensure token is a "literal expression" (literally only a literal
+ * token of any type) */
+ if (!t->is_literal ())
+ {
+ Error error (
+ t->get_locus (),
+ "arbitrary expressions in key-value attributes are unstable");
+ collect_potential_gating_error (
+ Feature::Name::EXTENDED_KEY_VALUE_ATTRIBUTES, std::move (error));
+ }
// attempt to parse macro
// TODO: macros may/may not be allowed in attributes
// this is needed for "#[doc = include_str!(...)]"
@@ -308,20 +318,6 @@ Parser<ManagedTokenSource>::parse_attr_input ()
new AST::AttrInputMacro (std::move (invoke)));
}
- /* Ensure token is a "literal expression" (literally only a literal
- * token of any type) */
- if (!t->is_literal ())
- {
- Error error (
- t->get_locus (),
- "unknown token %qs in attribute body - literal expected",
- t->get_token_description ());
- add_error (std::move (error));
-
- skip_after_end_attribute ();
- return Parse::Error::AttrInput::make_malformed ();
- }
-
AST::Literal::LitType lit_type = AST::Literal::STRING;
// Crappy mapping of token type to literal type
switch (t->get_id ())
@@ -345,9 +341,14 @@ Parser<ManagedTokenSource>::parse_attr_input ()
lit_type = AST::Literal::RAW_STRING;
break;
case STRING_LITERAL:
- default:
lit_type = AST::Literal::STRING;
break; // TODO: raw string? don't eliminate it from lexer?
+ default:
+ rust_sorry_at (t->get_locus (),
+ "Unsupported attribute input, only literals and "
+ "macros are supported for now");
+ skip_after_end_attribute ();
+ return Parse::Error::AttrInput::make_malformed ();
}
// create actual LiteralExpr
diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h
index 7d632391c..07d08333b 100644
--- a/gcc/rust/parse/rust-parse.h
+++ b/gcc/rust/parse/rust-parse.h
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "rust-diagnostics.h"
#include "rust-parse-error.h"
#include "rust-parse-utils.h"
+#include "rust-feature.h"
#include "expected.h"
@@ -852,6 +853,17 @@ private:
void add_error (Error error) { error_table.push_back (std::move (error)); }
+ // We don't know the crate's valid feature set since we may not have parsed
+ // all feature declaration attributes yet, some features are not available
and
+ // we can't decide at parse time whether we should reject the syntax.
+ //
+ // To fix this we collect the feature gating errors now and will emit the
+ // errors later.
+ void collect_potential_gating_error (Feature::Name feature, Error error)
+ {
+ gating_errors.emplace_back (feature, error);
+ }
+
public:
// Construct parser with specified "managed" token source.
Parser (ManagedTokenSource &tokenSource) : lexer (tokenSource) {}
@@ -874,6 +886,12 @@ public:
// Get a reference to the list of errors encountered
std::vector<Error> &get_errors () { return error_table; }
+ std::vector<std::pair<Feature::Name, Error>> &
+ get_potential_feature_gate_errors ()
+ {
+ return gating_errors;
+ }
+
const ManagedTokenSource &get_token_source () const { return lexer; }
const_TokenPtr peek_current_token () { return lexer.peek_token (0); }
@@ -884,6 +902,8 @@ private:
ManagedTokenSource &lexer;
// The error list.
std::vector<Error> error_table;
+
+ std::vector<std::pair<Feature::Name, Error>> gating_errors;
// The names of inline modules while parsing.
std::vector<std::string> inline_module_stack;
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index cf3237ccd..a87f00780 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -601,6 +601,7 @@ Session::compile_crate (const char *filename)
// generate crate from parser
std::unique_ptr<AST::Crate> ast_crate = parser.parse_crate ();
+ auto &feature_gate_errors = parser.get_potential_feature_gate_errors ();
// handle crate name
handle_crate_name (filename, *ast_crate.get ());
@@ -712,7 +713,7 @@ Session::compile_crate (const char *filename)
if (last_step == CompileOptions::CompileStep::FeatureGating)
return;
- FeatureGate (parsed_crate_features).check (parsed_crate);
+ FeatureGate (parsed_crate_features).check (parsed_crate,
feature_gate_errors);
if (last_step == CompileOptions::CompileStep::NameResolution)
return;
diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc
index af6f5fdac..b3d607914 100644
--- a/gcc/rust/util/rust-attributes.cc
+++ b/gcc/rust/util/rust-attributes.cc
@@ -498,11 +498,38 @@ check_export_name_attribute (const AST::Attribute
&attribute)
return;
}
- if (!Attributes::extract_string_literal (attribute))
+ // We don't support the whole extended_key_value_attributes feature, we only
+ // support a subset for macros. We need to emit an error message when the
+ // attribute does not contain a macro or a string literal.
+ if (attribute.has_attr_input ())
{
- rust_error_at (attribute.get_locus (),
- "attribute must be a string literal");
+ auto &attr_input = attribute.get_attr_input ();
+ switch (attr_input.get_attr_input_type ())
+ {
+ case AST::AttrInput::AttrInputType::LITERAL:
+ {
+ auto &literal_expr
+ = static_cast<AST::AttrInputLiteral &> (attr_input)
+ .get_literal ();
+ auto lit_type = literal_expr.get_lit_type ();
+ switch (lit_type)
+ {
+ case AST::Literal::LitType::STRING:
+ case AST::Literal::LitType::RAW_STRING:
+ case AST::Literal::LitType::BYTE_STRING:
+ return;
+ default:
+ break;
+ }
+ break;
+ }
+ case AST::AttrInput::AttrInputType::MACRO:
+ return;
+ default:
+ break;
+ }
}
+ rust_error_at (attribute.get_locus (), "attribute must be a string literal");
}
static void
diff --git a/gcc/testsuite/rust/compile/doc_macro.rs
b/gcc/testsuite/rust/compile/doc_macro.rs
index f71bd7ca0..179455ddf 100644
--- a/gcc/testsuite/rust/compile/doc_macro.rs
+++ b/gcc/testsuite/rust/compile/doc_macro.rs
@@ -1,4 +1,4 @@
#![feature(no_core)]
#![no_core]
-
+#![feature(extended_key_value_attributes)]
#![doc = concat!("AB")]
diff --git a/gcc/testsuite/rust/compile/parse_time_feature_gate.rs
b/gcc/testsuite/rust/compile/parse_time_feature_gate.rs
new file mode 100644
index 000000000..238b2cfd5
--- /dev/null
+++ b/gcc/testsuite/rust/compile/parse_time_feature_gate.rs
@@ -0,0 +1,6 @@
+#![feature(no_core)]
+#![no_core]
+
+// { dg-error "arbitrary expressions in key-value attributes are unstable" ""
{ target *-*-* } .+1 }
+#[export_name = concat!(stringify!(non), stringify!(literal))]
+pub extern "C" fn attribute_test_function() {}
--
2.53.0