LCOV - code coverage report
Current view: top level - gcc - attr-handlers.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 85.1 % 309 263
Test Date: 2026-10-17 16:30:31 Functions: 95.7 % 23 22
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Language-independent attribute handlers shared across front ends.
       2              :    Copyright (C) 2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify it under
       7              : the terms of the GNU General Public License as published by the Free
       8              : Software Foundation; either version 3, or (at your option) any later
       9              : version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12              : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13              : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14              : for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : #include "config.h"
      21              : #include "system.h"
      22              : #include "coretypes.h"
      23              : #include "target.h"
      24              : #include "function.h"
      25              : #include "tree.h"
      26              : #include "stringpool.h"
      27              : #include "attribs.h"
      28              : #include "attr-handlers.h"
      29              : #include "diagnostic-core.h"
      30              : #include "options.h"
      31              : #include "cgraph.h"
      32              : #include "varasm.h"
      33              : #include "common/common-target.h"
      34              : #include "tree-pretty-print.h"
      35              : 
      36              : /* Helper to define attribute exclusions.  */
      37              : #define ATTR_EXCL(name, function, type, variable)       \
      38              :   { name, function, type, variable }
      39              : 
      40              : /* Define attributes that are mutually exclusive with one another.  */
      41              : const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
      42              : {
      43              :   ATTR_EXCL ("alloc_align", true, true, true),
      44              :   ATTR_EXCL ("alloc_size", true, true, true),
      45              :   ATTR_EXCL ("const", true, true, true),
      46              :   ATTR_EXCL ("malloc", true, true, true),
      47              :   ATTR_EXCL ("pure", true, true, true),
      48              :   ATTR_EXCL ("returns_twice", true, true, true),
      49              :   ATTR_EXCL ("warn_unused_result", true, true, true),
      50              :   ATTR_EXCL (NULL, false, false, false),
      51              : };
      52              : 
      53              : const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
      54              : {
      55              :   ATTR_EXCL ("noreturn", true, true, true),
      56              :   ATTR_EXCL (NULL, false, false, false),
      57              : };
      58              : 
      59              : /* Exclusions that apply to attribute alloc_align, alloc_size, and malloc.  */
      60              : const struct attribute_spec::exclusions attr_alloc_exclusions[] =
      61              : {
      62              :   ATTR_EXCL ("const", true, true, true),
      63              :   ATTR_EXCL ("noreturn", true, true, true),
      64              :   ATTR_EXCL ("pure", true, true, true),
      65              :   ATTR_EXCL (NULL, false, false, false),
      66              : };
      67              : 
      68              : const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
      69              : {
      70              :   ATTR_EXCL ("const", true, true, true),
      71              :   ATTR_EXCL ("alloc_align", true, true, true),
      72              :   ATTR_EXCL ("alloc_size", true, true, true),
      73              :   ATTR_EXCL ("malloc", true, true, true),
      74              :   ATTR_EXCL ("noreturn", true, true, true),
      75              :   ATTR_EXCL ("pure", true, true, true),
      76              :   ATTR_EXCL (NULL, false, false, false)
      77              : };
      78              : 
      79              : const struct attribute_spec::exclusions attr_always_inline_exclusions[] =
      80              : {
      81              :   ATTR_EXCL ("noinline", true, true, true),
      82              :   ATTR_EXCL ("target_clones", true, true, true),
      83              :   ATTR_EXCL (NULL, false, false, false),
      84              : };
      85              : 
      86              : const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
      87              : {
      88              :   ATTR_EXCL ("cold", true, true, true),
      89              :   ATTR_EXCL ("hot", true, true, true),
      90              :   ATTR_EXCL (NULL, false, false, false)
      91              : };
      92              : 
      93              : const struct attribute_spec::exclusions attr_noinline_exclusions[] =
      94              : {
      95              :   ATTR_EXCL ("always_inline", true, true, true),
      96              :   ATTR_EXCL ("gnu_inline", true, true, true),
      97              :   ATTR_EXCL (NULL, false, false, false),
      98              : };
      99              : 
     100              : const struct attribute_spec::exclusions attr_target_exclusions[] =
     101              : {
     102              :   ATTR_EXCL ("target_clones", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
     103              :              TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
     104              :   ATTR_EXCL (NULL, false, false, false),
     105              : };
     106              : 
     107              : /* Exclusions that apply to attributes that put declarations in specific
     108              :    sections.  */
     109              : const struct attribute_spec::exclusions attr_section_exclusions[] =
     110              : {
     111              :   ATTR_EXCL ("noinit", true, true, true),
     112              :   ATTR_EXCL ("persistent", true, true, true),
     113              :   ATTR_EXCL ("section", true, true, true),
     114              :   ATTR_EXCL (NULL, false, false, false),
     115              : };
     116              : 
     117              : /* Return the first of DECL or TYPE attributes installed in NODE if it's
     118              :    a DECL, or TYPE attributes if it's a TYPE, or null otherwise.  */
     119              : 
     120              : static tree
     121      2635459 : decl_or_type_attrs (tree node)
     122              : {
     123      2635459 :   if (DECL_P (node))
     124              :     {
     125       137695 :       if (tree attrs = DECL_ATTRIBUTES (node))
     126              :         return attrs;
     127              : 
     128        57347 :       tree type = TREE_TYPE (node);
     129        57347 :       if (type == error_mark_node)
     130              :         return NULL_TREE;
     131        57346 :       return TYPE_ATTRIBUTES (type);
     132              :     }
     133              : 
     134      2497764 :   if (TYPE_P (node))
     135      2497764 :     return TYPE_ATTRIBUTES (node);
     136              : 
     137              :   return NULL_TREE;
     138              : }
     139              : 
     140              : /* Given a pair of NODEs for arbitrary DECLs or TYPEs, validate one or
     141              :    two integral or string attribute arguments NEWARGS to be applied to
     142              :    NODE[0] for the absence of conflicts with the same attribute arguments
     143              :    already applied to NODE[1]. Issue a warning for conflicts and return
     144              :    false.  Otherwise, when no conflicts are found, return true.  */
     145              : 
     146              : bool
     147      4996498 : validate_attr_args (tree node[2], tree name, tree newargs[2])
     148              : {
     149              :   /* First validate the arguments against those already applied to
     150              :      the same declaration (or type).  */
     151      4996498 :   tree self[2] = { node[0], node[0] };
     152      4996498 :   if (node[0] != node[1] && !validate_attr_args (self, name, newargs))
     153              :     return false;
     154              : 
     155      4996462 :   if (!node[1])
     156              :     return true;
     157              : 
     158              :   /* Extract the same attribute from the previous declaration or type.  */
     159      2635459 :   tree prevattr = decl_or_type_attrs (node[1]);
     160      2635459 :   const char* const namestr = IDENTIFIER_POINTER (name);
     161      2635459 :   prevattr = lookup_attribute (namestr, prevattr);
     162      2635459 :   if (!prevattr)
     163              :     return true;
     164              : 
     165              :   /* Extract one or both attribute arguments.  */
     166        28618 :   tree prevargs[2];
     167        28618 :   prevargs[0] = TREE_VALUE (TREE_VALUE (prevattr));
     168        28618 :   prevargs[1] = TREE_CHAIN (TREE_VALUE (prevattr));
     169        28618 :   if (prevargs[1])
     170           33 :     prevargs[1] = TREE_VALUE (prevargs[1]);
     171              : 
     172              :   /* Both arguments must be equal or, for the second pair, neither must
     173              :      be provided to succeed.  */
     174        28618 :   bool arg1eq, arg2eq;
     175        28618 :   if (TREE_CODE (newargs[0]) == INTEGER_CST)
     176              :     {
     177        28609 :       arg1eq = tree_int_cst_equal (newargs[0], prevargs[0]);
     178        28609 :       if (newargs[1] && prevargs[1])
     179           16 :         arg2eq = tree_int_cst_equal (newargs[1], prevargs[1]);
     180              :       else
     181        28593 :         arg2eq = newargs[1] == prevargs[1];
     182              :     }
     183            9 :   else if (TREE_CODE (newargs[0]) == STRING_CST)
     184              :     {
     185            9 :       const char *s0 = TREE_STRING_POINTER (newargs[0]);
     186            9 :       const char *s1 = TREE_STRING_POINTER (prevargs[0]);
     187            9 :       arg1eq = strcmp (s0, s1) == 0;
     188            9 :       if (newargs[1] && prevargs[1])
     189              :         {
     190            0 :           s0 = TREE_STRING_POINTER (newargs[1]);
     191            0 :           s1 = TREE_STRING_POINTER (prevargs[1]);
     192            0 :           arg2eq = strcmp (s0, s1) == 0;
     193              :         }
     194              :       else
     195            9 :         arg2eq = newargs[1] == prevargs[1];
     196              :     }
     197              :   else
     198            0 :     gcc_unreachable ();
     199              : 
     200        28618 :   if (arg1eq && arg2eq)
     201              :     return true;
     202              : 
     203              :   /* If the two locations are different print a note pointing to
     204              :      the previous one.  */
     205           48 :   const location_t curloc = input_location;
     206           48 :   const location_t prevloc
     207           48 :     = DECL_P (node[1]) ? DECL_SOURCE_LOCATION (node[1]) : curloc;
     208              : 
     209              :   /* Format the attribute specification for convenience.  */
     210           48 :   char newspec[80], prevspec[80];
     211           48 :   if (newargs[1])
     212            2 :     snprintf (newspec, sizeof newspec, "%s (%s, %s)", namestr,
     213              :               print_generic_expr_to_str (newargs[0]),
     214              :               print_generic_expr_to_str (newargs[1]));
     215              :   else
     216           46 :     snprintf (newspec, sizeof newspec, "%s (%s)", namestr,
     217              :               print_generic_expr_to_str (newargs[0]));
     218              : 
     219           48 :   if (prevargs[1])
     220           17 :     snprintf (prevspec, sizeof prevspec, "%s (%s, %s)", namestr,
     221              :               print_generic_expr_to_str (prevargs[0]),
     222              :               print_generic_expr_to_str (prevargs[1]));
     223              :   else
     224           31 :     snprintf (prevspec, sizeof prevspec, "%s (%s)", namestr,
     225              :               print_generic_expr_to_str (prevargs[0]));
     226              : 
     227           84 :   if (warning_at (curloc, OPT_Wattributes,
     228              :                   "ignoring attribute %qs because it conflicts "
     229              :                   "with previous %qs",
     230              :                   newspec, prevspec)
     231           48 :       && curloc != prevloc)
     232           12 :     inform (prevloc, "previous declaration here");
     233              : 
     234              :   return false;
     235              : }
     236              : 
     237              : /* Convenience wrapper for validate_attr_args to validate a single
     238              :    attribute argument.  Used by handlers for attributes that take
     239              :    just a single argument.  */
     240              : 
     241              : bool
     242       104939 : validate_attr_arg (tree node[2], tree name, tree newarg)
     243              : {
     244       104939 :   tree argarray[2] = { newarg, NULL_TREE };
     245       104939 :   return validate_attr_args (node, name, argarray);
     246              : }
     247              : 
     248              : /* Handle an "alias" or "ifunc" attribute; arguments as in
     249              :    struct attribute_spec.handler, except that IS_ALIAS tells us
     250              :    whether this is an alias as opposed to ifunc attribute.  */
     251              : 
     252              : tree
     253         5711 : handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args,
     254              :                               bool *no_add_attrs)
     255              : {
     256         5711 :   tree decl = *node;
     257              : 
     258         5711 :   if (TREE_CODE (decl) != FUNCTION_DECL
     259          202 :       && (!is_alias || !VAR_P (decl)))
     260              :     {
     261            1 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     262            1 :       *no_add_attrs = true;
     263              :     }
     264         5509 :   else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
     265         5710 :       || (TREE_CODE (decl) != FUNCTION_DECL
     266          201 :           && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
     267              :       /* A static variable declaration is always a tentative definition,
     268              :          but the alias is a non-tentative definition which overrides.  */
     269        11420 :       || (TREE_CODE (decl) != FUNCTION_DECL
     270          201 :           && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
     271              :     {
     272            0 :       error ("%q+D defined both normally and as %qE attribute", decl, name);
     273            0 :       *no_add_attrs = true;
     274            0 :       return NULL_TREE;
     275              :     }
     276         5710 :   else if (!is_alias
     277         5710 :            && (lookup_attribute ("weak", DECL_ATTRIBUTES (decl))
     278          117 :                || lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))))
     279              :     {
     280            1 :       error ("weak %q+D cannot be defined %qE", decl, name);
     281            1 :       *no_add_attrs = true;
     282            1 :       return NULL_TREE;
     283              :     }
     284              : 
     285              :   /* Note that the very first time we process a nested declaration,
     286              :      decl_function_context will not be set.  Indeed, *would* never
     287              :      be set except for the DECL_INITIAL/DECL_EXTERNAL frobbery that
     288              :      we do below.  After such frobbery, pushdecl would set the context.
     289              :      In any case, this is never what we want.  */
     290         5709 :   else if (decl_function_context (decl) == 0 && current_function_decl == NULL)
     291              :     {
     292         5702 :       tree id;
     293              : 
     294         5702 :       id = TREE_VALUE (args);
     295         5702 :       if (TREE_CODE (id) != STRING_CST)
     296              :         {
     297            0 :           error ("attribute %qE argument not a string", name);
     298            0 :           *no_add_attrs = true;
     299            0 :           return NULL_TREE;
     300              :         }
     301         5702 :       id = get_identifier (TREE_STRING_POINTER (id));
     302              :       /* This counts as a use of the object pointed to.  */
     303         5702 :       TREE_USED (id) = 1;
     304              : 
     305         5702 :       if (TREE_CODE (decl) == FUNCTION_DECL)
     306         5501 :         DECL_INITIAL (decl) = error_mark_node;
     307              :       else
     308          201 :         TREE_STATIC (decl) = 1;
     309              : 
     310         5702 :       if (!is_alias)
     311              :         {
     312              :           /* ifuncs are also aliases, so set that attribute too.  */
     313          117 :           DECL_ATTRIBUTES (decl)
     314          117 :             = tree_cons (get_identifier ("alias"), args,
     315          117 :                          DECL_ATTRIBUTES (decl));
     316          117 :           DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("ifunc"),
     317          117 :                                               NULL, DECL_ATTRIBUTES (decl));
     318              :         }
     319              :     }
     320              :   else
     321              :     {
     322            7 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     323            7 :       *no_add_attrs = true;
     324              :     }
     325              : 
     326         5710 :   if (decl_in_symtab_p (*node))
     327              :     {
     328         5709 :       struct symtab_node *n = symtab_node::get (decl);
     329         5709 :       if (n && n->refuse_visibility_changes)
     330            0 :         error ("%+qD declared %qs after being used",
     331              :                decl, is_alias ? "alias" : "ifunc");
     332              :     }
     333              : 
     334              :   return NULL_TREE;
     335              : }
     336              : 
     337              : /* Ignore the given attribute.  Used when this attribute may be usefully
     338              :    overridden by the target, but is not used generically.  */
     339              : 
     340              : tree
     341            0 : ignore_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name),
     342              :                   tree ARG_UNUSED (args), int ARG_UNUSED (flags),
     343              :                   bool *no_add_attrs)
     344              : {
     345            0 :   *no_add_attrs = true;
     346            0 :   return NULL_TREE;
     347              : }
     348              : 
     349              : /* Handle a "leaf" attribute; arguments as in
     350              :    struct attribute_spec.handler.  */
     351              : 
     352              : tree
     353    438739378 : handle_leaf_attribute (tree *node, tree name,
     354              :                        tree ARG_UNUSED (args),
     355              :                        int ARG_UNUSED (flags), bool *no_add_attrs)
     356              : {
     357    438739378 :   if (TREE_CODE (*node) != FUNCTION_DECL)
     358              :     {
     359            0 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     360            0 :       *no_add_attrs = true;
     361              :     }
     362    438739378 :   if (!TREE_PUBLIC (*node))
     363              :     {
     364            7 :       warning (OPT_Wattributes, "%qE attribute has no effect on unit local "
     365              :                "functions", name);
     366            7 :       *no_add_attrs = true;
     367              :     }
     368              : 
     369    438739378 :   return NULL_TREE;
     370              : }
     371              : 
     372              : /* Handle a "const" attribute; arguments as in
     373              :    struct attribute_spec.handler.  */
     374              : 
     375              : tree
     376    187775157 : handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args),
     377              :                         int flags, bool *no_add_attrs)
     378              : {
     379    187775157 :   tree type = TREE_TYPE (*node);
     380              : 
     381              :   /* See FIXME comment on noreturn in c_common_attribute_table.  */
     382    187775157 :   if (TREE_CODE (*node) == FUNCTION_DECL)
     383    187775121 :     TREE_READONLY (*node) = 1;
     384           36 :   else if (TREE_CODE (type) == POINTER_TYPE
     385           36 :            && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
     386           31 :     TREE_TYPE (*node)
     387           31 :       = (build_qualified_type
     388           31 :          (build_pointer_type
     389           62 :           (build_type_variant (TREE_TYPE (type), 1,
     390              :                                TREE_THIS_VOLATILE (TREE_TYPE (type)))),
     391           31 :           TYPE_QUALS (type)));
     392              :   else
     393              :     {
     394            5 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     395            5 :       *no_add_attrs = true;
     396              :     }
     397              : 
     398              :   /* void __builtin_unreachable (void) is const.  Accept other such
     399              :      built-ins but warn on user-defined functions that return void.  */
     400    187775157 :   if (!(flags & ATTR_FLAG_BUILT_IN)
     401      3221299 :       && TREE_CODE (*node) == FUNCTION_DECL
     402    190996420 :       && VOID_TYPE_P (TREE_TYPE (type)))
     403           14 :     warning (OPT_Wattributes, "%qE attribute on function "
     404              :              "returning %<void%>", name);
     405              : 
     406    187775157 :   return NULL_TREE;
     407              : }
     408              : 
     409              : /* Handle a "pure" attribute; arguments as in
     410              :    struct attribute_spec.handler.  */
     411              : 
     412              : tree
     413     20484103 : handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args),
     414              :                        int ARG_UNUSED (flags), bool *no_add_attrs)
     415              : {
     416     20484103 :   if (TREE_CODE (*node) == FUNCTION_DECL)
     417              :     {
     418     20484103 :       tree type = TREE_TYPE (*node);
     419     20484103 :       if (VOID_TYPE_P (TREE_TYPE (type)))
     420            3 :         warning (OPT_Wattributes, "%qE attribute on function "
     421              :                  "returning %<void%>", name);
     422              : 
     423     20484103 :       DECL_PURE_P (*node) = 1;
     424              :       /* ??? TODO: Support types.  */
     425              :     }
     426              :   else
     427              :     {
     428            0 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     429            0 :       *no_add_attrs = true;
     430              :     }
     431              : 
     432     20484103 :   return NULL_TREE;
     433              : }
     434              : 
     435              : /* Handle a "no vops" attribute; arguments as in
     436              :    struct attribute_spec.handler.  */
     437              : 
     438              : tree
     439      1710783 : handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
     440              :                          tree ARG_UNUSED (args), int ARG_UNUSED (flags),
     441              :                          bool *ARG_UNUSED (no_add_attrs))
     442              : {
     443      1710783 :   gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
     444      1710783 :   DECL_IS_NOVOPS (*node) = 1;
     445      1710783 :   return NULL_TREE;
     446              : }
     447              : 
     448              : /* Handle a "nothrow" attribute; arguments as in
     449              :    struct attribute_spec.handler.  */
     450              : 
     451              : tree
     452    450752458 : handle_nothrow_attribute (tree *node, tree name, tree ARG_UNUSED (args),
     453              :                           int ARG_UNUSED (flags), bool *no_add_attrs)
     454              : {
     455    450752458 :   if (TREE_CODE (*node) == FUNCTION_DECL)
     456    450752458 :     TREE_NOTHROW (*node) = 1;
     457              :   /* ??? TODO: Support types.  */
     458              :   else
     459              :     {
     460            0 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     461            0 :       *no_add_attrs = true;
     462              :     }
     463              : 
     464    450752458 :   return NULL_TREE;
     465              : }
     466              : 
     467              : /* Handle a "type_generic" attribute.  */
     468              : 
     469              : tree
     470      6705677 : handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
     471              :                                tree ARG_UNUSED (args), int ARG_UNUSED (flags),
     472              :                                bool * ARG_UNUSED (no_add_attrs))
     473              : {
     474              :   /* Ensure we have a function type.  */
     475      6705677 :   gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
     476              : 
     477              :   /* Ensure we have a variadic function.  */
     478      6705677 :   gcc_assert (!prototype_p (*node) || stdarg_p (*node));
     479              : 
     480      6705677 :   return NULL_TREE;
     481              : }
     482              : 
     483              : /* Handle a "returns_twice" attribute.  */
     484              : 
     485              : tree
     486       228290 : handle_returns_twice_attribute (tree *node, tree name, tree ARG_UNUSED (args),
     487              :                          int ARG_UNUSED (flags), bool *no_add_attrs)
     488              : {
     489       228290 :   if (TREE_CODE (*node) == FUNCTION_DECL)
     490       228290 :     DECL_IS_RETURNS_TWICE (*node) = 1;
     491              :   else
     492              :     {
     493            0 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     494            0 :       *no_add_attrs = true;
     495              :     }
     496              : 
     497       228290 :   return NULL_TREE;
     498              : }
     499              : 
     500              : /* Handle a "fn spec" attribute; arguments as in
     501              :    struct attribute_spec.handler.  */
     502              : 
     503              : tree
     504    135493648 : handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
     505              :                          tree args, int ARG_UNUSED (flags),
     506              :                          bool *no_add_attrs ATTRIBUTE_UNUSED)
     507              : {
     508    270987296 :   gcc_assert (args
     509              :               && TREE_CODE (TREE_VALUE (args)) == STRING_CST
     510              :               && !TREE_CHAIN (args));
     511    135493648 :   return NULL_TREE;
     512              : }
     513              : 
     514              : /* Handle an "visibility" attribute; arguments as in
     515              :    struct attribute_spec.handler.  */
     516              : 
     517              : tree
     518       695910 : handle_visibility_attribute (tree *node, tree name, tree args,
     519              :                              int ARG_UNUSED (flags),
     520              :                              bool *ARG_UNUSED (no_add_attrs))
     521              : {
     522       695910 :   tree decl = *node;
     523       695910 :   tree id = TREE_VALUE (args);
     524       695910 :   enum symbol_visibility vis;
     525              : 
     526       695910 :   if (TYPE_P (*node))
     527              :     {
     528          130 :       if (TREE_CODE (*node) == ENUMERAL_TYPE)
     529              :         /* OK.  */;
     530          127 :       else if (!RECORD_OR_UNION_TYPE_P (*node))
     531              :         {
     532            2 :           warning (OPT_Wattributes, "%qE attribute ignored on non-class types",
     533              :                    name);
     534            2 :           return NULL_TREE;
     535              :         }
     536          125 :       else if (TYPE_FIELDS (*node))
     537              :         {
     538            0 :           error ("%qE attribute ignored because %qT is already defined",
     539              :                  name, *node);
     540            0 :           return NULL_TREE;
     541              :         }
     542              :     }
     543       695780 :   else if (decl_function_context (decl) != 0 || !TREE_PUBLIC (decl))
     544              :     {
     545            0 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     546            0 :       return NULL_TREE;
     547              :     }
     548              : 
     549       695908 :   if (TREE_CODE (id) != STRING_CST)
     550              :     {
     551            0 :       error ("visibility argument not a string");
     552            0 :       return NULL_TREE;
     553              :     }
     554              : 
     555              :   /*  If this is a type, set the visibility on the type decl.  */
     556       695908 :   if (TYPE_P (decl))
     557              :     {
     558          128 :       decl = TYPE_NAME (decl);
     559          128 :       if (!decl)
     560              :         return NULL_TREE;
     561          128 :       if (TREE_CODE (decl) == IDENTIFIER_NODE)
     562              :         {
     563            1 :            warning (OPT_Wattributes, "%qE attribute ignored on types",
     564              :                     name);
     565            1 :            return NULL_TREE;
     566              :         }
     567              :     }
     568              : 
     569       695907 :   if (strcmp (TREE_STRING_POINTER (id), "default") == 0)
     570              :     vis = VISIBILITY_DEFAULT;
     571       638181 :   else if (strcmp (TREE_STRING_POINTER (id), "internal") == 0)
     572              :     vis = VISIBILITY_INTERNAL;
     573       638121 :   else if (strcmp (TREE_STRING_POINTER (id), "hidden") == 0)
     574              :     vis = VISIBILITY_HIDDEN;
     575           66 :   else if (strcmp (TREE_STRING_POINTER (id), "protected") == 0)
     576              :     vis = VISIBILITY_PROTECTED;
     577              :   else
     578              :     {
     579            0 :       error ("attribute %qE argument must be one of %qs, %qs, %qs, or %qs",
     580              :              name, "default", "hidden", "protected", "internal");
     581            0 :       vis = VISIBILITY_DEFAULT;
     582              :     }
     583              : 
     584       695907 :   if (DECL_VISIBILITY_SPECIFIED (decl)
     585       695907 :       && vis != DECL_VISIBILITY (decl))
     586              :     {
     587           21 :       tree attributes = (TYPE_P (*node)
     588           21 :                          ? TYPE_ATTRIBUTES (*node)
     589           21 :                          : DECL_ATTRIBUTES (decl));
     590           21 :       if (lookup_attribute ("visibility", attributes))
     591            3 :         error ("%qD redeclared with different visibility", decl);
     592              :       else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
     593              :                && lookup_attribute ("dllimport", attributes))
     594              :         error ("%qD was declared %qs which implies default visibility",
     595              :                decl, "dllimport");
     596              :       else if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
     597              :                && lookup_attribute ("dllexport", attributes))
     598              :         error ("%qD was declared %qs which implies default visibility",
     599              :                decl, "dllexport");
     600              :     }
     601              : 
     602       695907 :   DECL_VISIBILITY (decl) = vis;
     603       695907 :   DECL_VISIBILITY_SPECIFIED (decl) = 1;
     604              : 
     605              :   /* Go ahead and attach the attribute to the node as well.  This is needed
     606              :      so we can determine whether we have VISIBILITY_DEFAULT because the
     607              :      visibility was not specified, or because it was explicitly overridden
     608              :      from the containing scope.  */
     609              : 
     610       695907 :   return NULL_TREE;
     611              : }
     612              : 
     613              : /* Handle a "always_inline" attribute; arguments as in
     614              :    struct attribute_spec.handler.  */
     615              : 
     616              : tree
     617     43189130 : handle_always_inline_attribute (tree *node, tree name,
     618              :                                 tree ARG_UNUSED (args),
     619              :                                 int ARG_UNUSED (flags),
     620              :                                 bool *no_add_attrs)
     621              : {
     622     43189130 :   if (TREE_CODE (*node) == FUNCTION_DECL)
     623              :     {
     624              :       /* Set the attribute and mark it for disregarding inline
     625              :          limits.  */
     626     43189130 :       DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
     627              :     }
     628              :   else
     629              :     {
     630            0 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     631            0 :       *no_add_attrs = true;
     632              :     }
     633              : 
     634     43189130 :   return NULL_TREE;
     635              : }
     636              : 
     637              : /* Handle a "noinline" attribute; arguments as in
     638              :    struct attribute_spec.handler.  */
     639              : 
     640              : tree
     641       909793 : handle_noinline_attribute (tree *node, tree name,
     642              :                            tree ARG_UNUSED (args),
     643              :                            int ARG_UNUSED (flags), bool *no_add_attrs)
     644              : {
     645       909793 :   if (TREE_CODE (*node) == FUNCTION_DECL)
     646       909785 :     DECL_UNINLINABLE (*node) = 1;
     647              :   else
     648              :     {
     649            8 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     650            8 :       *no_add_attrs = true;
     651              :     }
     652              : 
     653       909793 :   return NULL_TREE;
     654              : }
     655              : 
     656              : /* Handle a "weak" attribute; arguments as in
     657              :    struct attribute_spec.handler.  */
     658              : 
     659              : tree
     660         9087 : handle_weak_attribute (tree *node, tree name,
     661              :                        tree ARG_UNUSED (args),
     662              :                        int ARG_UNUSED (flags),
     663              :                        bool * ARG_UNUSED (no_add_attrs))
     664              : {
     665         9087 :   if (TREE_CODE (*node) == FUNCTION_DECL
     666         9087 :       && DECL_DECLARED_INLINE_P (*node))
     667              :     {
     668            1 :       warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
     669            1 :       *no_add_attrs = true;
     670              :     }
     671         9086 :   else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (*node)))
     672              :     {
     673            1 :       error ("indirect function %q+D cannot be declared weak", *node);
     674            1 :       *no_add_attrs = true;
     675            1 :       return NULL_TREE;
     676              :     }
     677         9085 :   else if (VAR_OR_FUNCTION_DECL_P (*node))
     678         9080 :     declare_weak (*node);
     679              :   else
     680            5 :     warning (OPT_Wattributes, "%qE attribute ignored", name);
     681              : 
     682              :   return NULL_TREE;
     683              : }
     684              : 
     685              : /* Handle a "target" attribute.  */
     686              : 
     687              : tree
     688     24940633 : handle_target_attribute (tree *node, tree name, tree args, int flags,
     689              :                          bool *no_add_attrs)
     690              : {
     691              :   /* Ensure we have a function declaration.  */
     692     24940633 :   if (TREE_CODE (*node) != FUNCTION_DECL)
     693              :     {
     694            1 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     695            1 :       *no_add_attrs = true;
     696              :     }
     697     24940632 :   else if (! targetm.target_option.valid_attribute_p (*node, name, args,
     698              :                                                       flags))
     699          123 :     *no_add_attrs = true;
     700              : 
     701              :   /* Check that there's no empty string in values of the attribute.  */
     702     50681602 :   for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
     703              :     {
     704     25740969 :       tree value = TREE_VALUE (t);
     705     25740969 :       if (TREE_CODE (value) == STRING_CST
     706     25740960 :           && TREE_STRING_LENGTH (value) == 1
     707     25740978 :           && TREE_STRING_POINTER (value)[0] == '\0')
     708              :         {
     709            9 :           warning (OPT_Wattributes, "empty string in attribute %<target%>");
     710            9 :           *no_add_attrs = true;
     711              :         }
     712              :     }
     713              : 
     714     24940633 :   return NULL_TREE;
     715              : }
     716              : 
     717              : /* Handle a "used" attribute; arguments as in
     718              :    struct attribute_spec.handler.  */
     719              : 
     720              : tree
     721         1810 : handle_used_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
     722              :                        int ARG_UNUSED (flags), bool *no_add_attrs)
     723              : {
     724         1810 :   tree node = *pnode;
     725              : 
     726         1810 :   if (TREE_CODE (node) == FUNCTION_DECL
     727          960 :       || (VAR_P (node) && TREE_STATIC (node))
     728           34 :       || (TREE_CODE (node) == TYPE_DECL))
     729              :     {
     730         1791 :       TREE_USED (node) = 1;
     731         1791 :       DECL_PRESERVE_P (node) = 1;
     732         1791 :       if (VAR_P (node))
     733          926 :         DECL_READ_P (node) = 1;
     734              :     }
     735              :   else
     736              :     {
     737           19 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     738           19 :       *no_add_attrs = true;
     739              :     }
     740              : 
     741         1810 :   return NULL_TREE;
     742              : }
     743              : 
     744              : /* Handle an "alias" or "ifunc" attribute; arguments as in
     745              :    struct attribute_spec.handler.  */
     746              : 
     747              : tree
     748         5593 : handle_alias_attribute (tree *node, tree name, tree args,
     749              :                         int ARG_UNUSED (flags), bool *no_add_attrs)
     750              : {
     751         5593 :   return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs);
     752              : }
     753              : 
     754              : /* Handle a "section" attribute; arguments as in
     755              :    struct attribute_spec.handler.  */
     756              : 
     757              : tree
     758          487 : handle_section_attribute (tree *node, tree name, tree args,
     759              :                           int flags, bool *no_add_attrs)
     760              : {
     761          487 :   tree decl = *node;
     762          487 :   tree res = NULL_TREE;
     763          487 :   tree argval = TREE_VALUE (args);
     764          487 :   const char* new_section_name;
     765              : 
     766          487 :   if (!targetm_common.have_named_sections)
     767              :     {
     768            0 :       error_at (DECL_SOURCE_LOCATION (*node),
     769              :                 "section attributes are not supported for this target");
     770            0 :       goto fail;
     771              :     }
     772              : 
     773          487 :   if (!VAR_OR_FUNCTION_DECL_P (decl))
     774              :     {
     775            0 :       error ("section attribute not allowed for %q+D", *node);
     776            0 :       goto fail;
     777              :     }
     778              : 
     779          487 :   if (TREE_CODE (argval) != STRING_CST)
     780              :     {
     781            0 :       error ("section attribute argument not a string constant");
     782            0 :       goto fail;
     783              :     }
     784              : 
     785          487 :   if (VAR_P (decl)
     786          374 :       && current_function_decl != NULL_TREE
     787           32 :       && !TREE_STATIC (decl))
     788              :     {
     789            0 :       error_at (DECL_SOURCE_LOCATION (decl),
     790              :                 "section attribute cannot be specified for local variables");
     791            0 :       goto fail;
     792              :     }
     793              : 
     794          487 :   new_section_name = TREE_STRING_POINTER (argval);
     795              : 
     796              :   /* The decl may have already been given a section attribute
     797              :      from a previous declaration.  Ensure they match.  */
     798          487 :   if (const char* const old_section_name = DECL_SECTION_NAME (decl))
     799            2 :     if (strcmp (old_section_name, new_section_name) != 0)
     800              :       {
     801            2 :         error ("section of %q+D conflicts with previous declaration",
     802              :                *node);
     803            2 :         goto fail;
     804              :       }
     805              : 
     806          485 :   if (VAR_P (decl)
     807          374 :       && !targetm.have_tls && targetm.emutls.tmpl_section
     808          485 :       && DECL_THREAD_LOCAL_P (decl))
     809              :     {
     810            0 :       error ("section of %q+D cannot be overridden", *node);
     811            0 :       goto fail;
     812              :     }
     813              : 
     814          485 :   if (!validate_attr_arg (node, name, argval))
     815            1 :     goto fail;
     816              : 
     817          484 :   res = targetm.handle_generic_attribute (node, name, args, flags,
     818              :                                           no_add_attrs);
     819              : 
     820              :   /* If the back end confirms the attribute can be added then continue onto
     821              :      final processing.  */
     822          484 :   if (!(*no_add_attrs))
     823              :     {
     824          484 :       set_decl_section_name (decl, new_section_name);
     825          484 :       return res;
     826              :     }
     827              : 
     828            0 : fail:
     829            3 :   *no_add_attrs = true;
     830            3 :   return res;
     831              : }
     832              : 
     833              : /* Handle a "retain" attribute; arguments as in
     834              :    struct attribute_spec.handler.  */
     835              : 
     836              : tree
     837          262 : handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args),
     838              :                          int ARG_UNUSED (flags), bool *no_add_attrs)
     839              : {
     840          262 :   tree node = *pnode;
     841              : 
     842          262 :   if (SUPPORTS_SHF_GNU_RETAIN
     843          262 :       && (TREE_CODE (node) == FUNCTION_DECL
     844          186 :           || (VAR_P (node) && TREE_STATIC (node))))
     845              :     ;
     846              :   else
     847              :     {
     848            4 :       warning (OPT_Wattributes, "%qE attribute ignored", name);
     849            4 :       *no_add_attrs = true;
     850              :     }
     851              : 
     852          262 :   return NULL_TREE;
     853              : }
     854              : 
     855              : /* Part of the `malloc` attribute handling which is shared by libgccjit and
     856              :    the C-family front-end.  */
     857              : 
     858              : tree
     859      3010410 : handle_malloc_common (tree *node, tree name, tree ARG_UNUSED (args),
     860              :                       int ARG_UNUSED (flags), bool *no_add_attrs)
     861              : {
     862      3010410 :   if (TREE_CODE (*node) != FUNCTION_DECL)
     863              :     {
     864            0 :       warning (OPT_Wattributes, "%qE attribute ignored; valid only "
     865              :                "for functions", name);
     866            0 :       *no_add_attrs = true;
     867            0 :       return NULL_TREE;
     868              :     }
     869              : 
     870      3010410 :   tree rettype = TREE_TYPE (TREE_TYPE (*node));
     871      3010410 :   if (!POINTER_TYPE_P (rettype))
     872              :     {
     873            4 :       warning (OPT_Wattributes, "%qE attribute ignored on functions "
     874              :                "returning %qT; valid only for pointer return types",
     875              :                name, rettype);
     876            4 :       *no_add_attrs = true;
     877            4 :       return NULL_TREE;
     878              :     }
     879              : 
     880      3010406 :   DECL_IS_MALLOC (*node) = 1;
     881      3010406 :   return NULL_TREE;
     882              : }
        

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.