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)
{
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 ())
}
}
+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
check_lang_item_attribute (function.get_outer_attrs ());
+ note_stability_attribute (function.get_outer_attrs ());
+
AST::DefaultASTVisitor::visit (function);
}