From: Pierre-Emmanuel Patry <[email protected]>
We use multiple parsers and can't retrieve all early feature gating
errors within the usual gating pass. This commit introduces a store to
collect all early gating errors in the same place from multiple parsers.
The features are then checked as usual within the feature gate checker.
gcc/rust/ChangeLog:
* checks/errors/feature/rust-feature-gate.cc
(EarlyFeatureGateStore::get):
Add function to retrieve singleton instance.
(EarlyFeatureGateStore::add): New function to add an error and the
corresponding feature in the store.
(EarlyFeatureGateStore::get_error): Add new function to retrieve the
oldest error.
(FeatureGate::check): Update the function to retrieve the errors from
the store instead of getting it from the parameters.
* checks/errors/feature/rust-feature-gate.h (class
EarlyFeatureGateStore):
Add a new class to collect all early feature gating errors.
* parse/rust-parse.h: Use store instead of keeping the errors within
the parser instance.
* rust-session-manager.cc (Session::compile_crate): Remove old early
error collection from the main parser.
* rust-system.h: Include queue header.
gcc/testsuite/ChangeLog:
* rust/compile/issue-3661.rs: Add key_value_attribute feature to
prevent error on stringify macro.
* rust/compile/early_feature_gate_in_macro.rs: Add test to highlight
early feature gate error collection within macros.
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/86a5d264f3207ba8f8600d307cacbef850fa4748
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 | 33 ++++++++++++++++---
.../checks/errors/feature/rust-feature-gate.h | 22 +++++++++++--
gcc/rust/parse/rust-parse.h | 9 ++---
gcc/rust/rust-session-manager.cc | 3 +-
gcc/rust/rust-system.h | 1 +
.../compile/early_feature_gate_in_macro.rs | 23 +++++++++++++
gcc/testsuite/rust/compile/issue-3661.rs | 1 +
7 files changed, 75 insertions(+), 17 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs
diff --git a/gcc/rust/checks/errors/feature/rust-feature-gate.cc
b/gcc/rust/checks/errors/feature/rust-feature-gate.cc
index 2c0ee08e4..2164453ec 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-gate.cc
+++ b/gcc/rust/checks/errors/feature/rust-feature-gate.cc
@@ -26,13 +26,36 @@
namespace Rust {
+EarlyFeatureGateStore &
+EarlyFeatureGateStore::get ()
+{
+ static EarlyFeatureGateStore instance{};
+ return instance;
+}
+
+void
+EarlyFeatureGateStore::add (Feature::Name name, Error error)
+{
+ potential_errors.emplace (name, error);
+}
+
+std::pair<Feature::Name, Error>
+EarlyFeatureGateStore::get_error ()
+{
+ auto ret = potential_errors.front ();
+ potential_errors.pop ();
+ return ret;
+}
+
void
-FeatureGate::check (
- AST::Crate &crate,
- std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors)
+FeatureGate::check (AST::Crate &crate)
{
- for (auto &pair : parsing_feature_gate_errors)
- gate (pair.first, pair.second.locus, pair.second.message);
+ auto &store = EarlyFeatureGateStore::get ();
+ while (store.has_error ())
+ {
+ auto pair = store.get_error ();
+ 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 33cb2758a..38a19d09e 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-gate.h
+++ b/gcc/rust/checks/errors/feature/rust-feature-gate.h
@@ -25,6 +25,24 @@
namespace Rust {
+/**
+ * We don't know the whole set of valid features until a crate has been parsed.
+ * We're collecting in this store all the potential feature errors and check
+ * them later.
+ */
+class EarlyFeatureGateStore
+{
+ std::queue<std::pair<Feature::Name, Error>> potential_errors;
+
+public:
+ static EarlyFeatureGateStore &get ();
+ void add (Feature::Name name, Error error);
+
+ bool has_error () { return !potential_errors.empty (); }
+
+ std::pair<Feature::Name, Error> get_error ();
+};
+
class FeatureGate : public AST::DefaultASTVisitor
{
public:
@@ -32,9 +50,7 @@ public:
using AST::DefaultASTVisitor::visit;
- void check (
- AST::Crate &crate,
- std::vector<std::pair<Feature::Name, Error>> &parsing_feature_gate_errors);
+ void check (AST::Crate &crate);
void visit (AST::Crate &crate) override;
void visit (AST::LifetimeParam &lifetime_param) override;
diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h
index 07d08333b..70d3a18a8 100644
--- a/gcc/rust/parse/rust-parse.h
+++ b/gcc/rust/parse/rust-parse.h
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "rust-parse-error.h"
#include "rust-parse-utils.h"
#include "rust-feature.h"
+#include "rust-feature-gate.h"
#include "expected.h"
@@ -853,15 +854,9 @@ 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);
+ EarlyFeatureGateStore::get ().add (feature, error);
}
public:
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index a87f00780..cf3237ccd 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -601,7 +601,6 @@ 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 ());
@@ -713,7 +712,7 @@ Session::compile_crate (const char *filename)
if (last_step == CompileOptions::CompileStep::FeatureGating)
return;
- FeatureGate (parsed_crate_features).check (parsed_crate,
feature_gate_errors);
+ FeatureGate (parsed_crate_features).check (parsed_crate);
if (last_step == CompileOptions::CompileStep::NameResolution)
return;
diff --git a/gcc/rust/rust-system.h b/gcc/rust/rust-system.h
index 6d3fe2e2a..b47fa265c 100644
--- a/gcc/rust/rust-system.h
+++ b/gcc/rust/rust-system.h
@@ -36,6 +36,7 @@
#include <map>
#include <set>
#include <vector>
+#include <queue>
#include <stack>
#include <sstream>
#include <string>
diff --git a/gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs
b/gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs
new file mode 100644
index 000000000..f76577362
--- /dev/null
+++ b/gcc/testsuite/rust/compile/early_feature_gate_in_macro.rs
@@ -0,0 +1,23 @@
+#![feature(rustc_attrs)]
+#![feature(lang_items)]
+#![feature(no_core)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! concat {
+ () => {{}};
+}
+
+macro_rules! prefix_symbol(
+ ($prefix : tt, { $($ident: ident, )* }) => {
+ $(
+ // { dg-error "arbitrary expressions in key-value attributes are
unstable" "" { target *-*-* } .+1 }
+ #[export_name = concat!(stringify!($prefix), stringify!($ident))]
+ pub extern "C" fn $ident() {
+ }
+ )*
+});
+
+prefix_symbol!(a,{
+ __func0,
+});
diff --git a/gcc/testsuite/rust/compile/issue-3661.rs
b/gcc/testsuite/rust/compile/issue-3661.rs
index 6c1a1a52f..7cb7c6add 100644
--- a/gcc/testsuite/rust/compile/issue-3661.rs
+++ b/gcc/testsuite/rust/compile/issue-3661.rs
@@ -1,5 +1,6 @@
#![feature(no_core)]
#![no_core]
+#![feature(extended_key_value_attributes)]
pub macro m($inner_str:expr) {
#[m = $inner_str]
--
2.53.0