// Copyright (C) 2020-2025 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "rust-feature-gate.h" #include "rust-abi.h" #include "rust-attribute-values.h" #include "rust-ast-visitor.h" #include "rust-feature.h" namespace Rust { void FeatureGate::check (AST::Crate &crate) { visit (crate); } void FeatureGate::visit (AST::Crate &crate) { valid_features.clear (); for (const auto &attr : crate.inner_attrs) { if (attr.get_path ().as_string () == "feature") { const auto &attr_input = attr.get_attr_input (); auto type = attr_input.get_attr_input_type (); if (type == AST::AttrInput::AttrInputType::TOKEN_TREE) { const auto &option = static_cast ( attr.get_attr_input ()); std::unique_ptr meta_item ( option.parse_to_meta_item ()); 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); } else rust_error_at (item->get_locus (), ErrorCode::E0635, "unknown feature %qs", name_str.c_str ()); } } } } AST::DefaultASTVisitor::visit (crate); } void FeatureGate::gate (Feature::Name name, location_t loc, const std::string &error_msg) { if (!valid_features.count (name)) { auto feature = Feature::create (name); auto issue = feature.issue (); if (issue > 0) { const char *fmt_str = "%s. see issue %u " " for more " "information. add `#![feature(%s)]` to the crate attributes to " "enable."; rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (), issue, issue, feature.as_string ().c_str ()); } else { const char *fmt_str = "%s. add `#![feature(%s)]` to the crate attributes to enable."; rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (), feature.as_string ().c_str ()); } } } void FeatureGate::visit (AST::ExternBlock &block) { if (block.has_abi ()) { const auto abi = block.get_abi (); if (get_abi_from_string (abi) == ABI::INTRINSIC) gate (Feature::Name::INTRINSICS, block.get_locus (), "intrinsics are subject to change"); } AST::DefaultASTVisitor::visit (block); } void FeatureGate::check_rustc_attri (const std::vector &attributes) { for (const AST::Attribute &attr : attributes) { auto name = attr.get_path ().as_string (); if (name.rfind ("rustc_", 0) == 0) { gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (), "internal implementation detail"); } } } void FeatureGate::check_may_dangle_attribute ( const std::vector &attributes) { for (const AST::Attribute &attr : attributes) { if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE) gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (), "`may_dangle` has unstable semantics and may be removed in the " "future"); } } void FeatureGate::visit (AST::MacroRulesDefinition &rules_def) { check_rustc_attri (rules_def.get_outer_attrs ()); } void FeatureGate::visit (AST::Function &function) { if (!function.is_external ()) check_rustc_attri (function.get_outer_attrs ()); AST::DefaultASTVisitor::visit (function); } void FeatureGate::visit (AST::ExternalTypeItem &item) { // TODO(mxlol233): The gating needs a complete visiting chain to activate // `AST::ExternalTypeItem`. gate (Feature::Name::EXTERN_TYPES, item.get_locus (), "extern types are experimental"); } void FeatureGate::visit (AST::TraitImpl &impl) { if (impl.is_exclam ()) gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (), "negative_impls are not yet implemented"); AST::DefaultASTVisitor::visit (impl); }; void FeatureGate::visit (AST::BoxExpr &expr) { gate ( Feature::Name::BOX_SYNTAX, expr.get_locus (), "box expression syntax is experimental; you can call `Box::new` instead"); AST::DefaultASTVisitor::visit (expr); } void FeatureGate::visit (AST::LifetimeParam &lifetime_param) { check_may_dangle_attribute (lifetime_param.get_outer_attrs ()); AST::DefaultASTVisitor::visit (lifetime_param); } void FeatureGate::visit (AST::ConstGenericParam &const_param) { check_may_dangle_attribute (const_param.get_outer_attrs ()); AST::DefaultASTVisitor::visit (const_param); } void FeatureGate::visit (AST::TypeParam ¶m) { check_may_dangle_attribute (param.get_outer_attrs ()); AST::DefaultASTVisitor::visit (param); } void FeatureGate::visit (AST::BorrowExpr &expr) { if (expr.is_raw_borrow ()) gate (Feature::Name::RAW_REF_OP, expr.get_locus (), "raw address of syntax is experimental"); } void FeatureGate::visit (AST::RangePattern &pattern) { if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED) gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (), "exclusive range pattern syntax is experimental"); } } // namespace Rust