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.8 % 181 177
Test Date: 2026-06-20 15:32:29 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         4695 : FeatureGate::check (AST::Crate &crate)
      32              : {
      33         4695 :   auto &store = Features::EarlyFeatureGateStore::get ();
      34         9394 :   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         4695 :   visit (crate);
      40         4695 : }
      41              : 
      42              : void
      43         4695 : FeatureGate::visit (AST::Crate &crate)
      44              : {
      45         4695 :   AST::DefaultASTVisitor::visit (crate);
      46              : 
      47         4700 :   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        16601 :   for (const auto &attribute : crate.inner_attrs)
      67              :     {
      68        11906 :       check_no_core_attribute (attribute);
      69              : 
      70        11906 :       if (attribute.get_path ().as_string ()
      71        11906 :           == 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         4695 : }
      78              : 
      79              : void
      80         9008 : FeatureGate::gate (Feature::Name name, location_t loc,
      81              :                    const std::string &error_msg)
      82              : {
      83         9008 :   if (!features.valid_lang_features.count (name))
      84              :     {
      85           19 :       auto &feature = Feature::lookup (name);
      86           19 :       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            9 :           const char *fmt_str
     101              :             = "%s. add `#![feature(%s)]` to the crate attributes to enable.";
     102            9 :           rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
     103            9 :                          feature.as_string ().c_str ());
     104              :         }
     105              :     }
     106         9008 : }
     107              : 
     108              : void
     109         1620 : FeatureGate::visit (AST::ExternBlock &block)
     110              : {
     111         1620 :   if (block.has_abi ())
     112              :     {
     113         1620 :       const auto abi = block.get_abi ();
     114              : 
     115         1620 :       if (get_abi_from_string (abi) == ABI::INTRINSIC)
     116          556 :         gate (Feature::Name::INTRINSICS, block.get_locus (),
     117         1112 :               "intrinsics are subject to change");
     118         1620 :     }
     119         1620 :   AST::DefaultASTVisitor::visit (block);
     120         1620 : }
     121              : 
     122              : void
     123        11906 : FeatureGate::check_no_core_attribute (const AST::Attribute &attribute)
     124              : {
     125        11906 :   if (attribute.get_path ().as_string () == Values::Attributes::NO_CORE)
     126         4696 :     gate (Feature::Name::NO_CORE, attribute.get_locus (),
     127         9392 :           "no_core is experimental");
     128        11906 : }
     129              : 
     130              : void
     131        17242 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
     132              : {
     133        27343 :   for (const AST::Attribute &attr : attributes)
     134              :     {
     135        10101 :       auto name = attr.get_path ().as_string ();
     136        10101 :       if (name.rfind ("rustc_", 0) == 0)
     137              :         {
     138          270 :           gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
     139          540 :                 "internal implementation detail");
     140              :         }
     141        10101 :     }
     142        17242 : }
     143              : 
     144              : void
     145         8819 : FeatureGate::check_may_dangle_attribute (
     146              :   const std::vector<AST::Attribute> &attributes)
     147              : {
     148         8824 :   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         8819 : }
     156              : 
     157              : void
     158        26020 : FeatureGate::check_lang_item_attribute (
     159              :   const std::vector<AST::Attribute> &attributes)
     160              : {
     161        40899 :   for (const AST::Attribute &attr : attributes)
     162              :     {
     163        14879 :       const auto &str_path = attr.get_path ().as_string ();
     164        14879 :       bool is_lang_item = str_path == Values::Attributes::LANG
     165         3264 :                           && attr.has_attr_input ()
     166        18143 :                           && attr.get_attr_input ().get_attr_input_type ()
     167        14879 :                                == AST::AttrInput::AttrInputType::LITERAL;
     168              : 
     169         3264 :       if (is_lang_item)
     170         3264 :         gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
     171         6528 :               "lang items are subject to change");
     172        14879 :     }
     173        26020 : }
     174              : 
     175              : void
     176        19744 : FeatureGate::note_stability_attribute (
     177              :   const std::vector<AST::Attribute> &attributes)
     178              : {
     179        30017 :   for (const AST::Attribute &attr : attributes)
     180              :     {
     181        10273 :       std::string attr_name = attr.get_path ().as_string ();
     182              : 
     183        10273 :       Stability stability;
     184              : 
     185        10273 :       if (attr_name == Values::Attributes::STABLE)
     186          643 :         stability = Stability::STABLE;
     187         9630 :       else if (attr_name == Values::Attributes::UNSTABLE)
     188          100 :         stability = Stability::UNSTABLE;
     189         9530 :       else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
     190          159 :         stability = Stability::STABLE;
     191         9371 :       else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
     192            8 :         stability = Stability::UNSTABLE;
     193              :       else
     194         9363 :         continue;
     195              : 
     196          910 :       if (attr.empty_input ())
     197              :         // TODO: error?
     198            0 :         continue;
     199              : 
     200          910 :       auto &attr_input = attr.get_attr_input ();
     201          910 :       if (attr_input.get_attr_input_type ()
     202              :           != AST::AttrInput::AttrInputType::TOKEN_TREE)
     203              :         // TODO: error?
     204            0 :         continue;
     205              : 
     206          910 :       std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
     207              :         static_cast<const AST::DelimTokenTree &> (attr_input)
     208          910 :           .parse_to_meta_item ());
     209              : 
     210         2730 :       for (auto &item : meta_item->get_items ())
     211              :         {
     212              :           // TODO: more thorough error checking?
     213              :           // ~only the standard libraries should ever exercise this
     214         1820 :           if (item->is_key_value_pair ())
     215              :             {
     216         1820 :               auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
     217         1820 :               if (pair.get_name ().as_string () == "feature")
     218          910 :                 defined_lib_features.emplace (pair.get_value (), stability);
     219              :             }
     220              :         }
     221        10273 :     }
     222        19744 : }
     223              : 
     224              : void
     225          979 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
     226              : {
     227          979 :   check_rustc_attri (rules_def.get_outer_attrs ());
     228          979 :   note_stability_attribute (rules_def.get_outer_attrs ());
     229          979 : }
     230              : 
     231              : void
     232        18765 : FeatureGate::visit (AST::Function &function)
     233              : {
     234        18765 :   if (!function.is_external ())
     235        16263 :     check_rustc_attri (function.get_outer_attrs ());
     236              : 
     237        28868 :   for (const AST::Attribute &attr : function.get_outer_attrs ())
     238              :     {
     239        10103 :       if (attr.get_path ().as_string () == "rustc_const_stable")
     240              :         {
     241          159 :           gate (Feature::Name::STAGED_API, attr.get_locus (),
     242          318 :                 "stability attributes may not be used outside of the standard "
     243              :                 "library");
     244              :         }
     245              :     }
     246              : 
     247        18765 :   check_lang_item_attribute (function.get_outer_attrs ());
     248              : 
     249        18765 :   note_stability_attribute (function.get_outer_attrs ());
     250              : 
     251        18765 :   AST::DefaultASTVisitor::visit (function);
     252        18765 : }
     253              : 
     254              : void
     255            1 : FeatureGate::visit (AST::ExternalTypeItem &item)
     256              : {
     257              :   // TODO(mxlol233): The gating needs a complete visiting chain to activate
     258              :   // `AST::ExternalTypeItem`.
     259            1 :   gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
     260            1 :         "extern types are experimental");
     261            1 : }
     262              : 
     263              : void
     264         4742 : FeatureGate::visit (AST::TraitImpl &impl)
     265              : {
     266         4742 :   if (impl.is_exclam ())
     267            6 :     gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
     268           12 :           "negative_impls are not yet implemented");
     269              : 
     270         4742 :   AST::DefaultASTVisitor::visit (impl);
     271         4742 : }
     272              : 
     273              : void
     274         3899 : FeatureGate::visit (AST::Trait &trait)
     275              : {
     276         3899 :   if (trait.is_auto ())
     277           20 :     gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
     278           40 :           "auto traits are experimental and possibly buggy");
     279         3899 :   check_lang_item_attribute (trait.get_outer_attrs ());
     280         3899 :   AST::DefaultASTVisitor::visit (trait);
     281         3899 : }
     282              : 
     283              : void
     284            1 : FeatureGate::visit (AST::BoxExpr &expr)
     285              : {
     286            1 :   gate (
     287              :     Feature::Name::BOX_SYNTAX, expr.get_locus (),
     288            1 :     "box expression syntax is experimental; you can call `Box::new` instead");
     289            1 :   AST::DefaultASTVisitor::visit (expr);
     290            1 : }
     291              : 
     292              : void
     293          277 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
     294              : {
     295          277 :   check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
     296          277 :   AST::DefaultASTVisitor::visit (lifetime_param);
     297          277 : }
     298              : 
     299              : void
     300          101 : FeatureGate::visit (AST::ConstGenericParam &const_param)
     301              : {
     302          101 :   check_may_dangle_attribute (const_param.get_outer_attrs ());
     303          101 :   AST::DefaultASTVisitor::visit (const_param);
     304          101 : }
     305              : 
     306              : void
     307         8441 : FeatureGate::visit (AST::TypeParam &param)
     308              : {
     309         8441 :   check_may_dangle_attribute (param.get_outer_attrs ());
     310         8441 :   AST::DefaultASTVisitor::visit (param);
     311         8441 : }
     312              : 
     313              : void
     314         1932 : FeatureGate::visit (AST::BorrowExpr &expr)
     315              : {
     316         1932 :   if (expr.is_raw_borrow ())
     317            5 :     gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
     318           10 :           "raw address of syntax is experimental");
     319         1932 : }
     320              : 
     321              : void
     322           51 : FeatureGate::visit (AST::RangePattern &pattern)
     323              : {
     324           51 :   if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
     325           20 :     gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
     326           40 :           "exclusive range pattern syntax is experimental");
     327           51 : }
     328              : 
     329              : void
     330           14 : FeatureGate::visit (AST::UseTreeGlob &use)
     331              : {
     332              :   // At the moment, UseTrees do not have outer attributes, but they should. we
     333              :   // need to eventually gate `#[prelude_import]` on use-trees based on the
     334              :   // #[feature(prelude_import)]
     335           14 : }
     336              : 
     337              : void
     338         1602 : FeatureGate::visit (AST::StructStruct &struct_item)
     339              : {
     340         1602 :   check_lang_item_attribute (struct_item.get_outer_attrs ());
     341         1602 :   AST::DefaultASTVisitor::visit (struct_item);
     342         1602 : }
     343              : 
     344              : void
     345          738 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
     346              : {
     347          738 :   check_lang_item_attribute (trait_item_type.get_outer_attrs ());
     348          738 :   AST::DefaultASTVisitor::visit (trait_item_type);
     349          738 : }
     350              : 
     351              : void
     352          553 : FeatureGate::visit (AST::Enum &enum_item)
     353              : {
     354          553 :   check_lang_item_attribute (enum_item.get_outer_attrs ());
     355          553 :   AST::DefaultASTVisitor::visit (enum_item);
     356          553 : }
     357              : 
     358              : void
     359          463 : FeatureGate::visit (AST::EnumItem &enum_variant)
     360              : {
     361          463 :   check_lang_item_attribute (enum_variant.get_outer_attrs ());
     362          463 :   AST::DefaultASTVisitor::visit (enum_variant);
     363          463 : }
     364              : 
     365              : } // 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.