LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors - rust-builtin-attribute-checker.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 78.9 % 261 206
Test Date: 2026-08-22 16:33:35 Functions: 100.0 % 35 35
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 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-builtin-attribute-checker.h"
      20              : #include "optional.h"
      21              : #include "rust-attributes.h"
      22              : #include "rust-attribute-values.h"
      23              : #include "rust-session-manager.h"
      24              : 
      25              : namespace Rust {
      26              : namespace Analysis {
      27              : 
      28              : using Attrs = Values::Attributes;
      29              : 
      30              : void
      31        12363 : check_inner_attribute (const AST::Attribute &attribute)
      32              : {
      33        12363 :   auto result_opt = lookup_builtin (attribute);
      34        12363 :   if (!result_opt.has_value ())
      35            0 :     return;
      36        12363 :   auto result = result_opt.value ();
      37              : 
      38        12363 :   if (Attributes::valid_outer_attribute (result.name))
      39            3 :     rust_error_at (attribute.get_locus (),
      40              :                    "attribute cannot be used at crate level");
      41              : 
      42        12363 :   if (result.name == Values::Attributes::NEEDS_ALLOCATOR)
      43              :     {
      44            1 :       rust_warning_at (attribute.get_locus (), 0,
      45              :                        "%<#[%s]%> is not implemented yet and has no effect",
      46            2 :                        attribute.as_string ().c_str ());
      47              :     }
      48        24726 : }
      49              : 
      50              : /**
      51              :  * Check that the string given to #[doc(alias = ...)] or #[doc(alias(...))] is
      52              :  * valid.
      53              :  *
      54              :  * This means no whitespace characters other than spaces and no quoting
      55              :  * characters.
      56              :  */
      57              : static void
      58          761 : check_doc_alias (const std::string &alias_input, const location_t locus)
      59              : {
      60              :   // FIXME: The locus here is for the whole attribute. Can we get the locus
      61              :   // of the alias input instead?
      62         2052 :   for (auto c : alias_input)
      63         1291 :     if ((ISSPACE (c) && c != ' ') || c == '\'' || c == '\"')
      64              :       {
      65            7 :         auto to_print = std::string (1, c);
      66            7 :         switch (c)
      67              :           {
      68            7 :           case '\n':
      69            7 :             to_print = "\\n";
      70            7 :             break;
      71            0 :           case '\t':
      72            0 :             to_print = "\\t";
      73            0 :             break;
      74              :           default:
      75              :             break;
      76              :           }
      77            7 :         rust_error_at (locus,
      78              :                        "invalid character used in %<#[doc(alias)]%> input: %qs",
      79              :                        to_print.c_str ());
      80            7 :       }
      81              : 
      82          761 :   if (alias_input.empty ())
      83              :     return;
      84              : 
      85         1522 :   if (alias_input.front () == ' ' || alias_input.back () == ' ')
      86            0 :     rust_error_at (locus,
      87              :                    "%<#[doc(alias)]%> input cannot start or end with a space");
      88              : }
      89              : 
      90              : // This namespace contains handlers for the builtin attribute checker,
      91              : // those handlers must verify the attribute internal structure and emit the
      92              : // appropriate error message if the structure is incorrect.
      93              : //
      94              : // They DO NOT check the attribute validity on the parent item.
      95              : namespace handlers {
      96              : 
      97              : void
      98        55564 : doc (const AST::Attribute &attribute)
      99              : {
     100        55564 :   if (!attribute.has_attr_input ())
     101              :     {
     102            2 :       rust_error_at (
     103              :         attribute.get_locus (),
     104              :         "valid forms for the attribute are "
     105              :         "%<#[doc(hidden|inline|...)]%> and %<#[doc = \" string \"]%>");
     106            2 :       return;
     107              :     }
     108              : 
     109        55562 :   switch (attribute.get_attr_input ().get_attr_input_type ())
     110              :     {
     111              :     case AST::AttrInput::LITERAL:
     112              :     case AST::AttrInput::META_ITEM:
     113              :     case AST::AttrInput::EXPR:
     114              :       break;
     115              :       // FIXME: Handle them as well
     116              : 
     117          994 :     case AST::AttrInput::TOKEN_TREE:
     118          994 :       {
     119              :         // FIXME: This doesn't check for #[doc(alias(...))]
     120          994 :         const auto &option = static_cast<const AST::DelimTokenTree &> (
     121          994 :           attribute.get_attr_input ());
     122          994 :         auto *meta_item = option.parse_to_meta_item ();
     123              : 
     124         1999 :         for (auto &item : meta_item->get_items ())
     125              :           {
     126         1005 :             if (item->is_key_value_pair ())
     127              :               {
     128          773 :                 auto name_value
     129          773 :                   = static_cast<AST::MetaNameValueStr *> (item.get ())
     130          773 :                       ->get_name_value_pair ();
     131              : 
     132              :                 // FIXME: Check for other stuff than #[doc(alias = ...)]
     133          773 :                 if (name_value.first.as_string () == "alias")
     134          761 :                   check_doc_alias (name_value.second, attribute.get_locus ());
     135          773 :               }
     136              :           }
     137              :         break;
     138              :       }
     139              :     }
     140              : }
     141              : 
     142              : void
     143            6 : deprecated (const AST::Attribute &attribute)
     144              : {
     145            6 :   if (!attribute.has_attr_input ())
     146              :     return;
     147              : 
     148            4 :   const auto &input = attribute.get_attr_input ();
     149              : 
     150            4 :   if (input.get_attr_input_type () != AST::AttrInput::META_ITEM)
     151              :     return;
     152              : 
     153            0 :   auto &meta = static_cast<const AST::AttrInputMetaItemContainer &> (input);
     154              : 
     155            0 :   for (auto &current : meta.get_items ())
     156              :     {
     157            0 :       switch (current->get_kind ())
     158              :         {
     159            0 :         case AST::MetaItemInner::Kind::MetaItem:
     160            0 :           {
     161            0 :             auto *meta_item = static_cast<AST::MetaItem *> (current.get ());
     162              : 
     163            0 :             switch (meta_item->get_item_kind ())
     164              :               {
     165            0 :               case AST::MetaItem::ItemKind::NameValueStr:
     166            0 :                 {
     167            0 :                   auto *nv = static_cast<AST::MetaNameValueStr *> (meta_item);
     168              : 
     169            0 :                   const std::string key = nv->get_name ().as_string ();
     170              : 
     171            0 :                   if (key != "since" && key != "note")
     172              :                     {
     173            0 :                       rust_error_at (nv->get_locus (), "unknown meta item %qs",
     174              :                                      key.c_str ());
     175            0 :                       rust_inform (nv->get_locus (),
     176              :                                    "expected one of %<since%>, %<note%>");
     177              :                     }
     178            0 :                 }
     179            0 :                 break;
     180              : 
     181            0 :               case AST::MetaItem::ItemKind::Path:
     182            0 :                 {
     183              :                   // #[deprecated(a,a)]
     184            0 :                   auto *p = static_cast<AST::MetaItemPath *> (meta_item);
     185              : 
     186            0 :                   std::string ident = p->get_path ().as_string ();
     187              : 
     188            0 :                   rust_error_at (p->get_locus (), "unknown meta item %qs",
     189              :                                  ident.c_str ());
     190            0 :                   rust_inform (p->get_locus (),
     191              :                                "expected one of %<since%>, %<note%>");
     192            0 :                 }
     193            0 :                 break;
     194              : 
     195            0 :               case AST::MetaItem::ItemKind::Word:
     196            0 :                 {
     197              :                   // #[deprecated("a")]
     198            0 :                   auto *w = static_cast<AST::MetaWord *> (meta_item);
     199              : 
     200            0 :                   rust_error_at (
     201            0 :                     w->get_locus (),
     202              :                     "item in %<deprecated%> must be a key/value pair");
     203              :                 }
     204            0 :                 break;
     205              : 
     206            0 :               case AST::MetaItem::ItemKind::PathExpr:
     207            0 :                 {
     208              :                   // #[deprecated(since=a)]
     209            0 :                   auto *px = static_cast<AST::MetaItemPathExpr *> (meta_item);
     210              : 
     211            0 :                   rust_error_at (
     212            0 :                     px->get_locus (),
     213              :                     "expected unsuffixed literal or identifier, found %qs",
     214            0 :                     px->get_expr ().as_string ().c_str ());
     215              :                 }
     216            0 :                 break;
     217              : 
     218            0 :               case AST::MetaItem::ItemKind::Seq:
     219            0 :               case AST::MetaItem::ItemKind::ListPaths:
     220            0 :               case AST::MetaItem::ItemKind::ListNameValueStr:
     221            0 :               default:
     222            0 :                 gcc_unreachable ();
     223            0 :                 break;
     224              :               }
     225              :           }
     226            0 :           break;
     227              : 
     228            0 :         case AST::MetaItemInner::Kind::LitExpr:
     229            0 :         default:
     230            0 :           gcc_unreachable ();
     231            0 :           break;
     232              :         }
     233              :     }
     234              : }
     235              : 
     236              : void
     237            2 : link_section (const AST::Attribute &attribute)
     238              : {
     239            2 :   if (!attribute.has_attr_input ())
     240              :     {
     241            1 :       rust_error_at (attribute.get_locus (),
     242              :                      "malformed %<link_section%> attribute input");
     243            1 :       rust_inform (attribute.get_locus (),
     244              :                    "must be of the form: %<#[link_section = \"name\"]%>");
     245              :     }
     246            2 : }
     247              : 
     248              : void
     249           11 : export_name (const AST::Attribute &attribute)
     250              : {
     251           11 :   if (!attribute.has_attr_input ())
     252              :     {
     253            2 :       rust_error_at (attribute.get_locus (),
     254              :                      "malformed %<export_name%> attribute input");
     255            2 :       rust_inform (attribute.get_locus (),
     256              :                    "must be of the form: %<#[export_name = \"name\"]%>");
     257            2 :       return;
     258              :     }
     259              : 
     260            9 :   auto &attr_input = attribute.get_attr_input ();
     261            9 :   if (attr_input.get_attr_input_type ()
     262              :       == AST::AttrInput::AttrInputType::LITERAL)
     263              :     {
     264            7 :       auto &literal_expr
     265            7 :         = static_cast<AST::AttrInputLiteral &> (attr_input).get_literal ();
     266            7 :       auto lit_type = literal_expr.get_lit_type ();
     267            7 :       switch (lit_type)
     268              :         {
     269              :         case AST::Literal::LitType::STRING:
     270              :         case AST::Literal::LitType::RAW_STRING:
     271              :         case AST::Literal::LitType::BYTE_STRING:
     272              :           return;
     273              :         default:
     274              :           break;
     275              :         }
     276              :     }
     277              : 
     278            4 :   rust_error_at (attribute.get_locus (), "attribute must be a string literal");
     279              : }
     280              : 
     281              : void
     282          775 : lint (const AST::Attribute &attribute)
     283              : {
     284          775 :   if (!attribute.has_attr_input ())
     285              :     {
     286            1 :       auto name = attribute.get_path ().as_string ();
     287            1 :       rust_error_at (attribute.get_locus (), "malformed %qs attribute input",
     288              :                      name.c_str ());
     289            1 :       rust_inform (attribute.get_locus (),
     290              :                    "must be of the form: %<#[%s(lint1, lint2, ...)]%>",
     291              :                    name.c_str ());
     292            1 :     }
     293          775 : }
     294              : 
     295              : void
     296          552 : link_name (const AST::Attribute &attribute)
     297              : {
     298          552 :   if (!attribute.has_attr_input ())
     299              :     {
     300            1 :       rust_error_at (attribute.get_locus (),
     301              :                      "malformed %<link_name%> attribute input");
     302            1 :       rust_inform (attribute.get_locus (),
     303              :                    "must be of the form: %<#[link_name = \"name\"]%>");
     304              :     }
     305          552 : }
     306              : 
     307              : namespace {
     308              : void
     309           58 : check_crate_type (const AST::Attribute &attribute)
     310              : {
     311           58 :   if (!Session::get_instance ().options.is_proc_macro ())
     312              :     {
     313            3 :       auto name = attribute.get_path ().as_string ();
     314              : 
     315            3 :       rust_error_at (attribute.get_locus (),
     316              :                      "the %<#[%s]%> attribute is only usable with crates of "
     317              :                      "the %<proc-macro%> crate type",
     318              :                      name.c_str ());
     319            3 :     }
     320           58 : }
     321              : } // namespace
     322              : 
     323              : static void
     324           20 : proc_macro_derive (const AST::Attribute &attribute)
     325              : {
     326           20 :   if (!attribute.has_attr_input ())
     327              :     {
     328            1 :       auto name = attribute.get_path ().as_string ();
     329            1 :       rust_error_at (attribute.get_locus (), "malformed %qs attribute input",
     330              :                      name.c_str ());
     331            1 :       rust_inform (attribute.get_locus (),
     332              :                    "must be of the form: %<#[proc_macro_derive(TraitName, "
     333              :                    "/*opt*/ attributes(name1, name2, ...))]%>");
     334            1 :     }
     335           20 :   check_crate_type (attribute);
     336           20 : }
     337              : 
     338              : static void
     339           38 : proc_macro (const AST::Attribute &attribute)
     340              : {
     341           38 :   check_crate_type (attribute);
     342           38 : }
     343              : 
     344              : static void
     345         1710 : target_feature (const AST::Attribute &attribute)
     346              : {
     347         1710 :   if (!attribute.has_attr_input ())
     348              :     {
     349            1 :       rust_error_at (attribute.get_locus (),
     350              :                      "malformed %<target_feature%> attribute input");
     351            1 :       rust_inform (attribute.get_locus (),
     352              :                    "must be of the form: %<#[target_feature(enable = "
     353              :                    "\"name\")]%>");
     354              :     }
     355         1710 : }
     356              : 
     357              : void
     358           17 : expect_no_input (const AST::Attribute &attribute)
     359              : {
     360           17 :   if (attribute.has_attr_input ())
     361              :     {
     362            5 :       std::string attr_name = attribute.get_path ().as_string ();
     363            5 :       rust_error_at (attribute.get_locus (), "malformed %<%s%> attribute input",
     364              :                      attr_name.c_str ());
     365            5 :       rust_inform (attribute.get_locus (), "must be of the form: %<#[%s]%>",
     366              :                    attr_name.c_str ());
     367            5 :     }
     368           17 : }
     369              : 
     370              : } // namespace handlers
     371              : 
     372              : const std::unordered_map<std::string, std::function<void (AST::Attribute &)>>
     373              :   attribute_checking_handlers = {
     374              :     {Attrs::DOC, handlers::doc},
     375              :     {Attrs::DEPRECATED, handlers::deprecated},
     376              :     {Attrs::LINK_SECTION, handlers::link_section},
     377              :     {Attrs::EXPORT_NAME, handlers::export_name},
     378              :     {Attrs::NO_MANGLE, handlers::expect_no_input},
     379              :     {Attrs::ALLOW, handlers::lint},
     380              :     {Attrs::DENY, handlers::lint},
     381              :     {Attrs::WARN, handlers::lint},
     382              :     {Attrs::FORBID, handlers::lint},
     383              :     {Attrs::LINK_NAME, handlers::link_name},
     384              :     {Attrs::PROC_MACRO_DERIVE, handlers::proc_macro_derive},
     385              :     {Attrs::PROC_MACRO, handlers::proc_macro},
     386              :     {Attrs::PROC_MACRO_ATTRIBUTE, handlers::proc_macro},
     387              :     {Attrs::TARGET_FEATURE, handlers::target_feature},
     388              :     {Attrs::RUSTC_STD_INTERNAL_SYMBOL, handlers::expect_no_input},
     389              :     {Attrs::RUSTC_ALLOCATOR, handlers::expect_no_input},
     390              :     {Attrs::RUSTC_ALLOCATOR_NOUNWIND, handlers::expect_no_input},
     391              :     {Attrs::GLOBAL_ALLOCATOR, handlers::expect_no_input},
     392              :     {Attrs::RUSTC_CONVERSION_SUGGESTION, handlers::expect_no_input},
     393              : };
     394              : 
     395              : tl::optional<std::function<void (AST::Attribute &)>>
     396       100854 : lookup_handler (std::string attr_name)
     397              : {
     398       100854 :   auto res = attribute_checking_handlers.find (attr_name);
     399       100854 :   if (res != attribute_checking_handlers.cend ())
     400        58695 :     return res->second;
     401        42159 :   return tl::nullopt;
     402              : }
     403              : 
     404              : static void
     405            3 : check_no_mangle_function (const AST::Attribute &attribute,
     406              :                           const AST::Function &fun)
     407              : {
     408            3 :   if (!is_ascii_only (fun.get_function_name ().as_string ()))
     409            0 :     rust_error_at (fun.get_function_name ().get_locus (),
     410              :                    "the %<#[no_mangle]%> attribute requires ASCII identifier");
     411            3 : }
     412              : 
     413              : /**
     414              :  * Emit an error when an attribute is attached
     415              :  * to an incompatable item type. e.g.:
     416              :  *
     417              :  * #[cold]
     418              :  * struct A(u8, u8);
     419              :  *
     420              :  * Note that "#[derive]" is handled
     421              :  * explicitly in rust-derive.cc
     422              :  */
     423              : void
     424        82656 : check_valid_attribute_for_item (const AST::Attribute &attr,
     425              :                                 const AST::Item &item)
     426              : {
     427       165312 :   if (item.get_item_kind () != AST::Item::Kind::Function
     428       186265 :       && (attr.get_path () == Values::Attributes::TARGET_FEATURE
     429       124560 :           || attr.get_path () == Values::Attributes::COLD
     430       103608 :           || attr.get_path () == Values::Attributes::INLINE))
     431              :     {
     432            1 :       rust_error_at (attr.get_locus (),
     433              :                      "the %<#[%s]%> attribute may only be applied to functions",
     434            2 :                      attr.get_path ().as_string ().c_str ());
     435              :     }
     436       165310 :   else if (attr.get_path () == Values::Attributes::REPR
     437          161 :            && item.get_item_kind () != AST::Item::Kind::Enum
     438          157 :            && item.get_item_kind () != AST::Item::Kind::Union
     439        82797 :            && item.get_item_kind () != AST::Item::Kind::Struct)
     440              :     {
     441            1 :       rust_error_at (attr.get_locus (),
     442              :                      "the %<#[%s]%> attribute may only be applied "
     443              :                      "to structs, enums and unions",
     444            2 :                      attr.get_path ().as_string ().c_str ());
     445              :     }
     446       165308 :   else if (attr.get_path () == Values::Attributes::GLOBAL_ALLOCATOR
     447        82654 :            && item.get_item_kind () != AST::Item::Kind::StaticItem)
     448              :     {
     449            1 :       rust_error_at (attr.get_locus (),
     450              :                      "the %<#[%s]%> attribute may only be applied "
     451              :                      "to static items",
     452            2 :                      attr.get_path ().as_string ().c_str ());
     453              :     }
     454        82653 :   else if (attr.get_path () == Values::Attributes::RUSTC_CONVERSION_SUGGESTION)
     455              :     {
     456            4 :       auto attr_path = attr.get_path ().as_string ();
     457            4 :       rust_warning_at (attr.get_locus (), 0,
     458              :                        "%<#[%s]%> is not implemented yet and has no effect",
     459              :                        attr_path.c_str ());
     460            4 :       if (item.get_item_kind () != AST::Item::Kind::Function)
     461              :         {
     462            3 :           rust_error_at (item.get_locus (),
     463              :                          "%<#[%s]%> can only be applied to functions",
     464              :                          attr_path.c_str ());
     465              :         }
     466            4 :     }
     467        82656 : }
     468              : 
     469         4845 : BuiltinAttributeChecker::BuiltinAttributeChecker () {}
     470              : 
     471              : void
     472         4845 : BuiltinAttributeChecker::go (AST::Crate &crate)
     473              : {
     474         4845 :   visit (crate);
     475         4845 : }
     476              : 
     477              : void
     478         4845 : BuiltinAttributeChecker::visit (AST::Crate &crate)
     479              : {
     480        17208 :   for (auto &attr : crate.get_inner_attrs ())
     481              :     {
     482        12363 :       check_inner_attribute (attr);
     483              :     }
     484              : 
     485         4845 :   AST::DefaultASTVisitor::visit (crate);
     486         4845 : }
     487              : 
     488              : void
     489       100854 : BuiltinAttributeChecker::visit (AST::Attribute &attribute)
     490              : {
     491       159549 :   lookup_handler (attribute.get_path ().as_string ()).map ([&] (auto handler) {
     492        58695 :     handler (attribute);
     493              :   });
     494       100854 :   AST::DefaultASTVisitor::visit (attribute);
     495       100854 : }
     496              : 
     497              : void
     498         1537 : BuiltinAttributeChecker::visit (AST::Module &module)
     499              : {
     500         1537 :   default_outer_attribute_check (module);
     501         1537 : }
     502              : 
     503              : void
     504           28 : BuiltinAttributeChecker::visit (AST::ExternCrate &extern_crate)
     505              : {
     506           28 :   default_outer_attribute_check (extern_crate);
     507           28 : }
     508              : 
     509              : void
     510         1376 : BuiltinAttributeChecker::visit (AST::UseDeclaration &declaration)
     511              : {
     512         1376 :   default_outer_attribute_check (declaration);
     513         1376 : }
     514              : 
     515              : void
     516        31475 : BuiltinAttributeChecker::visit (AST::Function &function)
     517              : {
     518        31475 :   BuiltinAttrDefinition result;
     519        93178 :   for (auto &attribute : function.get_outer_attrs ())
     520              :     {
     521        61703 :       check_valid_attribute_for_item (attribute, function);
     522              : 
     523        61703 :       auto result = lookup_builtin (attribute);
     524        61703 :       if (!result)
     525            0 :         return;
     526              : 
     527        61703 :       if (result->name == Attrs::TARGET_FEATURE)
     528              :         {
     529         1709 :           if (!function.get_qualifiers ().is_unsafe ())
     530              :             {
     531            1 :               rust_error_at (
     532              :                 attribute.get_locus (),
     533              :                 "the %<#[target_feature]%> attribute can only be applied "
     534              :                 "to %<unsafe%> functions");
     535              :             }
     536              :         }
     537        59994 :       else if (result->name == Attrs::NO_MANGLE)
     538              :         {
     539            3 :           check_no_mangle_function (attribute, function);
     540              :         }
     541        61703 :     }
     542              : 
     543        31475 :   AST::DefaultASTVisitor::visit (function);
     544        31475 : }
     545              : 
     546              : void
     547         3979 : BuiltinAttributeChecker::visit (AST::TypeAlias &alias)
     548              : {
     549         3979 :   default_outer_attribute_check (alias);
     550         3979 : }
     551              : 
     552              : void
     553         2286 : BuiltinAttributeChecker::visit (AST::StructStruct &struct_item)
     554              : {
     555         2286 :   default_outer_attribute_check (struct_item);
     556         2286 : }
     557              : 
     558              : void
     559         1088 : BuiltinAttributeChecker::visit (AST::TupleStruct &tuple_struct)
     560              : {
     561         1088 :   default_outer_attribute_check (tuple_struct);
     562         1088 : }
     563              : 
     564              : void
     565          597 : BuiltinAttributeChecker::visit (AST::Enum &enumeration)
     566              : {
     567          597 :   default_outer_attribute_check (enumeration);
     568          597 : }
     569              : 
     570              : void
     571          114 : BuiltinAttributeChecker::visit (AST::Union &u)
     572              : {
     573          114 :   default_outer_attribute_check (u);
     574          114 : }
     575              : 
     576              : void
     577         1304 : BuiltinAttributeChecker::visit (AST::ConstantItem &item)
     578              : {
     579         1304 :   default_outer_attribute_check (item);
     580         1304 : }
     581              : 
     582              : void
     583          103 : BuiltinAttributeChecker::visit (AST::StaticItem &item)
     584              : {
     585          116 :   for (auto &attr : item.get_outer_attrs ())
     586           13 :     check_valid_attribute_for_item (attr, item);
     587              : 
     588          103 :   AST::DefaultASTVisitor::visit (item);
     589          103 : }
     590              : 
     591              : void
     592         4139 : BuiltinAttributeChecker::visit (AST::Trait &trait)
     593              : {
     594         4139 :   default_outer_attribute_check (trait);
     595         4139 : }
     596              : 
     597              : void
     598         1298 : BuiltinAttributeChecker::visit (AST::InherentImpl &impl)
     599              : {
     600         1298 :   default_outer_attribute_check (impl);
     601         1298 : }
     602              : 
     603              : void
     604        11566 : BuiltinAttributeChecker::visit (AST::TraitImpl &impl)
     605              : {
     606        11566 :   default_outer_attribute_check (impl);
     607        11566 : }
     608              : 
     609              : void
     610         1729 : BuiltinAttributeChecker::visit (AST::ExternBlock &block)
     611              : {
     612         1729 :   default_outer_attribute_check (block);
     613         1729 : }
     614              : 
     615              : } // namespace Analysis
     616              : } // 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.