From: Owen Avery <[email protected]>

This fixes a false positive with undefined features, improves the
implementation of Feature::as_name, and configures the testsuite to
check further stages of libcore compilation.

gcc/rust/ChangeLog:

        * ast/rust-macro.h (MetaNameValueStr::get_name): New function.
        (MetaNameValueStr::get_value): Likewise.
        * checks/errors/feature/rust-feature-gate.cc
        (FeatureGate::visit): Tweak unknown feature detection.
        (FeatureGate::gate): Handle field rename.
        (FeatureGate::note_stability_attribute): New function
        definition.
        * checks/errors/feature/rust-feature-gate.h
        (FeatureGate::note_stability_attribute): New function
        declaration.
        (FeatureGate::Stability): New enum class.
        (FeatureGate::valid_features): Rename field to...
        (FeatureGate::valid_lang_features): ...here.
        (FeatureGate::valid_lib_features): New field.
        (FeatureGate::defined_lib_features): Likewise.
        * checks/errors/feature/rust-feature.cc (Feature::as_name):
        Improve implementation.

gcc/testsuite/ChangeLog:

        * rust/core/core.exp: Change -frust-compile-until=astvalidation
        to -frust-compile-until=nameresolution.

Signed-off-by: Owen Avery <[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/12adbc3130dd2352e628a3ee992645d05b3ff046

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4319

 gcc/rust/ast/rust-macro.h                     |  4 +
 .../errors/feature/rust-feature-gate.cc       | 91 +++++++++++++++++--
 .../checks/errors/feature/rust-feature-gate.h | 13 ++-
 .../checks/errors/feature/rust-feature.cc     |  9 +-
 gcc/testsuite/rust/core/core.exp              |  2 +-
 5 files changed, 103 insertions(+), 16 deletions(-)

diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h
index 416507501..71de8f022 100644
--- a/gcc/rust/ast/rust-macro.h
+++ b/gcc/rust/ast/rust-macro.h
@@ -993,6 +993,10 @@ public:
     return ident.as_string () + " = \"" + str + "\"";
   }
 
+  const Identifier &get_name () const { return ident; }
+
+  const std::string &get_value () const { return str; }
+
   void accept_vis (ASTVisitor &vis) override;
 
   // HACK: used to simplify parsing - creates a copy of this
diff --git a/gcc/rust/checks/errors/feature/rust-feature-gate.cc 
b/gcc/rust/checks/errors/feature/rust-feature-gate.cc
index 448fa18f2..9df822b7e 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-gate.cc
+++ b/gcc/rust/checks/errors/feature/rust-feature-gate.cc
@@ -34,7 +34,10 @@ FeatureGate::check (AST::Crate &crate)
 void
 FeatureGate::visit (AST::Crate &crate)
 {
-  valid_features.clear ();
+  valid_lang_features.clear ();
+  valid_lib_features.clear ();
+
+  // avoid clearing defined features (?)
 
   for (const auto &attr : crate.inner_attrs)
     {
@@ -58,29 +61,45 @@ FeatureGate::visit (AST::Crate &crate)
              for (const auto &item : meta_item->get_items ())
                {
                  const auto &name_str = item->as_string ();
-                 auto tname = Feature::as_name (name_str);
-                 if (tname.has_value ())
-                   {
-                     auto name = tname.value ();
-                     valid_features.insert (name);
-                   }
 
+                 // TODO: detect duplicates
+                 if (auto tname = Feature::as_name (name_str))
+                   valid_lang_features.insert (tname.value ());
                  else
-                   rust_error_at (item->get_locus (), ErrorCode::E0635,
-                                  "unknown feature %qs", name_str.c_str ());
+                   valid_lib_features.emplace (name_str, item->get_locus ());
                }
            }
        }
     }
 
   AST::DefaultASTVisitor::visit (crate);
