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

Reply via email to