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]>
---
.../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 515b753a43b..2c0ee08e4dd 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 120808339f0..33cb2758ae8 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 85fab52c997..5c7bd99bf3e 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 7d632391c7a..07d08333b7f 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 cf3237ccd71..a87f0078047 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 af6f5fdac08..b3d60791432 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 f71bd7ca04c..179455ddf95 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 00000000000..238b2cfd5c7
--- /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.50.1