+
+  for (auto &ent : valid_lib_features)
+    {
+      const std::string &feature = ent.first;
+      location_t locus = ent.second;
+
+      // rustc treats these as valid,
+      // but apparently has special handling for them
+      if (feature == "libc" || feature == "test")
+       continue;
+
+      if (defined_lib_features.find (feature) != defined_lib_features.end ())
+       {
+         // TODO: emit warning if stable
+         continue;
+       }
+
+      rust_error_at (locus, ErrorCode::E0635, "unknown feature %qs",
+                    feature.c_str ());
+    }
 }
 
 void
 FeatureGate::gate (Feature::Name name, location_t loc,
                   const std::string &error_msg)
 {
-  if (!valid_features.count (name))
+  if (!valid_lang_features.count (name))
     {
       auto &feature = Feature::lookup (name);
       if (auto issue = feature.issue ())
@@ -164,10 +183,60 @@ FeatureGate::check_lang_item_attribute (
     }
 }
 
+void
+FeatureGate::note_stability_attribute (
+  const std::vector<AST::Attribute> &attributes)
+{
+  for (const AST::Attribute &attr : attributes)
+    {
+      std::string attr_name = attr.get_path ().as_string ();
+
+      Stability stability;
+
+      if (attr_name == Values::Attributes::STABLE)
+       stability = Stability::STABLE;
+      else if (attr_name == Values::Attributes::UNSTABLE)
+       stability = Stability::UNSTABLE;
+      else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
+       stability = Stability::STABLE;
+      else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
+       stability = Stability::UNSTABLE;
+      else
+       continue;
+
+      if (attr.empty_input ())
+       // TODO: error?
+       continue;
+
+      auto &attr_input = attr.get_attr_input ();
+      if (attr_input.get_attr_input_type ()
+         != AST::AttrInput::AttrInputType::TOKEN_TREE)
+       // TODO: error?
+       continue;
+
+      std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
+       static_cast<const AST::DelimTokenTree &> (attr_input)
+         .parse_to_meta_item ());
+
+      for (auto &item : meta_item->get_items ())
+       {
+         // TODO: more thorough error checking?
+         // ~only the standard libraries should ever exercise this
+         if (item->is_key_value_pair ())
+           {
+             auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
+             if (pair.get_name ().as_string () == "feature")
+               defined_lib_features.emplace (pair.get_value (), stability);
+           }
+       }
+    }
+}
+
 void
 FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
 {
   check_rustc_attri (rules_def.get_outer_attrs ());
+  note_stability_attribute (rules_def.get_outer_attrs ());
 }
 
 void
@@ -178,6 +247,8 @@ FeatureGate::visit (AST::Function &function)
 
   check_lang_item_attribute (function.get_outer_attrs ());
 
+  note_stability_attribute (function.get_outer_attrs ());
+
   AST::DefaultASTVisitor::visit (function);
 }
 
diff --git a/gcc/rust/checks/errors/feature/rust-feature-gate.h 
b/gcc/rust/checks/errors/feature/rust-feature-gate.h
index c8ab66b75..8ff491c10 100644
--- a/gcc/rust/checks/errors/feature/rust-feature-gate.h
+++ b/gcc/rust/checks/errors/feature/rust-feature-gate.h
@@ -59,7 +59,18 @@ private:
   check_may_dangle_attribute (const std::vector<AST::Attribute> &attributes);
   void
   check_lang_item_attribute (const std::vector<AST::Attribute> &attributes);
-  std::set<Feature::Name> valid_features;
+  void note_stability_attribute (const std::vector<AST::Attribute> 
&attributes);
+
+  std::set<Feature::Name> valid_lang_features;
+  std::map<std::string, location_t> valid_lib_features;
+
+  enum class Stability
+  {
+    STABLE,
+    UNSTABLE,
+  };
+
+  std::map<std::string, Stability> defined_lib_features;
 };
 } // namespace Rust
 #endif
diff --git a/gcc/rust/checks/errors/feature/rust-feature.cc 
b/gcc/rust/checks/errors/feature/rust-feature.cc
index 7fc5cb047..1a967aa70 100644
--- a/gcc/rust/checks/errors/feature/rust-feature.cc
+++ b/gcc/rust/checks/errors/feature/rust-feature.cc
@@ -77,10 +77,11 @@ const std::map<std::string, Feature::Name> 
Feature::name_hash_map = {
 tl::optional<Feature::Name>
 Feature::as_name (const std::string &name)
 {
-  if (Feature::name_hash_map.count (name))
-    return Feature::name_hash_map.at (name);
-
-  return tl::nullopt;
+  auto it = Feature::name_hash_map.find (name);
+  if (it == Feature::name_hash_map.end ())
+    return tl::nullopt;
+  else
+    return it->second;
 }
 
 tl::optional<std::reference_wrapper<const Feature>>
diff --git a/gcc/testsuite/rust/core/core.exp b/gcc/testsuite/rust/core/core.exp
index 330c6d5ba..45bdbb599 100644
--- a/gcc/testsuite/rust/core/core.exp
+++ b/gcc/testsuite/rust/core/core.exp
@@ -30,7 +30,7 @@ set saved-dg-do-what-default ${dg-do-what-default}
 set dg-do-what-default "compile"
 set individual_timeout 600
 dg-additional-files [lsort [glob -nocomplain 
$srcdir/../../libgrust/rustc-lib/*]]
-dg-runtest $srcdir/../../libgrust/rustc-lib/core/src/lib.rs 
"-frust-edition=2018 -frust-crate=core -frust-compile-until=astvalidation -w" ""
+dg-runtest $srcdir/../../libgrust/rustc-lib/core/src/lib.rs 
"-frust-edition=2018 -frust-crate=core -frust-compile-until=nameresolution -w" 
""
 set dg-do-what-default ${saved-dg-do-what-default}
 
 # All done.

base-commit: 13dafe56a3d167b9900c985e5d1cc34d67c58de0
-- 
2.51.2

Reply via email to