From: Owen Avery Date: Sat, 29 Nov 2025 23:20:01 +0000 (-0500) Subject: gccrs: Improve feature handling X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=317840fe20b694ce49af371f673cd6ead9daa822;p=thirdparty%2Fgcc.git gccrs: Improve feature handling 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 --- diff --git a/gcc/rust/ast/rust-macro.h b/gcc/rust/ast/rust-macro.h index 416507501ac..71de8f022d2 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 448fa18f21d..9df822b7e1c 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 &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 meta_item ( + static_cast (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 (*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 c8ab66b753d..8ff491c108e 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 &attributes); void check_lang_item_attribute (const std::vector &attributes); - std::set valid_features; + void note_stability_attribute (const std::vector &attributes); + + std::set valid_lang_features; + std::map valid_lib_features; + + enum class Stability + { + STABLE, + UNSTABLE, + }; + + std::map 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 7fc5cb04797..1a967aa70a9 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 Feature::name_hash_map = { tl::optional 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> diff --git a/gcc/testsuite/rust/core/core.exp b/gcc/testsuite/rust/core/core.exp index 330c6d5ba5b..45bdbb59959 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.