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 % 173 169
Test Date: 2026-03-28 14:25:54 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         4521 : FeatureGate::check (AST::Crate &crate)
      32              : {
      33         4521 :   auto &store = Features::EarlyFeatureGateStore::get ();
      34         9046 :   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         4521 :   visit (crate);
      40         4521 : }
      41              : 
      42              : void
      43         4521 : FeatureGate::visit (AST::Crate &crate)
      44              : {
      45         4521 :   AST::DefaultASTVisitor::visit (crate);
      46              : 
      47         4526 :   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         4521 :   check_no_core_attribute (crate.inner_attrs);
      67         4521 : }
      68              : 
      69              : void
      70         8370 : FeatureGate::gate (Feature::Name name, location_t loc,
      71              :                    const std::string &error_msg)
      72              : {
      73         8370 :   if (!features.valid_lang_features.count (name))
      74              :     {
      75           16 :       auto &feature = Feature::lookup (name);
      76           16 :       if (auto issue = feature.issue ())
      77              :         {
      78           10 :           auto issue_number = issue.value ();
      79           10 :           const char *fmt_str
      80              :             = "%s. see issue %u "
      81              :               "<https://github.com/rust-lang/rust/issues/%u> for more "
      82              :               "information. add `#![feature(%s)]` to the crate attributes to "
      83              :               "enable.";
      84           10 :           rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
      85              :                          issue_number, issue_number,
      86           10 :                          feature.as_string ().c_str ());
      87              :         }
      88              :       else
      89              :         {
      90            6 :           const char *fmt_str
      91              :             = "%s. add `#![feature(%s)]` to the crate attributes to enable.";
      92            6 :           rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
      93            6 :                          feature.as_string ().c_str ());
      94              :         }
      95              :     }
      96         8370 : }
      97              : 
      98              : void
      99         1473 : FeatureGate::visit (AST::ExternBlock &block)
     100              : {
     101         1473 :   if (block.has_abi ())
     102              :     {
     103         1473 :       const auto abi = block.get_abi ();
     104              : 
     105         1473 :       if (get_abi_from_string (abi) == ABI::INTRINSIC)
     106          411 :         gate (Feature::Name::INTRINSICS, block.get_locus (),
     107          822 :               "intrinsics are subject to change");
     108         1473 :     }
     109         1473 :   AST::DefaultASTVisitor::visit (block);
     110         1473 : }
     111              : 
     112              : void
     113         4521 : FeatureGate::check_no_core_attribute (
     114              :   const std::vector<AST::Attribute> &attributes)
     115              : {
     116        15772 :   for (const AST::Attribute &attr : attributes)
     117              :     {
     118        11251 :       if (attr.get_path ().as_string () == Values::Attributes::NO_CORE)
     119         4522 :         gate (Feature::Name::NO_CORE, attr.get_locus (),
     120         9044 :               "no_core is experimental");
     121              :     }
     122         4521 : }
     123              : 
     124              : void
     125        17057 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
     126              : {
     127        27150 :   for (const AST::Attribute &attr : attributes)
     128              :     {
     129        10093 :       auto name = attr.get_path ().as_string ();
     130        10093 :       if (name.rfind ("rustc_", 0) == 0)
     131              :         {
     132          264 :           gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
     133          528 :                 "internal implementation detail");
     134              :         }
     135        10093 :     }
     136        17057 : }
     137              : 
     138              : void
     139         8513 : FeatureGate::check_may_dangle_attribute (
     140              :   const std::vector<AST::Attribute> &attributes)
     141              : {
     142         8518 :   for (const AST::Attribute &attr : attributes)
     143              :     {
     144            5 :       if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
     145            5 :         gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
     146           10 :               "`may_dangle` has unstable semantics and may be removed in the "
     147              :               "future");
     148              :     }
     149         8513 : }
     150              : 
     151              : void
     152        25379 : FeatureGate::check_lang_item_attribute (
     153              :   const std::vector<AST::Attribute> &attributes)
     154              : {
     155        40103 :   for (const AST::Attribute &attr : attributes)
     156              :     {
     157        14724 :       const auto &str_path = attr.get_path ().as_string ();
     158        14724 :       bool is_lang_item = str_path == Values::Attributes::LANG
     159         3111 :                           && attr.has_attr_input ()
     160        17835 :                           && attr.get_attr_input ().get_attr_input_type ()
     161        14724 :                                == AST::AttrInput::AttrInputType::LITERAL;
     162              : 
     163         3111 :       if (is_lang_item)
     164         3111 :         gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
     165         6222 :               "lang items are subject to change");
     166        14724 :     }
     167        25379 : }
     168              : 
     169              : void
     170        19272 : FeatureGate::note_stability_attribute (
     171              :   const std::vector<AST::Attribute> &attributes)
     172              : {
     173        29536 :   for (const AST::Attribute &attr : attributes)
     174              :     {
     175        10264 :       std::string attr_name = attr.get_path ().as_string ();
     176              : 
     177        10264 :       Stability stability;
     178              : 
     179        10264 :       if (attr_name == Values::Attributes::STABLE)
     180          643 :         stability = Stability::STABLE;
     181         9621 :       else if (attr_name == Values::Attributes::UNSTABLE)
     182          100 :         stability = Stability::UNSTABLE;
     183         9521 :       else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
     184          158 :         stability = Stability::STABLE;
     185         9363 :       else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
     186            8 :         stability = Stability::UNSTABLE;
     187              :       else
     188         9355 :         continue;
     189              : 
     190          909 :       if (attr.empty_input ())
     191              :         // TODO: error?
     192            0 :         continue;
     193              : 
     194          909 :       auto &attr_input = attr.get_attr_input ();
     195          909 :       if (attr_input.get_attr_input_type ()
     196              :           != AST::AttrInput::AttrInputType::TOKEN_TREE)
     197              :         // TODO: error?
     198            0 :         continue;
     199              : 
     200          909 :       std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
     201              :         static_cast<const AST::DelimTokenTree &> (attr_input)
     202          909 :           .parse_to_meta_item ());
     203              : 
     204         2727 :       for (auto &item : meta_item->get_items ())
     205              :         {
     206              :           // TODO: more thorough error checking?
     207              :           // ~only the standard libraries should ever exercise this
     208         1818 :           if (item->is_key_value_pair ())
     209              :             {
     210         1818 :               auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
     211         1818 :               if (pair.get_name ().as_string () == "feature")
     212          909 :                 defined_lib_features.emplace (pair.get_value (), stability);
     213              :             }
     214              :         }
     215        10264 :     }
     216        19272 : }
     217              : 
     218              : void
     219          971 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
     220              : {
     221          971 :   check_rustc_attri (rules_def.get_outer_attrs ());
     222          971 :   note_stability_attribute (rules_def.get_outer_attrs ());
     223          971 : }
     224              : 
     225              : void
     226        18301 : FeatureGate::visit (AST::Function &function)
     227              : {
     228        18301 :   if (!function.is_external ())
     229        16086 :     check_rustc_attri (function.get_outer_attrs ());
     230              : 
     231        18301 :   check_lang_item_attribute (function.get_outer_attrs ());
     232              : 
     233        18301 :   note_stability_attribute (function.get_outer_attrs ());
     234              : 
     235        18301 :   AST::DefaultASTVisitor::visit (function);
     236        18301 : }
     237              : 
     238              : void
     239            1 : FeatureGate::visit (AST::ExternalTypeItem &item)
     240              : {
     241              :   // TODO(mxlol233): The gating needs a complete visiting chain to activate
     242              :   // `AST::ExternalTypeItem`.
     243            1 :   gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
     244            1 :         "extern types are experimental");
     245            1 : }
     246              : 
     247              : void
     248         4739 : FeatureGate::visit (AST::TraitImpl &impl)
     249              : {
     250         4739 :   if (impl.is_exclam ())
     251            6 :     gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
     252           12 :           "negative_impls are not yet implemented");
     253              : 
     254         4739 :   AST::DefaultASTVisitor::visit (impl);
     255         4739 : }
     256              : 
     257              : void
     258         3742 : FeatureGate::visit (AST::Trait &trait)
     259              : {
     260         3742 :   if (trait.is_auto ())
     261           20 :     gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
     262           40 :           "auto traits are experimental and possibly buggy");
     263         3742 :   check_lang_item_attribute (trait.get_outer_attrs ());
     264         3742 :   AST::DefaultASTVisitor::visit (trait);
     265         3742 : }
     266              : 
     267              : void
     268            1 : FeatureGate::visit (AST::BoxExpr &expr)
     269              : {
     270            1 :   gate (
     271              :     Feature::Name::BOX_SYNTAX, expr.get_locus (),
     272            1 :     "box expression syntax is experimental; you can call `Box::new` instead");
     273            1 :   AST::DefaultASTVisitor::visit (expr);
     274            1 : }
     275              : 
     276              : void
     277          277 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
     278              : {
     279          277 :   check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
     280          277 :   AST::DefaultASTVisitor::visit (lifetime_param);
     281          277 : }
     282              : 
     283              : void
     284           97 : FeatureGate::visit (AST::ConstGenericParam &const_param)
     285              : {
     286           97 :   check_may_dangle_attribute (const_param.get_outer_attrs ());
     287           97 :   AST::DefaultASTVisitor::visit (const_param);
     288           97 : }
     289              : 
     290              : void
     291         8139 : FeatureGate::visit (AST::TypeParam &param)
     292              : {
     293         8139 :   check_may_dangle_attribute (param.get_outer_attrs ());
     294         8139 :   AST::DefaultASTVisitor::visit (param);
     295         8139 : }
     296              : 
     297              : void
     298         1929 : FeatureGate::visit (AST::BorrowExpr &expr)
     299              : {
     300         1929 :   if (expr.is_raw_borrow ())
     301            5 :     gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
     302           10 :           "raw address of syntax is experimental");
     303         1929 : }
     304              : 
     305              : void
     306           51 : FeatureGate::visit (AST::RangePattern &pattern)
     307              : {
     308           51 :   if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
     309           20 :     gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
     310           40 :           "exclusive range pattern syntax is experimental");
     311           51 : }
     312              : 
     313              : void
     314           12 : FeatureGate::visit (AST::UseTreeGlob &use)
     315              : {
     316              :   // At the moment, UseTrees do not have outer attributes, but they should. we
     317              :   // need to eventually gate `#[prelude_import]` on use-trees based on the
     318              :   // #[feature(prelude_import)]
     319           12 : }
     320              : 
     321              : void
     322         1598 : FeatureGate::visit (AST::StructStruct &struct_item)
     323              : {
     324         1598 :   check_lang_item_attribute (struct_item.get_outer_attrs ());
     325         1598 :   AST::DefaultASTVisitor::visit (struct_item);
     326         1598 : }
     327              : 
     328              : void
     329          738 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
     330              : {
     331          738 :   check_lang_item_attribute (trait_item_type.get_outer_attrs ());
     332          738 :   AST::DefaultASTVisitor::visit (trait_item_type);
     333          738 : }
     334              : 
     335              : void
     336          544 : FeatureGate::visit (AST::Enum &enum_item)
     337              : {
     338          544 :   check_lang_item_attribute (enum_item.get_outer_attrs ());
     339          544 :   AST::DefaultASTVisitor::visit (enum_item);
     340          544 : }
     341              : 
     342              : void
     343          456 : FeatureGate::visit (AST::EnumItem &enum_variant)
     344              : {
     345          456 :   check_lang_item_attribute (enum_variant.get_outer_attrs ());
     346          456 :   AST::DefaultASTVisitor::visit (enum_variant);
     347          456 : }
     348              : 
     349              : } // 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.