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.4 % 189 186
Test Date: 2026-10-03 16:17:38 Functions: 100.0 % 26 26
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         4975 : FeatureGate::check (AST::Crate &crate)
      32              : {
      33         4975 :   auto &store = Features::EarlyFeatureGateStore::get ();
      34        11279 :   while (store.has_error ())
      35              :     {
      36         1329 :       auto pair = store.get_error ();
      37         1329 :       gate (pair.first, pair.second.locus, pair.second.message);
      38         1329 :     }
      39         4975 :   visit (crate);
      40         4975 : }
      41              : 
      42              : void
      43         4975 : FeatureGate::visit (AST::Crate &crate)
      44              : {
      45         4975 :   AST::DefaultASTVisitor::visit (crate);
      46              : 
      47         5015 :   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        17750 :   for (const auto &attribute : crate.inner_attrs)
      67              :     {
      68        12775 :       check_no_core_attribute (attribute);
      69              : 
      70        25550 :       if (attribute.get_path ().as_string ()
      71        12775 :           == 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         4975 : }
      78              : 
      79              : FeatureGate::GateResult
      80        14376 : FeatureGate::gate (Feature::Name name, location_t loc,
      81              :                    const std::string &error_msg)
      82              : {
      83        14376 :   if (!features.valid_lang_features.count (name))
      84              :     {
      85           20 :       auto &feature = Feature::lookup (name);
      86           20 :       if (auto issue = feature.issue ())
      87              :         {
      88           11 :           auto issue_number = issue.value ();
      89           11 :           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           11 :           rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
      95              :                          issue_number, issue_number,
      96           11 :                          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           20 :       return GateResult::Gated;
     107              :     }
     108              : 
     109              :   return GateResult::Allowed;
     110              : }
     111              : 
     112              : void
     113         1774 : FeatureGate::visit (AST::ExternBlock &block)
     114              : {
     115         1774 :   if (block.has_abi ())
     116              :     {
     117         1773 :       const auto abi = block.get_abi ();
     118              : 
     119         1773 :       if (get_abi_from_string (abi) == ABI::INTRINSIC)
     120          600 :         gate (Feature::Name::INTRINSICS, block.get_locus (),
     121         1200 :               "intrinsics are subject to change");
     122         1773 :     }
     123         1774 :   AST::DefaultASTVisitor::visit (block);
     124         1774 : }
     125              : 
     126              : void
     127        12775 : FeatureGate::check_no_core_attribute (const AST::Attribute &attribute)
     128              : {
     129        12775 :   if (attribute.get_path ().as_string () == Values::Attributes::NO_CORE)
     130         4976 :     gate (Feature::Name::NO_CORE, attribute.get_locus (),
     131         9952 :           "no_core is experimental");
     132        12775 : }
     133              : 
     134              : void
     135        33136 : FeatureGate::check_rustc_attri (const std::vector<AST::Attribute> &attributes)
     136              : {
     137       104651 :   for (const AST::Attribute &attr : attributes)
     138              :     {
     139        71515 :       auto name = attr.get_path ().as_string ();
     140        71515 :       if (name.rfind ("rustc_", 0) == 0)
     141              :         {
     142         2715 :           gate (Feature::Name::RUSTC_ATTRS, attr.get_locus (),
     143         5430 :                 "internal implementation detail");
     144              :         }
     145        71515 :     }
     146        33136 : }
     147              : 
     148              : void
     149        20927 : FeatureGate::check_may_dangle_attribute (
     150              :   const std::vector<AST::Attribute> &attributes)
     151              : {
     152        20943 :   for (const AST::Attribute &attr : attributes)
     153              :     {
     154           16 :       if (attr.get_path ().as_string () == Values::Attributes::MAY_DANGLE)
     155           15 :         gate (Feature::Name::DROPCK_EYEPATCH, attr.get_locus (),
     156           30 :               "`may_dangle` has unstable semantics and may be removed in the "
     157              :               "future");
     158              :     }
     159        20927 : }
     160              : 
     161              : void
     162        44022 : FeatureGate::check_lang_item_attribute (
     163              :   const std::vector<AST::Attribute> &attributes)
     164              : {
     165       130422 :   for (const AST::Attribute &attr : attributes)
     166              :     {
     167        86400 :       const auto &str_path = attr.get_path ().as_string ();
     168        86400 :       bool is_lang_item = str_path == Values::Attributes::LANG
     169         3709 :                           && attr.has_attr_input ()
     170        90109 :                           && attr.get_attr_input ().get_attr_input_type ()
     171        86400 :                                == AST::AttrInput::AttrInputType::LITERAL;
     172              : 
     173         3709 :       if (is_lang_item)
     174         3709 :         gate (Feature::Name::LANG_ITEMS, attr.get_locus (),
     175         7418 :               "lang items are subject to change");
     176        86400 :     }
     177        44022 : }
     178              : 
     179              : void
     180        36663 : FeatureGate::note_stability_attribute (
     181              :   const std::vector<AST::Attribute> &attributes)
     182              : {
     183       110310 :   for (const AST::Attribute &attr : attributes)
     184              :     {
     185        73647 :       std::string attr_name = attr.get_path ().as_string ();
     186              : 
     187        73647 :       Stability stability;
     188              : 
     189        73647 :       if (attr_name == Values::Attributes::STABLE)
     190         3530 :         stability = Stability::STABLE;
     191        70117 :       else if (attr_name == Values::Attributes::UNSTABLE)
     192          694 :         stability = Stability::UNSTABLE;
     193        69423 :       else if (attr_name == Values::Attributes::RUSTC_CONST_STABLE)
     194          915 :         stability = Stability::STABLE;
     195        68508 :       else if (attr_name == Values::Attributes::RUSTC_CONST_UNSTABLE)
     196          410 :         stability = Stability::UNSTABLE;
     197              :       else
     198        68098 :         continue;
     199              : 
     200         5549 :       if (attr.empty_input ())
     201              :         // TODO: error?
     202            0 :         continue;
     203              : 
     204         5549 :       auto &attr_input = attr.get_attr_input ();
     205         5549 :       if (attr_input.get_attr_input_type ()
     206              :           != AST::AttrInput::AttrInputType::TOKEN_TREE)
     207              :         // TODO: error?
     208            0 :         continue;
     209              : 
     210         5549 :       std::unique_ptr<AST::AttrInputMetaItemContainer> meta_item (
     211              :         static_cast<const AST::DelimTokenTree &> (attr_input)
     212         5549 :           .parse_to_meta_item ());
     213              : 
     214        16781 :       for (auto &item : meta_item->get_items ())
     215              :         {
     216              :           // TODO: more thorough error checking?
     217              :           // ~only the standard libraries should ever exercise this
     218        11232 :           if (item->is_key_value_pair ())
     219              :             {
     220        11231 :               auto &pair = static_cast<const AST::MetaNameValueStr &> (*item);
     221        11231 :               if (pair.get_name ().as_string () == "feature")
     222         5549 :                 defined_lib_features.emplace (pair.get_value (), stability);
     223              :             }
     224              :         }
     225        73647 :     }
     226        36663 : }
     227              : 
     228              : void
     229         1819 : FeatureGate::visit (AST::MacroRulesDefinition &rules_def)
     230              : {
     231         1819 :   check_rustc_attri (rules_def.get_outer_attrs ());
     232         1819 :   note_stability_attribute (rules_def.get_outer_attrs ());
     233         1819 : }
     234              : 
     235              : void
     236        34844 : FeatureGate::visit (AST::Function &function)
     237              : {
     238        34844 :   if (!function.is_external ())
     239        31317 :     check_rustc_attri (function.get_outer_attrs ());
     240              : 
     241       106972 :   for (const AST::Attribute &attr : function.get_outer_attrs ())
     242              :     {
     243        72128 :       if (attr.get_path ().as_string () == "rustc_const_stable")
     244              :         {
     245          915 :           gate (Feature::Name::STAGED_API, attr.get_locus (),
     246         1830 :                 "stability attributes may not be used outside of the standard "
     247              :                 "library");
     248              :         }
     249              :     }
     250              : 
     251        34844 :   check_lang_item_attribute (function.get_outer_attrs ());
     252              : 
     253        34844 :   note_stability_attribute (function.get_outer_attrs ());
     254              : 
     255        34844 :   AST::DefaultASTVisitor::visit (function);
     256        34844 : }
     257              : 
     258              : void
     259            5 : FeatureGate::visit (AST::ExternalTypeItem &item)
     260              : {
     261              :   // TODO(mxlol233): The gating needs a complete visiting chain to activate
     262              :   // `AST::ExternalTypeItem`.
     263            5 :   gate (Feature::Name::EXTERN_TYPES, item.get_locus (),
     264            5 :         "extern types are experimental");
     265            5 : }
     266              : 
     267              : void
     268        13160 : FeatureGate::visit (AST::TraitImpl &impl)
     269              : {
     270        13160 :   if (impl.is_exclam ())
     271           26 :     gate (Feature::Name::NEGATIVE_IMPLS, impl.get_locus (),
     272           52 :           "negative_impls are not yet implemented");
     273              : 
     274        13160 :   AST::DefaultASTVisitor::visit (impl);
     275        13160 : }
     276              : 
     277              : void
     278         4466 : FeatureGate::visit (AST::Trait &trait)
     279              : {
     280         4466 :   if (trait.is_auto ())
     281           30 :     gate (Feature::Name::OPTIN_BUILTIN_TRAITS, trait.get_locus (),
     282           60 :           "auto traits are experimental and possibly buggy");
     283         4466 :   check_lang_item_attribute (trait.get_outer_attrs ());
     284         4466 :   AST::DefaultASTVisitor::visit (trait);
     285         4466 : }
     286              : 
     287              : void
     288           19 : FeatureGate::visit (AST::BoxExpr &expr)
     289              : {
     290           19 :   gate (
     291              :     Feature::Name::BOX_SYNTAX, expr.get_locus (),
     292           19 :     "box expression syntax is experimental; you can call `Box::new` instead");
     293           19 :   AST::DefaultASTVisitor::visit (expr);
     294           19 : }
     295              : 
     296              : void
     297         1840 : FeatureGate::visit (AST::LifetimeParam &lifetime_param)
     298              : {
     299         1840 :   check_may_dangle_attribute (lifetime_param.get_outer_attrs ());
     300         1840 :   AST::DefaultASTVisitor::visit (lifetime_param);
     301         1840 : }
     302              : 
     303              : void
     304          201 : FeatureGate::visit (AST::ConstGenericParam &const_param)
     305              : {
     306          201 :   check_may_dangle_attribute (const_param.get_outer_attrs ());
     307          201 :   AST::DefaultASTVisitor::visit (const_param);
     308          201 : }
     309              : 
     310              : void
     311        18886 : FeatureGate::visit (AST::TypeParam &param)
     312              : {
     313        18886 :   check_may_dangle_attribute (param.get_outer_attrs ());
     314        18886 :   AST::DefaultASTVisitor::visit (param);
     315        18886 : }
     316              : 
     317              : void
     318         5678 : FeatureGate::visit (AST::BorrowExpr &expr)
     319              : {
     320         5678 :   if (expr.is_raw_borrow ())
     321           11 :     gate (Feature::Name::RAW_REF_OP, expr.get_locus (),
     322           22 :           "raw address of syntax is experimental");
     323         5678 : }
     324              : 
     325              : void
     326          131 : FeatureGate::visit (AST::RangePattern &pattern)
     327              : {
     328          131 :   if (pattern.get_range_kind () == AST::RangeKind::EXCLUDED)
     329           23 :     gate (Feature::Name::EXCLUSIVE_RANGE_PATTERN, pattern.get_locus (),
     330           46 :           "exclusive range pattern syntax is experimental");
     331          131 : }
     332              : 
     333              : void
     334          128 : FeatureGate::visit (AST::UseTreeGlob &use)
     335              : {
     336              :   // At the moment, UseTrees do not have outer attributes, but they should. we
     337              :   // need to eventually gate `#[prelude_import]` on use-trees based on the
     338              :   // #[feature(prelude_import)]
     339          128 : }
     340              : 
     341              : void
     342         2603 : FeatureGate::visit (AST::StructStruct &struct_item)
     343              : {
     344         2603 :   check_lang_item_attribute (struct_item.get_outer_attrs ());
     345         2603 :   AST::DefaultASTVisitor::visit (struct_item);
     346         2603 : }
     347              : 
     348              : void
     349          880 : FeatureGate::visit (AST::TraitItemType &trait_item_type)
     350              : {
     351          880 :   check_lang_item_attribute (trait_item_type.get_outer_attrs ());
     352          880 :   AST::DefaultASTVisitor::visit (trait_item_type);
     353          880 : }
     354              : 
     355              : void
     356          651 : FeatureGate::visit (AST::Enum &enum_item)
     357              : {
     358          651 :   check_lang_item_attribute (enum_item.get_outer_attrs ());
     359          651 :   AST::DefaultASTVisitor::visit (enum_item);
     360          651 : }
     361              : 
     362              : void
     363          578 : FeatureGate::visit (AST::EnumItem &enum_variant)
     364              : {
     365          578 :   check_lang_item_attribute (enum_variant.get_outer_attrs ());
     366          578 :   AST::DefaultASTVisitor::visit (enum_variant);
     367          578 : }
     368              : 
     369              : void
     370       114351 : FeatureGate::visit (AST::Attribute &attr)
     371              : {
     372       114351 :   if (attr.get_path ().as_string () == "cfi_encoding")
     373            2 :     if (gate (Feature::Name::CFI_ENCODING, attr.get_locus (),
     374            4 :               "#[cfi_encoding] is an experimental feature")
     375            2 :         == GateResult::Allowed)
     376            1 :       rust_warning_at (
     377              :         attr.get_locus (), 0,
     378              :         "the %<#[cfi_encoding]%> attribute is currently ignored and "
     379              :         "does nothing - we are waiting on a patchset to land "
     380              :         "into GCC as the KCFI functionality is not present yet");
     381              : 
     382       114351 :   AST::DefaultASTVisitor::visit (attr);
     383       114351 : }
     384              : 
     385              : } // 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.