LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors/feature - rust-feature-gate.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 97.7 % 177 173
Test Date: 2026-04-20 14:57:17 Functions: 100.0 % 25 25
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-feature-gate.h"
      20              : #include "rust-abi.h"
      21              : #include "rust-attribute-values.h"
      22              : #include "rust-attributes.h"
      23              : #include "rust-ast-visitor.h"
      24              : #include "rust-feature.h"
      25              : #include "rust-ast-full.h"
      26              : #include "rust-feature-store.h"
      27              : 
      28              : namespace Rust {
      29              : 
      30              : void
      31         4683 : FeatureGate::check (AST::Crate &crate)
      32              : {
      33         4683 :   auto &store = Features::EarlyFeatureGateStore::get ();
      34         9370 :   while (store.has_error ())
      35              :     {
      36            4 :       auto pair = store.get_error ();
      37            4 :       gate (pair.first, pair.second.locus, pair.second.message);
      38            4 :     }
      39         4683 :   visit (crate);
      40         4683 : }
      41              : 
      42              : void
      43         4683 : FeatureGate::visit (AST::Crate &crate)
      44              : {
      45         4683 :   AST::DefaultASTVisitor::visit (crate);
      46              : 
      47         4688 :   for (auto &ent : features.valid_lib_features)
      48              :     {
      49            5 :       const std::string &feature = ent.first;
      50            5 :       location_t locus = ent.second;
      51              : 
      52              :       // rustc treats these as valid,
      53              :       // but apparently has special handling for them
      54            5 :       if (feature == "libc" || feature == "test")
      55            0 :         continue;
      56              : 
      57            5 :       if (defined_lib_features.find (feature) != defined_lib_features.end ())
      58              :         {
      59              :           // TODO: emit warning if stable
      60            0 :           continue;
      61              :         }
      62              : 
      63            5 :       rust_error_at (locus, ErrorCode::E0635, "unknown feature %qs",
      64              :                      feature.c_str ());
      65              :     }
      66        16544 :   for (const auto &attribute : crate.inner_attrs)
      67              :     {
      68        11861 :       check_no_core_attribute (attribute);
      69              : 
      70        11861 :       if (attribute.get_path ().as_string ()
      71        11861 :           == Values::Attributes::COMPILER_BUILTINS)
      72            1 :         gate (Feature::Name::COMPILER_BUILTINS, attribute.get_locus (),
      73            2 :               "the #[compiler_builtins] attribute is used to identify the "
      74              :               "compiler_builtins crate which contains compiler-rt intrinsics "
      75              :               "and will never be stable");
      76              :     }
      77         4683 : }
      78              : 
      79              : void
      80         8833 : FeatureGate::gate (Feature::Name name, location_t loc,
      81              :                    const std::string &error_msg)
      82              : {
      83         8833 :   if (!features.valid_lang_features.count (name))
      84              :     {
      85           17 :       auto &feature = Feature::lookup (name);
      86           17 :       if (auto issue = feature.issue ())
      87              :         {
      88           10 :           auto issue_number = issue.value ();
      89           10 :           const char *fmt_str
      90              :             = "%s. see issue %u "
      91              :               "<https://github.com/rust-lang/rust/issues/%u> for more "
      92              :               "information. add `#![feature(%s)]` to the crate attributes to "
      93              :               "enable.";
      94           10 :           rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
      95              :                          issue_number, issue_number,
      96           10 :                          feature.as_string ().c_str ());
      97              :         }
      98              :       else
      99              :         {
     100            7 :           const char *fmt_str
     101              :             = "%s. add `#![feature(%s)]` to the crate attributes to enable.";
     102            7 :           rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
     103            7 :                          feature.as_string ().c_str ());
     104              :         }
     105              :     }
     106         8833 : }
     107              : 
     108              : void
     109         1617 : FeatureGate::visit (AST::ExternBlock &block)
     110              : {
     111         1617 :   if (block.has_abi ())
     112              :     {
     113         1617 :       const auto abi = block.get_abi ();
     114              : 
     115         1617 :       if (get_abi_from_string (abi) == ABI::INTRINSIC)
     116          555 :         gate (Feature::Name::INTRINSICS, block.get_locus (),
     117         1110 :               "intrinsics are subject to change");
     118         1617 :     }
     119         1617 :   AST::DefaultASTVisitor::visit (block);
     120         1617 : }
     121              : 
     122              : void
     123        11861 : FeatureGate::check_no_core_attribute (const AST::Attribute &attribute)
     124              : {
     125        11861 :   if (attribute.get_path ().as_string () == Values::Attributes::NO_CORE)
     126         4684 :     gate (Feature::Name::NO_CORE, attribute.get_locus (),
     127         9368 :           "no_core is experimental");
     128        11861 : }
     129              : 
     130              : void
     131        17223 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
     132              : {
     133        27322 :   for (const AST::Attribute &attr : attributes)
     134              :     {
     135        10099 :       auto name = attr.get_path ().as_string ();
     136        10099 :       if (name.rfind ("rustc_", 0) == 0)
     137              :         {
     138          269 :           gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
     139          538 :                 "internal implementation detail");
     140              :         }
     141        10099 :     }
     142        17223 : }
     143              : 
     144              : void
     145         8813 : FeatureGate::check_may_dangle_attribute (
     146              :   const std::vector<AST::Attribute> &attributes)
     147              : {
     148         8818 :   for (const AST::Attribute &attr : attributes)
     149              :     {
     150            5 :       if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
     151            5 :         gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
     152           10 :               "`may_dangle` has unstable semantics and may be removed in the "
     153              :               "future");
     154              :     }
     155         8813 : }
     156              : 
     157              : void
     158        25996 : FeatureGate::check_lang_item_attribute (
     159              :   const std::vector<AST::Attribute> &attributes)
     160              : {
     161        40872 :   for (const AST::Attribute &attr : attributes)
     162              :     {
     163        14876 :       const auto &str_path = attr.get_path ().as_string ();
     164        14876 :       bool is_lang_item = str_path == Values::Attributes::LANG
     165         3262 :                           && attr.has_attr_input ()
     166        18138 :                           && attr.get_attr_input ().get_attr_input_type ()
     167        14876 :                                == AST::AttrInput::AttrInputType::LITERAL;
     168              : 
     169         3262 :       if (is_lang_item)
     170         3262 :         gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
     171         6524 :               "lang items are subject to change");
     172        14876 :     }
     173        25996 : }
     174              : 
     175              : void
     176        19722 : FeatureGate::note_stability_attribute (
     177              :   const std::vector<AST::Attribute> &attributes)
     178              : {
     179        29992 :   for (const AST::Attribute &attr : attributes)
     180              :     {
     181        10270 :       std::string attr_name = attr.get_path ().as_string ();
     182              : 
     183        10270 :       Stability stability;
     184              : 
     185        10270 :       if (attr_name == Values::Attributes::STABLE)
     186          643 :         stability = Stability::STABLE;
     187         9627 :       else if (attr_name == Values::Attributes::UNSTABLE)
     188          100 :         stability = Stability::UNSTABLE;
     189         9527 :       else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
     190          158 :         stability = Stability::STABLE;
     191         9369 :       else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
     192            8 :         stability = Stability::UNSTABLE;
     193              :       else
     194         9361 :         continue;
     195              : 
     196          909 :       if (attr.empty_input ())
     197              :         // TODO: error?
     198            0 :         continue;
     199              : 
     200          909 :       auto &attr_input = attr.get_attr_input ();
     201          909 :       if (attr_input.get_attr_input_type ()
     202              :           != AST::AttrInput::AttrInputType::TOKEN_TREE)
     203              :         // TODO: error?
     204            0 :         continue;
     205              : 
     206          909 :       std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
     207              :         static_cast<const AST::DelimTokenTree &> (attr_input)
     208          909 :           .parse_to_meta_item ());
     209              : 
     210         2727 :       for (auto &item : meta_item->get_items ())
     211              :         {
     212              :           // TODO: more thorough error checking?
     213              :           // ~only the standard libraries should ever exercise this
     214         1818 :           if (item->is_key_value_pair ())
     215              :             {
     216         1818 :               auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
     217         1818 :               if (pair.get_name ().as_string () == "feature")
     218          909 :                 defined_lib_features.emplace (pair.get_value (), stability);
     219              :             }
     220              :         }
     221        10270 :     }
     222        19722 : }
     223              : 
     224              : void
     225          976 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
     226              : {
     227          976 :   check_rustc_attri (rules_def.get_outer_attrs ());
     228          976 :   note_stability_attribute (rules_def.get_outer_attrs ());
     229          976 : }
     230              : 
     231              : void
     232        18746 : FeatureGate::visit (AST::Function &function)
     233              : {
     234        18746 :   if (!function.is_external ())
     235        16247 :     check_rustc_attri (function.get_outer_attrs ());
     236              : 
     237        18746 :   check_lang_item_attribute (function.get_outer_attrs ());
     238              : 
     239        18746 :   note_stability_attribute (function.get_outer_attrs ());
     240              : 
     241        18746 :   AST::DefaultASTVisitor::visit (function);
     242        18746 : }
     243              : 
     244              : void
     245            1 : FeatureGate::visit (AST::ExternalTypeItem &item)
     246              : {
     247              :   // TODO(mxlol233): The gating needs a complete visiting chain to activate
     248              :   // `AST::ExternalTypeItem`.
     249            1 :   gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
     250            1 :         "extern types are experimental");
     251            1 : }
     252              : 
     253              : void
     254         4742 : FeatureGate::visit (AST::TraitImpl &impl)
     255              : {
     256         4742 :   if (impl.is_exclam ())
     257            6 :     gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
     258           12 :           "negative_impls are not yet implemented");
     259              : 
     260         4742 :   AST::DefaultASTVisitor::visit (impl);
     261         4742 : }
     262              : 
     263              : void
     264         3895 : FeatureGate::visit (AST::Trait &trait)
     265              : {
     266         3895 :   if (trait.is_auto ())
     267           20 :     gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
     268           40 :           "auto traits are experimental and possibly buggy");
     269         3895 :   check_lang_item_attribute (trait.get_outer_attrs ());
     270         3895 :   AST::DefaultASTVisitor::visit (trait);
     271         3895 : }
     272              : 
     273              : void
     274            1 : FeatureGate::visit (AST::BoxExpr &expr)
     275              : {
     276            1 :   gate (
     277              :     Feature::Name::BOX_SYNTAX, expr.get_locus (),
     278            1 :     "box expression syntax is experimental; you can call `Box::new` instead");
     279            1 :   AST::DefaultASTVisitor::visit (expr);
     280            1 : }
     281              : 
     282              : void
     283          277 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
     284              : {
     285          277 :   check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
     286          277 :   AST::DefaultASTVisitor::visit (lifetime_param);
     287          277 : }
     288              : 
     289              : void
     290          100 : FeatureGate::visit (AST::ConstGenericParam &const_param)
     291              : {
     292          100 :   check_may_dangle_attribute (const_param.get_outer_attrs ());
     293          100 :   AST::DefaultASTVisitor::visit (const_param);
     294          100 : }
     295              : 
     296              : void
     297         8436 : FeatureGate::visit (AST::TypeParam &param)
     298              : {
     299         8436 :   check_may_dangle_attribute (param.get_outer_attrs ());
     300         8436 :   AST::DefaultASTVisitor::visit (param);
     301         8436 : }
     302              : 
     303              : void
     304         1929 : FeatureGate::visit (AST::BorrowExpr &expr)
     305              : {
     306         1929 :   if (expr.is_raw_borrow ())
     307            5 :     gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
     308           10 :           "raw address of syntax is experimental");
     309         1929 : }
     310              : 
     311              : void
     312           51 : FeatureGate::visit (AST::RangePattern &pattern)
     313              : {
     314           51 :   if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
     315           20 :     gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
     316           40 :           "exclusive range pattern syntax is experimental");
     317           51 : }
     318              : 
     319              : void
     320           14 : FeatureGate::visit (AST::UseTreeGlob &use)
     321              : {
     322              :   // At the moment, UseTrees do not have outer attributes, but they should. we
     323              :   // need to eventually gate `#[prelude_import]` on use-trees based on the
     324              :   // #[feature(prelude_import)]
     325           14 : }
     326              : 
     327              : void
     328         1601 : FeatureGate::visit (AST::StructStruct &struct_item)
     329              : {
     330         1601 :   check_lang_item_attribute (struct_item.get_outer_attrs ());
     331         1601 :   AST::DefaultASTVisitor::visit (struct_item);
     332         1601 : }
     333              : 
     334              : void
     335          738 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
     336              : {
     337          738 :   check_lang_item_attribute (trait_item_type.get_outer_attrs ());
     338          738 :   AST::DefaultASTVisitor::visit (trait_item_type);
     339          738 : }
     340              : 
     341              : void
     342          553 : FeatureGate::visit (AST::Enum &enum_item)
     343              : {
     344          553 :   check_lang_item_attribute (enum_item.get_outer_attrs ());
     345          553 :   AST::DefaultASTVisitor::visit (enum_item);
     346          553 : }
     347              : 
     348              : void
     349          463 : FeatureGate::visit (AST::EnumItem &enum_variant)
     350              : {
     351          463 :   check_lang_item_attribute (enum_variant.get_outer_attrs ());
     352          463 :   AST::DefaultASTVisitor::visit (enum_variant);
     353          463 : }
     354              : 
     355              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.