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: 98.5 % 206 203
Test Date: 2026-10-24 16:24:59 Functions: 100.0 % 29 29
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         5049 : FeatureGate::check (AST::Crate &crate)
      32              : {
      33         5049 :   auto &store = Features::EarlyFeatureGateStore::get ();
      34        10101 :   while (store.has_error ())
      35              :     {
      36            3 :       auto pair = store.get_error ();
      37            3 :       gate (pair.first, pair.second.locus, pair.second.message);
      38            3 :     }
      39         5049 :   visit (crate);
      40         5049 : }
      41              : 
      42              : void
      43         5049 : FeatureGate::visit (AST::Crate &crate)
      44              : {
      45         5049 :   AST::DefaultASTVisitor::visit (crate);
      46              : 
      47         5089 :   for (auto &ent : features.valid_lib_features)
      48              :     {
      49           40 :       const std::string &feature = ent.first;
      50           40 :       location_t locus = ent.second;
      51              : 
      52              :       // rustc treats these as valid,
      53              :       // but apparently has special handling for them
      54           40 :       if (feature == "libc" || feature == "test")
      55            0 :         continue;
      56              : 
      57           40 :       if (defined_lib_features.find (feature) != defined_lib_features.end ())
      58              :         {
      59              :           // TODO: emit warning if stable
      60           35 :           continue;
      61              :         }
      62              : 
      63            5 :       rust_error_at (locus, ErrorCode::E0635, "unknown feature %qs",
      64              :                      feature.c_str ());
      65              :     }
      66        17994 :   for (const auto &attribute : crate.inner_attrs)
      67              :     {
      68        12945 :       check_no_core_attribute (attribute);
      69              : 
      70        25890 :       if (attribute.get_path ().as_string ()
      71        12945 :           == 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         5049 : }
      78              : 
      79              : FeatureGate::GateResult
      80        13198 : FeatureGate::gate (Feature::Name name, location_t loc,
      81              :                    const std::string &error_msg)
      82              : {
      83        13198 :   if (!features.valid_lang_features.count (name))
      84              :     {
      85           22 :       auto &feature = Feature::lookup (name);
      86           22 :       if (auto issue = feature.issue ())
      87              :         {
      88           13 :           auto issue_number = issue.value ();
      89           13 :           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           13 :           rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
      95              :                          issue_number, issue_number,
      96           13 :                          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           22 :       return GateResult::Gated;
     107              :     }
     108              : 
     109              :   return GateResult::Allowed;
     110              : }
     111              : 
     112              : void
     113         1784 : FeatureGate::visit (AST::ExternBlock &block)
     114              : {
     115         1784 :   if (block.has_abi ())
     116              :     {
     117         1783 :       const auto abi = block.get_abi ();
     118              : 
     119         1783 :       if (get_abi_from_string (abi) == ABI::INTRINSIC)
     120          608 :         gate (Feature::Name::INTRINSICS, block.get_locus (),
     121         1216 :               "intrinsics are subject to change");
     122         1783 :     }
     123         1784 :   AST::DefaultASTVisitor::visit (block);
     124         1784 : }
     125              : 
     126              : void
     127           24 : FeatureGate::check_used_attribute (const AST::Attribute &attribute)
     128              : {
     129           24 :   if (attribute.get_path ().as_string () == Values::Attributes::USED)
     130           11 :     if (attribute.has_attr_input ())
     131            7 :       gate (Feature::Name::USED_WITH_ARG, attribute.get_locus (),
     132           14 :             "malformed #[used] attribute input");
     133           24 : }
     134              : 
     135              : void
     136        12945 : FeatureGate::check_no_core_attribute (const AST::Attribute &attribute)
     137              : {
     138        12945 :   if (attribute.get_path ().as_string () == Values::Attributes::NO_CORE)
     139         5050 :     gate (Feature::Name::NO_CORE, attribute.get_locus (),
     140        10100 :           "no_core is experimental");
     141        12945 : }
     142              : 
     143              : void
     144        33312 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
     145              : {
     146       104824 :   for (const AST::Attribute &attr : attributes)
     147              :     {
     148        71512 :       auto name = attr.get_path ().as_string ();
     149        71512 :       if (name.rfind ("rustc_", 0) == 0)
     150              :         {
     151         2712 :           gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
     152         5424 :                 "internal implementation detail");
     153              :         }
     154        71512 :     }
     155        33312 : }
     156              : 
     157              : void
     158        21118 : FeatureGate::check_may_dangle_attribute (
     159              :   const std::vector<AST::Attribute> &attributes)
     160              : {
     161        21134 :   for (const AST::Attribute &attr : attributes)
     162              :     {
     163           16 :       if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
     164           15 :         gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
     165           30 :               "`may_dangle` has unstable semantics and may be removed in the "
     166              :               "future");
     167              :     }
     168        21118 : }
     169              : 
     170              : void
     171        44392 : FeatureGate::check_lang_item_attribute (
     172              :   const std::vector<AST::Attribute> &attributes)
     173              : {
     174       130858 :   for (const AST::Attribute &attr : attributes)
     175              :     {
     176        86466 :       const auto &str_path = attr.get_path ().as_string ();
     177        86466 :       bool is_lang_item = str_path == Values::Attributes::LANG
     178         3769 :                           && attr.has_attr_input ()
     179        90235 :                           && attr.get_attr_input ().get_attr_input_type ()
     180        86466 :                                == AST::AttrInput::AttrInputType::LITERAL;
     181              : 
     182         3769 :       if (is_lang_item)
     183         3769 :         gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
     184         7538 :               "lang items are subject to change");
     185        86466 :     }
     186        44392 : }
     187              : 
     188              : void
     189        36858 : FeatureGate::note_stability_attribute (
     190              :   const std::vector<AST::Attribute> &attributes)
     191              : {
     192       110502 :   for (const AST::Attribute &attr : attributes)
     193              :     {
     194        73644 :       std::string attr_name = attr.get_path ().as_string ();
     195              : 
     196        73644 :       Stability stability;
     197              : 
     198        73644 :       if (attr_name == Values::Attributes::STABLE)
     199         3530 :         stability = Stability::STABLE;
     200        70114 :       else if (attr_name == Values::Attributes::UNSTABLE)
     201          694 :         stability = Stability::UNSTABLE;
     202        69420 :       else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
     203          915 :         stability = Stability::STABLE;
     204        68505 :       else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
     205          410 :         stability = Stability::UNSTABLE;
     206              :       else
     207        68095 :         continue;
     208              : 
     209         5549 :       if (attr.empty_input ())
     210              :         // TODO: error?
     211            0 :         continue;
     212              : 
     213         5549 :       auto &attr_input = attr.get_attr_input ();
     214         5549 :       if (attr_input.get_attr_input_type ()
     215              :           != AST::AttrInput::AttrInputType::TOKEN_TREE)
     216              :         // TODO: error?
     217            0 :         continue;
     218              : 
     219         5549 :       std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
     220              :         static_cast<const AST::DelimTokenTree &> (attr_input)
     221         5549 :           .parse_to_meta_item ());
     222              : 
     223        16781 :       for (auto &item : meta_item->get_items ())
     224              :         {
     225              :           // TODO: more thorough error checking?
     226              :           // ~only the standard libraries should ever exercise this
     227        11232 :           if (item->is_key_value_pair ())
     228              :             {
     229        11231 :               auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
     230        11231 :               if (pair.get_name ().as_string () == "feature")
     231         5549 :                 defined_lib_features.emplace (pair.get_value (), stability);
     232              :             }
     233              :         }
     234        73644 :     }
     235        36858 : }
     236              : 
     237              : void
     238         1815 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
     239              : {
     240         1815 :   check_rustc_attri (rules_def.get_outer_attrs ());
     241         1815 :   note_stability_attribute (rules_def.get_outer_attrs ());
     242         1815 : }
     243              : 
     244              : void
     245        35043 : FeatureGate::visit (AST::Function &function)
     246              : {
     247        35043 :   if (!function.is_external ())
     248        31497 :     check_rustc_attri (function.get_outer_attrs ());
     249              : 
     250       107171 :   for (const AST::Attribute &attr : function.get_outer_attrs ())
     251              :     {
     252        72128 :       if (attr.get_path ().as_string () == "rustc_const_stable")
     253              :         {
     254          915 :           gate (Feature::Name::STAGED_API, attr.get_locus (),
     255         1830 :                 "stability attributes may not be used outside of the standard "
     256              :                 "library");
     257              :         }
     258              :     }
     259              : 
     260        35043 :   check_lang_item_attribute (function.get_outer_attrs ());
     261              : 
     262        35043 :   note_stability_attribute (function.get_outer_attrs ());
     263              : 
     264        35043 :   AST::DefaultASTVisitor::visit (function);
     265        35043 : }
     266              : 
     267              : void
     268            5 : FeatureGate::visit (AST::ExternalTypeItem &item)
     269              : {
     270              :   // TODO(mxlol233): The gating needs a complete visiting chain to activate
     271              :   // `AST::ExternalTypeItem`.
     272            5 :   gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
     273            5 :         "extern types are experimental");
     274              : 
     275            5 :   AST::DefaultASTVisitor::visit (item);
     276            5 : }
     277              : 
     278              : void
     279        13182 : FeatureGate::visit (AST::TraitImpl &impl)
     280              : {
     281        13182 :   if (impl.is_exclam ())
     282           26 :     gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
     283           52 :           "negative_impls are not yet implemented");
     284              : 
     285        13182 :   AST::DefaultASTVisitor::visit (impl);
     286        13182 : }
     287              : 
     288              : void
     289         4546 : FeatureGate::visit (AST::Trait &trait)
     290              : {
     291         4546 :   if (trait.is_auto ())
     292           30 :     gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
     293           60 :           "auto traits are experimental and possibly buggy");
     294         4546 :   check_lang_item_attribute (trait.get_outer_attrs ());
     295         4546 :   AST::DefaultASTVisitor::visit (trait);
     296         4546 : }
     297              : 
     298              : void
     299           19 : FeatureGate::visit (AST::BoxExpr &expr)
     300              : {
     301           19 :   gate (
     302              :     Feature::Name::BOX_SYNTAX, expr.get_locus (),
     303           19 :     "box expression syntax is experimental; you can call `Box::new` instead");
     304           19 :   AST::DefaultASTVisitor::visit (expr);
     305           19 : }
     306              : 
     307              : void
     308         1860 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
     309              : {
     310         1860 :   check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
     311         1860 :   AST::DefaultASTVisitor::visit (lifetime_param);
     312         1860 : }
     313              : 
     314              : void
     315          203 : FeatureGate::visit (AST::ConstGenericParam &const_param)
     316              : {
     317          203 :   check_may_dangle_attribute (const_param.get_outer_attrs ());
     318          203 :   AST::DefaultASTVisitor::visit (const_param);
     319          203 : }
     320              : 
     321              : void
     322        19055 : FeatureGate::visit (AST::TypeParam &param)
     323              : {
     324        19055 :   check_may_dangle_attribute (param.get_outer_attrs ());
     325        19055 :   AST::DefaultASTVisitor::visit (param);
     326        19055 : }
     327              : 
     328              : void
     329         5683 : FeatureGate::visit (AST::BorrowExpr &expr)
     330              : {
     331         5683 :   if (expr.is_raw_borrow ())
     332           11 :     gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
     333           22 :           "raw address of syntax is experimental");
     334         5683 : }
     335              : 
     336              : void
     337          131 : FeatureGate::visit (AST::RangePattern &pattern)
     338              : {
     339          131 :   if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
     340           23 :     gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
     341           46 :           "exclusive range pattern syntax is experimental");
     342          131 : }
     343              : 
     344              : void
     345          128 : FeatureGate::visit (AST::UseTreeGlob &use)
     346              : {
     347              :   // At the moment, UseTrees do not have outer attributes, but they should. we
     348              :   // need to eventually gate `#[prelude_import]` on use-trees based on the
     349              :   // #[feature(prelude_import)]
     350          128 : }
     351              : 
     352              : void
     353         2646 : FeatureGate::visit (AST::StructStruct &struct_item)
     354              : {
     355         2646 :   check_lang_item_attribute (struct_item.get_outer_attrs ());
     356         2646 :   AST::DefaultASTVisitor::visit (struct_item);
     357         2646 : }
     358              : 
     359              : void
     360          901 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
     361              : {
     362          901 :   check_lang_item_attribute (trait_item_type.get_outer_attrs ());
     363          901 :   AST::DefaultASTVisitor::visit (trait_item_type);
     364          901 : }
     365              : 
     366              : void
     367          665 : FeatureGate::visit (AST::Enum &enum_item)
     368              : {
     369          665 :   check_lang_item_attribute (enum_item.get_outer_attrs ());
     370          665 :   AST::DefaultASTVisitor::visit (enum_item);
     371          665 : }
     372              : 
     373              : void
     374          591 : FeatureGate::visit (AST::EnumItem &enum_variant)
     375              : {
     376          591 :   check_lang_item_attribute (enum_variant.get_outer_attrs ());
     377          591 :   AST::DefaultASTVisitor::visit (enum_variant);
     378          591 : }
     379              : void
     380          132 : FeatureGate::visit (AST::StaticItem &static_item)
     381              : {
     382          156 :   for (const auto &attr : static_item.get_outer_attrs ())
     383           24 :     check_used_attribute (attr);
     384              : 
     385          132 :   AST::DefaultASTVisitor::visit (static_item);
     386          132 : }
     387              : 
     388              : void
     389            2 : FeatureGate::visit (AST::TraitAlias &trait_alias)
     390              : {
     391            2 :   gate (Feature::Name::TRAIT_ALIAS, trait_alias.get_locus (),
     392            2 :         "trait aliases are experimental");
     393              : 
     394            2 :   AST::DefaultASTVisitor::visit (trait_alias);
     395            2 : }
     396              : 
     397              : void
     398       114598 : FeatureGate::visit (AST::Attribute &attr)
     399              : {
     400       114598 :   if (attr.get_path ().as_string () == "cfi_encoding")
     401            2 :     if (gate (Feature::Name::CFI_ENCODING, attr.get_locus (),
     402            4 :               "#[cfi_encoding] is an experimental feature")
     403            2 :         == GateResult::Allowed)
     404            1 :       rust_warning_at (
     405              :         attr.get_locus (), 0,
     406              :         "the %<#[cfi_encoding]%> attribute is currently ignored and "
     407              :         "does nothing - we are waiting on a patchset to land "
     408              :         "into GCC as the KCFI functionality is not present yet");
     409              : 
     410       114598 :   AST::DefaultASTVisitor::visit (attr);
     411       114598 : }
     412              : 
     413              : } // namespace Rust
        

Generated by: LCOV version 2.5.0-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.