1 /* Functions dealing with attribute handling, used by most front ends. 2 Copyright (C) 1992-2022 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 #define INCLUDE_STRING 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "target.h" 25 #include "tree.h" 26 #include "stringpool.h" 27 #include "diagnostic-core.h" 28 #include "attribs.h" 29 #include "fold-const.h" 30 #include "stor-layout.h" 31 #include "langhooks.h" 32 #include "plugin.h" 33 #include "selftest.h" 34 #include "hash-set.h" 35 #include "diagnostic.h" 36 #include "pretty-print.h" 37 #include "tree-pretty-print.h" 38 #include "intl.h" 39 40 /* Table of the tables of attributes (common, language, format, machine) 41 searched. */ 42 static const struct attribute_spec *attribute_tables[4]; 43 44 /* Substring representation. */ 45 46 struct substring 47 { 48 const char *str; 49 int length; 50 }; 51 52 /* Simple hash function to avoid need to scan whole string. */ 53 54 static inline hashval_t 55 substring_hash (const char *str, int l) 56 { 57 return str[0] + str[l - 1] * 256 + l * 65536; 58 } 59 60 /* Used for attribute_hash. */ 61 62 struct attribute_hasher : nofree_ptr_hash <attribute_spec> 63 { 64 typedef substring *compare_type; 65 static inline hashval_t hash (const attribute_spec *); 66 static inline bool equal (const attribute_spec *, const substring *); 67 }; 68 69 inline hashval_t 70 attribute_hasher::hash (const attribute_spec *spec) 71 { 72 const int l = strlen (spec->name); 73 return substring_hash (spec->name, l); 74 } 75 76 inline bool 77 attribute_hasher::equal (const attribute_spec *spec, const substring *str) 78 { 79 return (strncmp (spec->name, str->str, str->length) == 0 80 && !spec->name[str->length]); 81 } 82 83 /* Scoped attribute name representation. */ 84 85 struct scoped_attributes 86 { 87 const char *ns; 88 vec<attribute_spec> attributes; 89 hash_table<attribute_hasher> *attribute_hash; 90 /* True if we should not warn about unknown attributes in this NS. */ 91 bool ignored_p; 92 }; 93 94 /* The table of scope attributes. */ 95 static vec<scoped_attributes> attributes_table; 96 97 static scoped_attributes* find_attribute_namespace (const char*); 98 static void register_scoped_attribute (const struct attribute_spec *, 99 scoped_attributes *); 100 static const struct attribute_spec *lookup_scoped_attribute_spec (const_tree, 101 const_tree); 102 103 static bool attributes_initialized = false; 104 105 /* Default empty table of attributes. */ 106 107 static const struct attribute_spec empty_attribute_table[] = 108 { 109 { NULL, 0, 0, false, false, false, false, NULL, NULL } 110 }; 111 112 /* Insert an array of attributes ATTRIBUTES into a namespace. This 113 array must be NULL terminated. NS is the name of attribute 114 namespace. IGNORED_P is true iff all unknown attributes in this 115 namespace should be ignored for the purposes of -Wattributes. The 116 function returns the namespace into which the attributes have been 117 registered. */ 118 119 scoped_attributes * 120 register_scoped_attributes (const struct attribute_spec *attributes, 121 const char *ns, bool ignored_p /*=false*/) 122 { 123 scoped_attributes *result = NULL; 124 125 /* See if we already have attributes in the namespace NS. */ 126 result = find_attribute_namespace (ns); 127 128 if (result == NULL) 129 { 130 /* We don't have any namespace NS yet. Create one. */ 131 scoped_attributes sa; 132 133 if (attributes_table.is_empty ()) 134 attributes_table.create (64); 135 136 memset (&sa, 0, sizeof (sa)); 137 sa.ns = ns; 138 sa.attributes.create (64); 139 sa.ignored_p = ignored_p; 140 result = attributes_table.safe_push (sa); 141 result->attribute_hash = new hash_table<attribute_hasher> (200); 142 } 143 else 144 result->ignored_p |= ignored_p; 145 146 /* Really add the attributes to their namespace now. */ 147 for (unsigned i = 0; attributes[i].name != NULL; ++i) 148 { 149 result->attributes.safe_push (attributes[i]); 150 register_scoped_attribute (&attributes[i], result); 151 } 152 153 gcc_assert (result != NULL); 154 155 return result; 156 } 157 158 /* Return the namespace which name is NS, NULL if none exist. */ 159 160 static scoped_attributes* 161 find_attribute_namespace (const char* ns) 162 { 163 for (scoped_attributes &iter : attributes_table) 164 if (ns == iter.ns 165 || (iter.ns != NULL 166 && ns != NULL 167 && !strcmp (iter.ns, ns))) 168 return &iter; 169 return NULL; 170 } 171 172 /* Make some sanity checks on the attribute tables. */ 173 174 static void 175 check_attribute_tables (void) 176 { 177 for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) 178 for (size_t j = 0; attribute_tables[i][j].name != NULL; j++) 179 { 180 /* The name must not begin and end with __. */ 181 const char *name = attribute_tables[i][j].name; 182 int len = strlen (name); 183 184 gcc_assert (!(name[0] == '_' && name[1] == '_' 185 && name[len - 1] == '_' && name[len - 2] == '_')); 186 187 /* The minimum and maximum lengths must be consistent. */ 188 gcc_assert (attribute_tables[i][j].min_length >= 0); 189 190 gcc_assert (attribute_tables[i][j].max_length == -1 191 || (attribute_tables[i][j].max_length 192 >= attribute_tables[i][j].min_length)); 193 194 /* An attribute cannot require both a DECL and a TYPE. */ 195 gcc_assert (!attribute_tables[i][j].decl_required 196 || !attribute_tables[i][j].type_required); 197 198 /* If an attribute requires a function type, in particular 199 it requires a type. */ 200 gcc_assert (!attribute_tables[i][j].function_type_required 201 || attribute_tables[i][j].type_required); 202 } 203 204 /* Check that each name occurs just once in each table. */ 205 for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) 206 for (size_t j = 0; attribute_tables[i][j].name != NULL; j++) 207 for (size_t k = j + 1; attribute_tables[i][k].name != NULL; k++) 208 gcc_assert (strcmp (attribute_tables[i][j].name, 209 attribute_tables[i][k].name)); 210 211 /* Check that no name occurs in more than one table. Names that 212 begin with '*' are exempt, and may be overridden. */ 213 for (size_t i = 0; i < ARRAY_SIZE (attribute_tables); i++) 214 for (size_t j = i + 1; j < ARRAY_SIZE (attribute_tables); j++) 215 for (size_t k = 0; attribute_tables[i][k].name != NULL; k++) 216 for (size_t l = 0; attribute_tables[j][l].name != NULL; l++) 217 gcc_assert (attribute_tables[i][k].name[0] == '*' 218 || strcmp (attribute_tables[i][k].name, 219 attribute_tables[j][l].name)); 220 } 221 222 /* Used to stash pointers to allocated memory so that we can free them at 223 the end of parsing of all TUs. */ 224 static vec<attribute_spec *> ignored_attributes_table; 225 226 /* Parse arguments V of -Wno-attributes=. 227 Currently we accept: 228 vendor::attr 229 vendor:: 230 This functions also registers the parsed attributes so that we don't 231 warn that we don't recognize them. */ 232 233 void 234 handle_ignored_attributes_option (vec<char *> *v) 235 { 236 if (v == nullptr) 237 return; 238 239 for (auto opt : v) 240 { 241 char *cln = strstr (opt, "::"); 242 /* We don't accept '::attr'. */ 243 if (cln == nullptr || cln == opt) 244 { 245 error ("wrong argument to ignored attributes"); 246 inform (input_location, "valid format is %<ns::attr%> or %<ns::%>"); 247 continue; 248 } 249 const char *vendor_start = opt; 250 ptrdiff_t vendor_len = cln - opt; 251 const char *attr_start = cln + 2; 252 /* This could really use rawmemchr :(. */ 253 ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start; 254 /* Verify that they look valid. */ 255 auto valid_p = [](const char *const s, ptrdiff_t len) { 256 bool ok = false; 257 258 for (int i = 0; i < len; ++i) 259 if (ISALNUM (s[i])) 260 ok = true; 261 else if (s[i] != '_') 262 return false; 263 264 return ok; 265 }; 266 if (!valid_p (vendor_start, vendor_len)) 267 { 268 error ("wrong argument to ignored attributes"); 269 continue; 270 } 271 canonicalize_attr_name (vendor_start, vendor_len); 272 /* We perform all this hijinks so that we don't have to copy OPT. */ 273 tree vendor_id = get_identifier_with_length (vendor_start, vendor_len); 274 const char *attr; 275 /* In the "vendor::" case, we should ignore *any* attribute coming 276 from this attribute namespace. */ 277 if (attr_len > 0) 278 { 279 if (!valid_p (attr_start, attr_len)) 280 { 281 error ("wrong argument to ignored attributes"); 282 continue; 283 } 284 canonicalize_attr_name (attr_start, attr_len); 285 tree attr_id = get_identifier_with_length (attr_start, attr_len); 286 attr = IDENTIFIER_POINTER (attr_id); 287 /* If we've already seen this vendor::attr, ignore it. Attempting to 288 register it twice would lead to a crash. */ 289 if (lookup_scoped_attribute_spec (vendor_id, attr_id)) 290 continue; 291 } 292 else 293 attr = nullptr; 294 /* Create a table with extra attributes which we will register. 295 We can't free it here, so squirrel away the pointers. */ 296 attribute_spec *table = new attribute_spec[2]; 297 ignored_attributes_table.safe_push (table); 298 table[0] = { attr, 0, -2, false, false, false, false, nullptr, nullptr }; 299 table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, 300 nullptr }; 301 register_scoped_attributes (table, IDENTIFIER_POINTER (vendor_id), !attr); 302 } 303 } 304 305 /* Free data we might have allocated when adding extra attributes. */ 306 307 void 308 free_attr_data () 309 { 310 for (auto x : ignored_attributes_table) 311 delete[] x; 312 ignored_attributes_table.release (); 313 } 314 315 /* Initialize attribute tables, and make some sanity checks if checking is 316 enabled. */ 317 318 void 319 init_attributes (void) 320 { 321 size_t i; 322 323 if (attributes_initialized) 324 return; 325 326 attribute_tables[0] = lang_hooks.common_attribute_table; 327 attribute_tables[1] = lang_hooks.attribute_table; 328 attribute_tables[2] = lang_hooks.format_attribute_table; 329 attribute_tables[3] = targetm.attribute_table; 330 331 /* Translate NULL pointers to pointers to the empty table. */ 332 for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) 333 if (attribute_tables[i] == NULL) 334 attribute_tables[i] = empty_attribute_table; 335 336 if (flag_checking) 337 check_attribute_tables (); 338 339 for (i = 0; i < ARRAY_SIZE (attribute_tables); ++i) 340 /* Put all the GNU attributes into the "gnu" namespace. */ 341 register_scoped_attributes (attribute_tables[i], "gnu"); 342 343 vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes; 344 handle_ignored_attributes_option (ignored); 345 346 invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL); 347 attributes_initialized = true; 348 } 349 350 /* Insert a single ATTR into the attribute table. */ 351 352 void 353 register_attribute (const struct attribute_spec *attr) 354 { 355 register_scoped_attribute (attr, find_attribute_namespace ("gnu")); 356 } 357 358 /* Insert a single attribute ATTR into a namespace of attributes. */ 359 360 static void 361 register_scoped_attribute (const struct attribute_spec *attr, 362 scoped_attributes *name_space) 363 { 364 struct substring str; 365 attribute_spec **slot; 366 367 gcc_assert (attr != NULL && name_space != NULL); 368 369 gcc_assert (name_space->attribute_hash); 370 371 str.str = attr->name; 372 str.length = strlen (str.str); 373 374 /* Attribute names in the table must be in the form 'text' and not 375 in the form '__text__'. */ 376 gcc_checking_assert (!canonicalize_attr_name (str.str, str.length)); 377 378 slot = name_space->attribute_hash 379 ->find_slot_with_hash (&str, substring_hash (str.str, str.length), 380 INSERT); 381 gcc_assert (!*slot || attr->name[0] == '*'); 382 *slot = CONST_CAST (struct attribute_spec *, attr); 383 } 384 385 /* Return the spec for the scoped attribute with namespace NS and 386 name NAME. */ 387 388 static const struct attribute_spec * 389 lookup_scoped_attribute_spec (const_tree ns, const_tree name) 390 { 391 struct substring attr; 392 scoped_attributes *attrs; 393 394 const char *ns_str = (ns != NULL_TREE) ? IDENTIFIER_POINTER (ns): NULL; 395 396 attrs = find_attribute_namespace (ns_str); 397 398 if (attrs == NULL) 399 return NULL; 400 401 attr.str = IDENTIFIER_POINTER (name); 402 attr.length = IDENTIFIER_LENGTH (name); 403 return attrs->attribute_hash->find_with_hash (&attr, 404 substring_hash (attr.str, 405 attr.length)); 406 } 407 408 /* Return the spec for the attribute named NAME. If NAME is a TREE_LIST, 409 it also specifies the attribute namespace. */ 410 411 const struct attribute_spec * 412 lookup_attribute_spec (const_tree name) 413 { 414 tree ns; 415 if (TREE_CODE (name) == TREE_LIST) 416 { 417 ns = TREE_PURPOSE (name); 418 name = TREE_VALUE (name); 419 } 420 else 421 ns = get_identifier ("gnu"); 422 return lookup_scoped_attribute_spec (ns, name); 423 } 424 425 426 /* Return the namespace of the attribute ATTR. This accessor works on 427 GNU and C++11 (scoped) attributes. On GNU attributes, 428 it returns an identifier tree for the string "gnu". 429 430 Please read the comments of cxx11_attribute_p to understand the 431 format of attributes. */ 432 433 tree 434 get_attribute_namespace (const_tree attr) 435 { 436 if (cxx11_attribute_p (attr)) 437 return TREE_PURPOSE (TREE_PURPOSE (attr)); 438 return get_identifier ("gnu"); 439 } 440 441 /* Check LAST_DECL and NODE of the same symbol for attributes that are 442 recorded in SPEC to be mutually exclusive with ATTRNAME, diagnose 443 them, and return true if any have been found. NODE can be a DECL 444 or a TYPE. */ 445 446 static bool 447 diag_attr_exclusions (tree last_decl, tree node, tree attrname, 448 const attribute_spec *spec) 449 { 450 const attribute_spec::exclusions *excl = spec->exclude; 451 452 tree_code code = TREE_CODE (node); 453 454 if ((code == FUNCTION_DECL && !excl->function 455 && (!excl->type || !spec->affects_type_identity)) 456 || (code == VAR_DECL && !excl->variable 457 && (!excl->type || !spec->affects_type_identity)) 458 || (((code == TYPE_DECL || RECORD_OR_UNION_TYPE_P (node)) && !excl->type))) 459 return false; 460 461 /* True if an attribute that's mutually exclusive with ATTRNAME 462 has been found. */ 463 bool found = false; 464 465 if (last_decl && last_decl != node && TREE_TYPE (last_decl) != node) 466 { 467 /* Check both the last DECL and its type for conflicts with 468 the attribute being added to the current decl or type. */ 469 found |= diag_attr_exclusions (last_decl, last_decl, attrname, spec); 470 tree decl_type = TREE_TYPE (last_decl); 471 found |= diag_attr_exclusions (last_decl, decl_type, attrname, spec); 472 } 473 474 /* NODE is either the current DECL to which the attribute is being 475 applied or its TYPE. For the former, consider the attributes on 476 both the DECL and its type. */ 477 tree attrs[2]; 478 479 if (DECL_P (node)) 480 { 481 attrs[0] = DECL_ATTRIBUTES (node); 482 if (TREE_TYPE (node)) 483 attrs[1] = TYPE_ATTRIBUTES (TREE_TYPE (node)); 484 else 485 /* TREE_TYPE can be NULL e.g. while processing attributes on 486 enumerators. */ 487 attrs[1] = NULL_TREE; 488 } 489 else 490 { 491 attrs[0] = TYPE_ATTRIBUTES (node); 492 attrs[1] = NULL_TREE; 493 } 494 495 /* Iterate over the mutually exclusive attribute names and verify 496 that the symbol doesn't contain it. */ 497 for (unsigned i = 0; i != sizeof attrs / sizeof *attrs; ++i) 498 { 499 if (!attrs[i]) 500 continue; 501 502 for ( ; excl->name; ++excl) 503 { 504 /* Avoid checking the attribute against itself. */ 505 if (is_attribute_p (excl->name, attrname)) 506 continue; 507 508 if (!lookup_attribute (excl->name, attrs[i])) 509 continue; 510 511 /* An exclusion may apply either to a function declaration, 512 type declaration, or a field/variable declaration, or 513 any subset of the three. */ 514 if (TREE_CODE (node) == FUNCTION_DECL 515 && !excl->function) 516 continue; 517 518 if (TREE_CODE (node) == TYPE_DECL 519 && !excl->type) 520 continue; 521 522 if ((TREE_CODE (node) == FIELD_DECL 523 || TREE_CODE (node) == VAR_DECL) 524 && !excl->variable) 525 continue; 526 527 found = true; 528 529 /* Print a note? */ 530 bool note = last_decl != NULL_TREE; 531 auto_diagnostic_group d; 532 if (TREE_CODE (node) == FUNCTION_DECL 533 && fndecl_built_in_p (node)) 534 note &= warning (OPT_Wattributes, 535 "ignoring attribute %qE in declaration of " 536 "a built-in function %qD because it conflicts " 537 "with attribute %qs", 538 attrname, node, excl->name); 539 else 540 note &= warning (OPT_Wattributes, 541 "ignoring attribute %qE because " 542 "it conflicts with attribute %qs", 543 attrname, excl->name); 544 545 if (note) 546 inform (DECL_SOURCE_LOCATION (last_decl), 547 "previous declaration here"); 548 } 549 } 550 551 return found; 552 } 553 554 /* Return true iff we should not complain about unknown attributes 555 coming from the attribute namespace NS. This is the case for 556 the -Wno-attributes=ns:: command-line option. */ 557 558 static bool 559 attr_namespace_ignored_p (tree ns) 560 { 561 if (ns == NULL_TREE) 562 return false; 563 scoped_attributes *r = find_attribute_namespace (IDENTIFIER_POINTER (ns)); 564 return r && r->ignored_p; 565 } 566 567 /* Return true if the attribute ATTR should not be warned about. */ 568 569 bool 570 attribute_ignored_p (tree attr) 571 { 572 if (!cxx11_attribute_p (attr)) 573 return false; 574 if (tree ns = get_attribute_namespace (attr)) 575 { 576 const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attr)); 577 if (as == NULL && attr_namespace_ignored_p (ns)) 578 return true; 579 if (as && as->max_length == -2) 580 return true; 581 } 582 return false; 583 } 584 585 /* Like above, but takes an attribute_spec AS, which must be nonnull. */ 586 587 bool 588 attribute_ignored_p (const attribute_spec *const as) 589 { 590 return as->max_length == -2; 591 } 592 593 /* Process the attributes listed in ATTRIBUTES and install them in *NODE, 594 which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL, 595 it should be modified in place; if a TYPE, a copy should be created 596 unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further 597 information, in the form of a bitwise OR of flags in enum attribute_flags 598 from tree.h. Depending on these flags, some attributes may be 599 returned to be applied at a later stage (for example, to apply 600 a decl attribute to the declaration rather than to its type). */ 601 602 tree 603 decl_attributes (tree *node, tree attributes, int flags, 604 tree last_decl /* = NULL_TREE */) 605 { 606 tree returned_attrs = NULL_TREE; 607 608 if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node) 609 return NULL_TREE; 610 611 if (!attributes_initialized) 612 init_attributes (); 613 614 /* If this is a function and the user used #pragma GCC optimize, add the 615 options to the attribute((optimize(...))) list. */ 616 if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma) 617 { 618 tree cur_attr = lookup_attribute ("optimize", attributes); 619 tree opts = copy_list (current_optimize_pragma); 620 621 if (! cur_attr) 622 attributes 623 = tree_cons (get_identifier ("optimize"), opts, attributes); 624 else 625 TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); 626 } 627 628 if (TREE_CODE (*node) == FUNCTION_DECL 629 && (optimization_current_node != optimization_default_node 630 || target_option_current_node != target_option_default_node) 631 && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)) 632 { 633 DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node; 634 /* Don't set DECL_FUNCTION_SPECIFIC_TARGET for targets that don't 635 support #pragma GCC target or target attribute. */ 636 if (target_option_default_node) 637 { 638 tree cur_tree 639 = build_target_option_node (&global_options, &global_options_set); 640 tree old_tree = DECL_FUNCTION_SPECIFIC_TARGET (*node); 641 if (!old_tree) 642 old_tree = target_option_default_node; 643 /* The changes on optimization options can cause the changes in 644 target options, update it accordingly if it's changed. */ 645 if (old_tree != cur_tree) 646 DECL_FUNCTION_SPECIFIC_TARGET (*node) = cur_tree; 647 } 648 } 649 650 /* If this is a function and the user used #pragma GCC target, add the 651 options to the attribute((target(...))) list. */ 652 if (TREE_CODE (*node) == FUNCTION_DECL 653 && current_target_pragma 654 && targetm.target_option.valid_attribute_p (*node, NULL_TREE, 655 current_target_pragma, 0)) 656 { 657 tree cur_attr = lookup_attribute ("target", attributes); 658 tree opts = copy_list (current_target_pragma); 659 660 if (! cur_attr) 661 attributes = tree_cons (get_identifier ("target"), opts, attributes); 662 else 663 TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr)); 664 } 665 666 /* A "naked" function attribute implies "noinline" and "noclone" for 667 those targets that support it. */ 668 if (TREE_CODE (*node) == FUNCTION_DECL 669 && attributes 670 && lookup_attribute ("naked", attributes) != NULL 671 && lookup_attribute_spec (get_identifier ("naked")) 672 && lookup_attribute ("noipa", attributes) == NULL) 673 attributes = tree_cons (get_identifier ("noipa"), NULL, attributes); 674 675 /* A "noipa" function attribute implies "noinline", "noclone" and "no_icf" 676 for those targets that support it. */ 677 if (TREE_CODE (*node) == FUNCTION_DECL 678 && attributes 679 && lookup_attribute ("noipa", attributes) != NULL 680 && lookup_attribute_spec (get_identifier ("noipa"))) 681 { 682 if (lookup_attribute ("noinline", attributes) == NULL) 683 attributes = tree_cons (get_identifier ("noinline"), NULL, attributes); 684 685 if (lookup_attribute ("noclone", attributes) == NULL) 686 attributes = tree_cons (get_identifier ("noclone"), NULL, attributes); 687 688 if (lookup_attribute ("no_icf", attributes) == NULL) 689 attributes = tree_cons (get_identifier ("no_icf"), NULL, attributes); 690 } 691 692 targetm.insert_attributes (*node, &attributes); 693 694 /* Note that attributes on the same declaration are not necessarily 695 in the same order as in the source. */ 696 for (tree attr = attributes; attr; attr = TREE_CHAIN (attr)) 697 { 698 tree ns = get_attribute_namespace (attr); 699 tree name = get_attribute_name (attr); 700 tree args = TREE_VALUE (attr); 701 tree *anode = node; 702 const struct attribute_spec *spec 703 = lookup_scoped_attribute_spec (ns, name); 704 int fn_ptr_quals = 0; 705 tree fn_ptr_tmp = NULL_TREE; 706 const bool cxx11_attr_p = cxx11_attribute_p (attr); 707 708 if (spec == NULL) 709 { 710 if (!(flags & (int) ATTR_FLAG_BUILT_IN) 711 && !attr_namespace_ignored_p (ns)) 712 { 713 if (ns == NULL_TREE || !cxx11_attr_p) 714 warning (OPT_Wattributes, "%qE attribute directive ignored", 715 name); 716 else 717 warning (OPT_Wattributes, 718 "%<%E::%E%> scoped attribute directive ignored", 719 ns, name); 720 } 721 continue; 722 } 723 else 724 { 725 int nargs = list_length (args); 726 if (nargs < spec->min_length 727 || (spec->max_length >= 0 728 && nargs > spec->max_length)) 729 { 730 error ("wrong number of arguments specified for %qE attribute", 731 name); 732 if (spec->max_length < 0) 733 inform (input_location, "expected %i or more, found %i", 734 spec->min_length, nargs); 735 else 736 inform (input_location, "expected between %i and %i, found %i", 737 spec->min_length, spec->max_length, nargs); 738 continue; 739 } 740 } 741 gcc_assert (is_attribute_p (spec->name, name)); 742 743 if (spec->decl_required && !DECL_P (*anode)) 744 { 745 if (flags & ((int) ATTR_FLAG_DECL_NEXT 746 | (int) ATTR_FLAG_FUNCTION_NEXT 747 | (int) ATTR_FLAG_ARRAY_NEXT)) 748 { 749 /* Pass on this attribute to be tried again. */ 750 tree attr = tree_cons (name, args, NULL_TREE); 751 returned_attrs = chainon (returned_attrs, attr); 752 continue; 753 } 754 else 755 { 756 warning (OPT_Wattributes, "%qE attribute does not apply to types", 757 name); 758 continue; 759 } 760 } 761 762 /* If we require a type, but were passed a decl, set up to make a 763 new type and update the one in the decl. ATTR_FLAG_TYPE_IN_PLACE 764 would have applied if we'd been passed a type, but we cannot modify 765 the decl's type in place here. */ 766 if (spec->type_required && DECL_P (*anode)) 767 { 768 anode = &TREE_TYPE (*anode); 769 flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; 770 } 771 772 if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE 773 && TREE_CODE (*anode) != METHOD_TYPE) 774 { 775 if (TREE_CODE (*anode) == POINTER_TYPE 776 && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE 777 || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE)) 778 { 779 /* OK, this is a bit convoluted. We can't just make a copy 780 of the pointer type and modify its TREE_TYPE, because if 781 we change the attributes of the target type the pointer 782 type needs to have a different TYPE_MAIN_VARIANT. So we 783 pull out the target type now, frob it as appropriate, and 784 rebuild the pointer type later. 785 786 This would all be simpler if attributes were part of the 787 declarator, grumble grumble. */ 788 fn_ptr_tmp = TREE_TYPE (*anode); 789 fn_ptr_quals = TYPE_QUALS (*anode); 790 anode = &fn_ptr_tmp; 791 flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE; 792 } 793 else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) 794 { 795 /* Pass on this attribute to be tried again. */ 796 tree attr = tree_cons (name, args, NULL_TREE); 797 returned_attrs = chainon (returned_attrs, attr); 798 continue; 799 } 800 801 if (TREE_CODE (*anode) != FUNCTION_TYPE 802 && TREE_CODE (*anode) != METHOD_TYPE) 803 { 804 warning (OPT_Wattributes, 805 "%qE attribute only applies to function types", 806 name); 807 continue; 808 } 809 } 810 811 if (TYPE_P (*anode) 812 && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) 813 && TYPE_SIZE (*anode) != NULL_TREE) 814 { 815 warning (OPT_Wattributes, "type attributes ignored after type is already defined"); 816 continue; 817 } 818 819 bool no_add_attrs = false; 820 821 /* Check for exclusions with other attributes on the current 822 declation as well as the last declaration of the same 823 symbol already processed (if one exists). Detect and 824 reject incompatible attributes. */ 825 bool built_in = flags & ATTR_FLAG_BUILT_IN; 826 if (spec->exclude 827 && (flag_checking || !built_in) 828 && !error_operand_p (last_decl)) 829 { 830 /* Always check attributes on user-defined functions. 831 Check them on built-ins only when -fchecking is set. 832 Ignore __builtin_unreachable -- it's both const and 833 noreturn. */ 834 835 if (!built_in 836 || !DECL_P (*anode) 837 || DECL_BUILT_IN_CLASS (*anode) != BUILT_IN_NORMAL 838 || (DECL_FUNCTION_CODE (*anode) != BUILT_IN_UNREACHABLE 839 && (DECL_FUNCTION_CODE (*anode) 840 != BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE))) 841 { 842 bool no_add = diag_attr_exclusions (last_decl, *anode, name, spec); 843 if (!no_add && anode != node) 844 no_add = diag_attr_exclusions (last_decl, *node, name, spec); 845 no_add_attrs |= no_add; 846 } 847 } 848 849 if (no_add_attrs 850 /* Don't add attributes registered just for -Wno-attributes=foo::bar 851 purposes. */ 852 || attribute_ignored_p (attr)) 853 continue; 854 855 if (spec->handler != NULL) 856 { 857 int cxx11_flag = (cxx11_attr_p ? ATTR_FLAG_CXX11 : 0); 858 859 /* Pass in an array of the current declaration followed 860 by the last pushed/merged declaration if one exists. 861 For calls that modify the type attributes of a DECL 862 and for which *ANODE is *NODE's type, also pass in 863 the DECL as the third element to use in diagnostics. 864 If the handler changes CUR_AND_LAST_DECL[0] replace 865 *ANODE with its value. */ 866 tree cur_and_last_decl[3] = { *anode, last_decl }; 867 if (anode != node && DECL_P (*node)) 868 cur_and_last_decl[2] = *node; 869 870 tree ret = (spec->handler) (cur_and_last_decl, name, args, 871 flags|cxx11_flag, &no_add_attrs); 872 873 *anode = cur_and_last_decl[0]; 874 if (ret == error_mark_node) 875 { 876 warning (OPT_Wattributes, "%qE attribute ignored", name); 877 no_add_attrs = true; 878 } 879 else 880 returned_attrs = chainon (ret, returned_attrs); 881 } 882 883 /* Layout the decl in case anything changed. */ 884 if (spec->type_required && DECL_P (*node) 885 && (VAR_P (*node) 886 || TREE_CODE (*node) == PARM_DECL 887 || TREE_CODE (*node) == RESULT_DECL)) 888 relayout_decl (*node); 889 890 if (!no_add_attrs) 891 { 892 tree old_attrs; 893 tree a; 894 895 if (DECL_P (*anode)) 896 old_attrs = DECL_ATTRIBUTES (*anode); 897 else 898 old_attrs = TYPE_ATTRIBUTES (*anode); 899 900 for (a = lookup_attribute (spec->name, old_attrs); 901 a != NULL_TREE; 902 a = lookup_attribute (spec->name, TREE_CHAIN (a))) 903 { 904 if (simple_cst_equal (TREE_VALUE (a), args) == 1) 905 break; 906 } 907 908 if (a == NULL_TREE) 909 { 910 /* This attribute isn't already in the list. */ 911 tree r; 912 /* Preserve the C++11 form. */ 913 if (cxx11_attr_p) 914 r = tree_cons (build_tree_list (ns, name), args, old_attrs); 915 else 916 r = tree_cons (name, args, old_attrs); 917 918 if (DECL_P (*anode)) 919 DECL_ATTRIBUTES (*anode) = r; 920 else if (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) 921 { 922 TYPE_ATTRIBUTES (*anode) = r; 923 /* If this is the main variant, also push the attributes 924 out to the other variants. */ 925 if (*anode == TYPE_MAIN_VARIANT (*anode)) 926 { 927 for (tree variant = *anode; variant; 928 variant = TYPE_NEXT_VARIANT (variant)) 929 { 930 if (TYPE_ATTRIBUTES (variant) == old_attrs) 931 TYPE_ATTRIBUTES (variant) 932 = TYPE_ATTRIBUTES (*anode); 933 else if (!lookup_attribute 934 (spec->name, TYPE_ATTRIBUTES (variant))) 935 TYPE_ATTRIBUTES (variant) = tree_cons 936 (name, args, TYPE_ATTRIBUTES (variant)); 937 } 938 } 939 } 940 else 941 *anode = build_type_attribute_variant (*anode, r); 942 } 943 } 944 945 if (fn_ptr_tmp) 946 { 947 /* Rebuild the function pointer type and put it in the 948 appropriate place. */ 949 fn_ptr_tmp = build_pointer_type (fn_ptr_tmp); 950 if (fn_ptr_quals) 951 fn_ptr_tmp = build_qualified_type (fn_ptr_tmp, fn_ptr_quals); 952 if (DECL_P (*node)) 953 TREE_TYPE (*node) = fn_ptr_tmp; 954 else 955 { 956 gcc_assert (TREE_CODE (*node) == POINTER_TYPE); 957 *node = fn_ptr_tmp; 958 } 959 } 960 } 961 962 return returned_attrs; 963 } 964 965 /* Return TRUE iff ATTR has been parsed by the front-end as a C++-11 966 attribute. 967 968 When G++ parses a C++11 attribute, it is represented as 969 a TREE_LIST which TREE_PURPOSE is itself a TREE_LIST. TREE_PURPOSE 970 (TREE_PURPOSE (ATTR)) is the namespace of the attribute, and the 971 TREE_VALUE (TREE_PURPOSE (ATTR)) is its non-qualified name. Please 972 use get_attribute_namespace and get_attribute_name to retrieve the 973 namespace and name of the attribute, as these accessors work with 974 GNU attributes as well. */ 975 976 bool 977 cxx11_attribute_p (const_tree attr) 978 { 979 if (attr == NULL_TREE 980 || TREE_CODE (attr) != TREE_LIST) 981 return false; 982 983 return (TREE_CODE (TREE_PURPOSE (attr)) == TREE_LIST); 984 } 985 986 /* Return the name of the attribute ATTR. This accessor works on GNU 987 and C++11 (scoped) attributes. 988 989 Please read the comments of cxx11_attribute_p to understand the 990 format of attributes. */ 991 992 tree 993 get_attribute_name (const_tree attr) 994 { 995 if (cxx11_attribute_p (attr)) 996 return TREE_VALUE (TREE_PURPOSE (attr)); 997 return TREE_PURPOSE (attr); 998 } 999 1000 /* Subroutine of set_method_tm_attributes. Apply TM attribute ATTR 1001 to the method FNDECL. */ 1002 1003 void 1004 apply_tm_attr (tree fndecl, tree attr) 1005 { 1006 decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0); 1007 } 1008 1009 /* Makes a function attribute of the form NAME(ARG_NAME) and chains 1010 it to CHAIN. */ 1011 1012 tree 1013 make_attribute (const char *name, const char *arg_name, tree chain) 1014 { 1015 tree attr_name; 1016 tree attr_arg_name; 1017 tree attr_args; 1018 tree attr; 1019 1020 attr_name = get_identifier (name); 1021 attr_arg_name = build_string (strlen (arg_name), arg_name); 1022 attr_args = tree_cons (NULL_TREE, attr_arg_name, NULL_TREE); 1023 attr = tree_cons (attr_name, attr_args, chain); 1024 return attr; 1025 } 1026 1027 1028 /* Common functions used for target clone support. */ 1030 1031 /* Comparator function to be used in qsort routine to sort attribute 1032 specification strings to "target". */ 1033 1034 static int 1035 attr_strcmp (const void *v1, const void *v2) 1036 { 1037 const char *c1 = *(char *const*)v1; 1038 const char *c2 = *(char *const*)v2; 1039 return strcmp (c1, c2); 1040 } 1041 1042 /* ARGLIST is the argument to target attribute. This function tokenizes 1043 the comma separated arguments, sorts them and returns a string which 1044 is a unique identifier for the comma separated arguments. It also 1045 replaces non-identifier characters "=,-" with "_". */ 1046 1047 char * 1048 sorted_attr_string (tree arglist) 1049 { 1050 tree arg; 1051 size_t str_len_sum = 0; 1052 char **args = NULL; 1053 char *attr_str, *ret_str; 1054 char *attr = NULL; 1055 unsigned int argnum = 1; 1056 unsigned int i; 1057 1058 for (arg = arglist; arg; arg = TREE_CHAIN (arg)) 1059 { 1060 const char *str = TREE_STRING_POINTER (TREE_VALUE (arg)); 1061 size_t len = strlen (str); 1062 str_len_sum += len + 1; 1063 if (arg != arglist) 1064 argnum++; 1065 for (i = 0; i < strlen (str); i++) 1066 if (str[i] == ',') 1067 argnum++; 1068 } 1069 1070 attr_str = XNEWVEC (char, str_len_sum); 1071 str_len_sum = 0; 1072 for (arg = arglist; arg; arg = TREE_CHAIN (arg)) 1073 { 1074 const char *str = TREE_STRING_POINTER (TREE_VALUE (arg)); 1075 size_t len = strlen (str); 1076 memcpy (attr_str + str_len_sum, str, len); 1077 attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0'; 1078 str_len_sum += len + 1; 1079 } 1080 1081 /* Replace "=,-" with "_". */ 1082 for (i = 0; i < strlen (attr_str); i++) 1083 if (attr_str[i] == '=' || attr_str[i]== '-') 1084 attr_str[i] = '_'; 1085 1086 if (argnum == 1) 1087 return attr_str; 1088 1089 args = XNEWVEC (char *, argnum); 1090 1091 i = 0; 1092 attr = strtok (attr_str, ","); 1093 while (attr != NULL) 1094 { 1095 args[i] = attr; 1096 i++; 1097 attr = strtok (NULL, ","); 1098 } 1099 1100 qsort (args, argnum, sizeof (char *), attr_strcmp); 1101 1102 ret_str = XNEWVEC (char, str_len_sum); 1103 str_len_sum = 0; 1104 for (i = 0; i < argnum; i++) 1105 { 1106 size_t len = strlen (args[i]); 1107 memcpy (ret_str + str_len_sum, args[i], len); 1108 ret_str[str_len_sum + len] = i < argnum - 1 ? '_' : '\0'; 1109 str_len_sum += len + 1; 1110 } 1111 1112 XDELETEVEC (args); 1113 XDELETEVEC (attr_str); 1114 return ret_str; 1115 } 1116 1117 1118 /* This function returns true if FN1 and FN2 are versions of the same function, 1119 that is, the target strings of the function decls are different. This assumes 1120 that FN1 and FN2 have the same signature. */ 1121 1122 bool 1123 common_function_versions (tree fn1, tree fn2) 1124 { 1125 tree attr1, attr2; 1126 char *target1, *target2; 1127 bool result; 1128 1129 if (TREE_CODE (fn1) != FUNCTION_DECL 1130 || TREE_CODE (fn2) != FUNCTION_DECL) 1131 return false; 1132 1133 attr1 = lookup_attribute ("target", DECL_ATTRIBUTES (fn1)); 1134 attr2 = lookup_attribute ("target", DECL_ATTRIBUTES (fn2)); 1135 1136 /* At least one function decl should have the target attribute specified. */ 1137 if (attr1 == NULL_TREE && attr2 == NULL_TREE) 1138 return false; 1139 1140 /* Diagnose missing target attribute if one of the decls is already 1141 multi-versioned. */ 1142 if (attr1 == NULL_TREE || attr2 == NULL_TREE) 1143 { 1144 if (DECL_FUNCTION_VERSIONED (fn1) || DECL_FUNCTION_VERSIONED (fn2)) 1145 { 1146 if (attr2 != NULL_TREE) 1147 { 1148 std::swap (fn1, fn2); 1149 attr1 = attr2; 1150 } 1151 error_at (DECL_SOURCE_LOCATION (fn2), 1152 "missing %<target%> attribute for multi-versioned %qD", 1153 fn2); 1154 inform (DECL_SOURCE_LOCATION (fn1), 1155 "previous declaration of %qD", fn1); 1156 /* Prevent diagnosing of the same error multiple times. */ 1157 DECL_ATTRIBUTES (fn2) 1158 = tree_cons (get_identifier ("target"), 1159 copy_node (TREE_VALUE (attr1)), 1160 DECL_ATTRIBUTES (fn2)); 1161 } 1162 return false; 1163 } 1164 1165 target1 = sorted_attr_string (TREE_VALUE (attr1)); 1166 target2 = sorted_attr_string (TREE_VALUE (attr2)); 1167 1168 /* The sorted target strings must be different for fn1 and fn2 1169 to be versions. */ 1170 if (strcmp (target1, target2) == 0) 1171 result = false; 1172 else 1173 result = true; 1174 1175 XDELETEVEC (target1); 1176 XDELETEVEC (target2); 1177 1178 return result; 1179 } 1180 1181 /* Make a dispatcher declaration for the multi-versioned function DECL. 1182 Calls to DECL function will be replaced with calls to the dispatcher 1183 by the front-end. Return the decl created. */ 1184 1185 tree 1186 make_dispatcher_decl (const tree decl) 1187 { 1188 tree func_decl; 1189 char *func_name; 1190 tree fn_type, func_type; 1191 1192 func_name = xstrdup (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); 1193 1194 fn_type = TREE_TYPE (decl); 1195 func_type = build_function_type (TREE_TYPE (fn_type), 1196 TYPE_ARG_TYPES (fn_type)); 1197 1198 func_decl = build_fn_decl (func_name, func_type); 1199 XDELETEVEC (func_name); 1200 TREE_USED (func_decl) = 1; 1201 DECL_CONTEXT (func_decl) = NULL_TREE; 1202 DECL_INITIAL (func_decl) = error_mark_node; 1203 DECL_ARTIFICIAL (func_decl) = 1; 1204 /* Mark this func as external, the resolver will flip it again if 1205 it gets generated. */ 1206 DECL_EXTERNAL (func_decl) = 1; 1207 /* This will be of type IFUNCs have to be externally visible. */ 1208 TREE_PUBLIC (func_decl) = 1; 1209 1210 return func_decl; 1211 } 1212 1213 /* Returns true if decl is multi-versioned and DECL is the default function, 1214 that is it is not tagged with target specific optimization. */ 1215 1216 bool 1217 is_function_default_version (const tree decl) 1218 { 1219 if (TREE_CODE (decl) != FUNCTION_DECL 1220 || !DECL_FUNCTION_VERSIONED (decl)) 1221 return false; 1222 tree attr = lookup_attribute ("target", DECL_ATTRIBUTES (decl)); 1223 gcc_assert (attr); 1224 attr = TREE_VALUE (TREE_VALUE (attr)); 1225 return (TREE_CODE (attr) == STRING_CST 1226 && strcmp (TREE_STRING_POINTER (attr), "default") == 0); 1227 } 1228 1229 /* Return a declaration like DDECL except that its DECL_ATTRIBUTES 1230 is ATTRIBUTE. */ 1231 1232 tree 1233 build_decl_attribute_variant (tree ddecl, tree attribute) 1234 { 1235 DECL_ATTRIBUTES (ddecl) = attribute; 1236 return ddecl; 1237 } 1238 1239 /* Return a type like TTYPE except that its TYPE_ATTRIBUTE 1240 is ATTRIBUTE and its qualifiers are QUALS. 1241 1242 Record such modified types already made so we don't make duplicates. */ 1243 1244 tree 1245 build_type_attribute_qual_variant (tree otype, tree attribute, int quals) 1246 { 1247 tree ttype = otype; 1248 if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute)) 1249 { 1250 tree ntype; 1251 1252 /* Building a distinct copy of a tagged type is inappropriate; it 1253 causes breakage in code that expects there to be a one-to-one 1254 relationship between a struct and its fields. 1255 build_duplicate_type is another solution (as used in 1256 handle_transparent_union_attribute), but that doesn't play well 1257 with the stronger C++ type identity model. */ 1258 if (TREE_CODE (ttype) == RECORD_TYPE 1259 || TREE_CODE (ttype) == UNION_TYPE 1260 || TREE_CODE (ttype) == QUAL_UNION_TYPE 1261 || TREE_CODE (ttype) == ENUMERAL_TYPE) 1262 { 1263 warning (OPT_Wattributes, 1264 "ignoring attributes applied to %qT after definition", 1265 TYPE_MAIN_VARIANT (ttype)); 1266 return build_qualified_type (ttype, quals); 1267 } 1268 1269 ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED); 1270 if (lang_hooks.types.copy_lang_qualifiers 1271 && otype != TYPE_MAIN_VARIANT (otype)) 1272 ttype = (lang_hooks.types.copy_lang_qualifiers 1273 (ttype, TYPE_MAIN_VARIANT (otype))); 1274 1275 tree dtype = ntype = build_distinct_type_copy (ttype); 1276 1277 TYPE_ATTRIBUTES (ntype) = attribute; 1278 1279 hashval_t hash = type_hash_canon_hash (ntype); 1280 ntype = type_hash_canon (hash, ntype); 1281 1282 if (ntype != dtype) 1283 /* This variant was already in the hash table, don't mess with 1284 TYPE_CANONICAL. */; 1285 else if (TYPE_STRUCTURAL_EQUALITY_P (ttype) 1286 || !comp_type_attributes (ntype, ttype)) 1287 /* If the target-dependent attributes make NTYPE different from 1288 its canonical type, we will need to use structural equality 1289 checks for this type. 1290 1291 We shouldn't get here for stripping attributes from a type; 1292 the no-attribute type might not need structural comparison. But 1293 we can if was discarded from type_hash_table. */ 1294 SET_TYPE_STRUCTURAL_EQUALITY (ntype); 1295 else if (TYPE_CANONICAL (ntype) == ntype) 1296 TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype); 1297 1298 ttype = build_qualified_type (ntype, quals); 1299 if (lang_hooks.types.copy_lang_qualifiers 1300 && otype != TYPE_MAIN_VARIANT (otype)) 1301 ttype = lang_hooks.types.copy_lang_qualifiers (ttype, otype); 1302 } 1303 else if (TYPE_QUALS (ttype) != quals) 1304 ttype = build_qualified_type (ttype, quals); 1305 1306 return ttype; 1307 } 1308 1309 /* Compare two identifier nodes representing attributes. 1310 Return true if they are the same, false otherwise. */ 1311 1312 static bool 1313 cmp_attrib_identifiers (const_tree attr1, const_tree attr2) 1314 { 1315 /* Make sure we're dealing with IDENTIFIER_NODEs. */ 1316 gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE 1317 && TREE_CODE (attr2) == IDENTIFIER_NODE); 1318 1319 /* Identifiers can be compared directly for equality. */ 1320 if (attr1 == attr2) 1321 return true; 1322 1323 return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1), 1324 IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2)); 1325 } 1326 1327 /* Compare two constructor-element-type constants. Return 1 if the lists 1328 are known to be equal; otherwise return 0. */ 1329 1330 bool 1331 simple_cst_list_equal (const_tree l1, const_tree l2) 1332 { 1333 while (l1 != NULL_TREE && l2 != NULL_TREE) 1334 { 1335 if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1) 1336 return false; 1337 1338 l1 = TREE_CHAIN (l1); 1339 l2 = TREE_CHAIN (l2); 1340 } 1341 1342 return l1 == l2; 1343 } 1344 1345 /* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are 1346 the same. */ 1347 1348 static bool 1349 omp_declare_simd_clauses_equal (tree clauses1, tree clauses2) 1350 { 1351 tree cl1, cl2; 1352 for (cl1 = clauses1, cl2 = clauses2; 1353 cl1 && cl2; 1354 cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2)) 1355 { 1356 if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2)) 1357 return false; 1358 if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN) 1359 { 1360 if (simple_cst_equal (OMP_CLAUSE_DECL (cl1), 1361 OMP_CLAUSE_DECL (cl2)) != 1) 1362 return false; 1363 } 1364 switch (OMP_CLAUSE_CODE (cl1)) 1365 { 1366 case OMP_CLAUSE_ALIGNED: 1367 if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1), 1368 OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1) 1369 return false; 1370 break; 1371 case OMP_CLAUSE_LINEAR: 1372 if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1), 1373 OMP_CLAUSE_LINEAR_STEP (cl2)) != 1) 1374 return false; 1375 break; 1376 case OMP_CLAUSE_SIMDLEN: 1377 if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1), 1378 OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1) 1379 return false; 1380 default: 1381 break; 1382 } 1383 } 1384 return true; 1385 } 1386 1387 1388 /* Compare two attributes for their value identity. Return true if the 1389 attribute values are known to be equal; otherwise return false. */ 1390 1391 bool 1392 attribute_value_equal (const_tree attr1, const_tree attr2) 1393 { 1394 if (TREE_VALUE (attr1) == TREE_VALUE (attr2)) 1395 return true; 1396 1397 if (TREE_VALUE (attr1) != NULL_TREE 1398 && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST 1399 && TREE_VALUE (attr2) != NULL_TREE 1400 && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST) 1401 { 1402 /* Handle attribute format. */ 1403 if (is_attribute_p ("format", get_attribute_name (attr1))) 1404 { 1405 attr1 = TREE_VALUE (attr1); 1406 attr2 = TREE_VALUE (attr2); 1407 /* Compare the archetypes (printf/scanf/strftime/...). */ 1408 if (!cmp_attrib_identifiers (TREE_VALUE (attr1), TREE_VALUE (attr2))) 1409 return false; 1410 /* Archetypes are the same. Compare the rest. */ 1411 return (simple_cst_list_equal (TREE_CHAIN (attr1), 1412 TREE_CHAIN (attr2)) == 1); 1413 } 1414 return (simple_cst_list_equal (TREE_VALUE (attr1), 1415 TREE_VALUE (attr2)) == 1); 1416 } 1417 1418 if (TREE_VALUE (attr1) 1419 && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE 1420 && TREE_VALUE (attr2) 1421 && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE) 1422 return omp_declare_simd_clauses_equal (TREE_VALUE (attr1), 1423 TREE_VALUE (attr2)); 1424 1425 return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1); 1426 } 1427 1428 /* Return 0 if the attributes for two types are incompatible, 1 if they 1429 are compatible, and 2 if they are nearly compatible (which causes a 1430 warning to be generated). */ 1431 int 1432 comp_type_attributes (const_tree type1, const_tree type2) 1433 { 1434 const_tree a1 = TYPE_ATTRIBUTES (type1); 1435 const_tree a2 = TYPE_ATTRIBUTES (type2); 1436 const_tree a; 1437 1438 if (a1 == a2) 1439 return 1; 1440 for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a)) 1441 { 1442 const struct attribute_spec *as; 1443 const_tree attr; 1444 1445 as = lookup_attribute_spec (get_attribute_name (a)); 1446 if (!as || as->affects_type_identity == false) 1447 continue; 1448 1449 attr = lookup_attribute (as->name, CONST_CAST_TREE (a2)); 1450 if (!attr || !attribute_value_equal (a, attr)) 1451 break; 1452 } 1453 if (!a) 1454 { 1455 for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a)) 1456 { 1457 const struct attribute_spec *as; 1458 1459 as = lookup_attribute_spec (get_attribute_name (a)); 1460 if (!as || as->affects_type_identity == false) 1461 continue; 1462 1463 if (!lookup_attribute (as->name, CONST_CAST_TREE (a1))) 1464 break; 1465 /* We don't need to compare trees again, as we did this 1466 already in first loop. */ 1467 } 1468 /* All types - affecting identity - are equal, so 1469 there is no need to call target hook for comparison. */ 1470 if (!a) 1471 return 1; 1472 } 1473 if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a))) 1474 return 0; 1475 if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL) 1476 ^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL)) 1477 return 0; 1478 /* As some type combinations - like default calling-convention - might 1479 be compatible, we have to call the target hook to get the final result. */ 1480 return targetm.comp_type_attributes (type1, type2); 1481 } 1482 1483 /* PREDICATE acts as a function of type: 1484 1485 (const_tree attr, const attribute_spec *as) -> bool 1486 1487 where ATTR is an attribute and AS is its possibly-null specification. 1488 Return a list of every attribute in attribute list ATTRS for which 1489 PREDICATE is true. Return ATTRS itself if PREDICATE returns true 1490 for every attribute. */ 1491 1492 template<typename Predicate> 1493 tree 1494 remove_attributes_matching (tree attrs, Predicate predicate) 1495 { 1496 tree new_attrs = NULL_TREE; 1497 tree *ptr = &new_attrs; 1498 const_tree start = attrs; 1499 for (const_tree attr = attrs; attr; attr = TREE_CHAIN (attr)) 1500 { 1501 tree name = get_attribute_name (attr); 1502 const attribute_spec *as = lookup_attribute_spec (name); 1503 const_tree end; 1504 if (!predicate (attr, as)) 1505 end = attr; 1506 else if (start == attrs) 1507 continue; 1508 else 1509 end = TREE_CHAIN (attr); 1510 1511 for (; start != end; start = TREE_CHAIN (start)) 1512 { 1513 *ptr = tree_cons (TREE_PURPOSE (start), 1514 TREE_VALUE (start), NULL_TREE); 1515 TREE_CHAIN (*ptr) = NULL_TREE; 1516 ptr = &TREE_CHAIN (*ptr); 1517 } 1518 start = TREE_CHAIN (attr); 1519 } 1520 gcc_assert (!start || start == attrs); 1521 return start ? attrs : new_attrs; 1522 } 1523 1524 /* If VALUE is true, return the subset of ATTRS that affect type identity, 1525 otherwise return the subset of ATTRS that don't affect type identity. */ 1526 1527 tree 1528 affects_type_identity_attributes (tree attrs, bool value) 1529 { 1530 auto predicate = [value](const_tree, const attribute_spec *as) -> bool 1531 { 1532 return bool (as && as->affects_type_identity) == value; 1533 }; 1534 return remove_attributes_matching (attrs, predicate); 1535 } 1536 1537 /* Remove attributes that affect type identity from ATTRS unless the 1538 same attributes occur in OK_ATTRS. */ 1539 1540 tree 1541 restrict_type_identity_attributes_to (tree attrs, tree ok_attrs) 1542 { 1543 auto predicate = [ok_attrs](const_tree attr, 1544 const attribute_spec *as) -> bool 1545 { 1546 if (!as || !as->affects_type_identity) 1547 return true; 1548 1549 for (tree ok_attr = lookup_attribute (as->name, ok_attrs); 1550 ok_attr; 1551 ok_attr = lookup_attribute (as->name, TREE_CHAIN (ok_attr))) 1552 if (simple_cst_equal (TREE_VALUE (ok_attr), TREE_VALUE (attr)) == 1) 1553 return true; 1554 1555 return false; 1556 }; 1557 return remove_attributes_matching (attrs, predicate); 1558 } 1559 1560 /* Return a type like TTYPE except that its TYPE_ATTRIBUTE 1561 is ATTRIBUTE. 1562 1563 Record such modified types already made so we don't make duplicates. */ 1564 1565 tree 1566 build_type_attribute_variant (tree ttype, tree attribute) 1567 { 1568 return build_type_attribute_qual_variant (ttype, attribute, 1569 TYPE_QUALS (ttype)); 1570 } 1571 1572 /* A variant of lookup_attribute() that can be used with an identifier 1574 as the first argument, and where the identifier can be either 1575 'text' or '__text__'. 1576 1577 Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST, 1578 return a pointer to the attribute's list element if the attribute 1579 is part of the list, or NULL_TREE if not found. If the attribute 1580 appears more than once, this only returns the first occurrence; the 1581 TREE_CHAIN of the return value should be passed back in if further 1582 occurrences are wanted. ATTR_IDENTIFIER must be an identifier but 1583 can be in the form 'text' or '__text__'. */ 1584 static tree 1585 lookup_ident_attribute (tree attr_identifier, tree list) 1586 { 1587 gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE); 1588 1589 while (list) 1590 { 1591 gcc_checking_assert (TREE_CODE (get_attribute_name (list)) 1592 == IDENTIFIER_NODE); 1593 1594 if (cmp_attrib_identifiers (attr_identifier, 1595 get_attribute_name (list))) 1596 /* Found it. */ 1597 break; 1598 list = TREE_CHAIN (list); 1599 } 1600 1601 return list; 1602 } 1603 1604 /* Remove any instances of attribute ATTR_NAME in LIST and return the 1605 modified list. */ 1606 1607 tree 1608 remove_attribute (const char *attr_name, tree list) 1609 { 1610 tree *p; 1611 gcc_checking_assert (attr_name[0] != '_'); 1612 1613 for (p = &list; *p;) 1614 { 1615 tree l = *p; 1616 1617 tree attr = get_attribute_name (l); 1618 if (is_attribute_p (attr_name, attr)) 1619 *p = TREE_CHAIN (l); 1620 else 1621 p = &TREE_CHAIN (l); 1622 } 1623 1624 return list; 1625 } 1626 1627 /* Return an attribute list that is the union of a1 and a2. */ 1628 1629 tree 1630 merge_attributes (tree a1, tree a2) 1631 { 1632 tree attributes; 1633 1634 /* Either one unset? Take the set one. */ 1635 1636 if ((attributes = a1) == 0) 1637 attributes = a2; 1638 1639 /* One that completely contains the other? Take it. */ 1640 1641 else if (a2 != 0 && ! attribute_list_contained (a1, a2)) 1642 { 1643 if (attribute_list_contained (a2, a1)) 1644 attributes = a2; 1645 else 1646 { 1647 /* Pick the longest list, and hang on the other list. */ 1648 1649 if (list_length (a1) < list_length (a2)) 1650 attributes = a2, a2 = a1; 1651 1652 for (; a2 != 0; a2 = TREE_CHAIN (a2)) 1653 { 1654 tree a; 1655 for (a = lookup_ident_attribute (get_attribute_name (a2), 1656 attributes); 1657 a != NULL_TREE && !attribute_value_equal (a, a2); 1658 a = lookup_ident_attribute (get_attribute_name (a2), 1659 TREE_CHAIN (a))) 1660 ; 1661 if (a == NULL_TREE) 1662 { 1663 a1 = copy_node (a2); 1664 TREE_CHAIN (a1) = attributes; 1665 attributes = a1; 1666 } 1667 } 1668 } 1669 } 1670 return attributes; 1671 } 1672 1673 /* Given types T1 and T2, merge their attributes and return 1674 the result. */ 1675 1676 tree 1677 merge_type_attributes (tree t1, tree t2) 1678 { 1679 return merge_attributes (TYPE_ATTRIBUTES (t1), 1680 TYPE_ATTRIBUTES (t2)); 1681 } 1682 1683 /* Given decls OLDDECL and NEWDECL, merge their attributes and return 1684 the result. */ 1685 1686 tree 1687 merge_decl_attributes (tree olddecl, tree newdecl) 1688 { 1689 return merge_attributes (DECL_ATTRIBUTES (olddecl), 1690 DECL_ATTRIBUTES (newdecl)); 1691 } 1692 1693 /* Duplicate all attributes with name NAME in ATTR list to *ATTRS if 1694 they are missing there. */ 1695 1696 void 1697 duplicate_one_attribute (tree *attrs, tree attr, const char *name) 1698 { 1699 attr = lookup_attribute (name, attr); 1700 if (!attr) 1701 return; 1702 tree a = lookup_attribute (name, *attrs); 1703 while (attr) 1704 { 1705 tree a2; 1706 for (a2 = a; a2; a2 = lookup_attribute (name, TREE_CHAIN (a2))) 1707 if (attribute_value_equal (attr, a2)) 1708 break; 1709 if (!a2) 1710 { 1711 a2 = copy_node (attr); 1712 TREE_CHAIN (a2) = *attrs; 1713 *attrs = a2; 1714 } 1715 attr = lookup_attribute (name, TREE_CHAIN (attr)); 1716 } 1717 } 1718 1719 /* Duplicate all attributes from user DECL to the corresponding 1720 builtin that should be propagated. */ 1721 1722 void 1723 copy_attributes_to_builtin (tree decl) 1724 { 1725 tree b = builtin_decl_explicit (DECL_FUNCTION_CODE (decl)); 1726 if (b) 1727 duplicate_one_attribute (&DECL_ATTRIBUTES (b), 1728 DECL_ATTRIBUTES (decl), "omp declare simd"); 1729 } 1730 1731 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES 1732 1733 /* Specialization of merge_decl_attributes for various Windows targets. 1734 1735 This handles the following situation: 1736 1737 __declspec (dllimport) int foo; 1738 int foo; 1739 1740 The second instance of `foo' nullifies the dllimport. */ 1741 1742 tree 1743 merge_dllimport_decl_attributes (tree old, tree new_tree) 1744 { 1745 tree a; 1746 int delete_dllimport_p = 1; 1747 1748 /* What we need to do here is remove from `old' dllimport if it doesn't 1749 appear in `new'. dllimport behaves like extern: if a declaration is 1750 marked dllimport and a definition appears later, then the object 1751 is not dllimport'd. We also remove a `new' dllimport if the old list 1752 contains dllexport: dllexport always overrides dllimport, regardless 1753 of the order of declaration. */ 1754 if (!VAR_OR_FUNCTION_DECL_P (new_tree)) 1755 delete_dllimport_p = 0; 1756 else if (DECL_DLLIMPORT_P (new_tree) 1757 && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old))) 1758 { 1759 DECL_DLLIMPORT_P (new_tree) = 0; 1760 warning (OPT_Wattributes, "%q+D already declared with dllexport " 1761 "attribute: dllimport ignored", new_tree); 1762 } 1763 else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree)) 1764 { 1765 /* Warn about overriding a symbol that has already been used, e.g.: 1766 extern int __attribute__ ((dllimport)) foo; 1767 int* bar () {return &foo;} 1768 int foo; 1769 */ 1770 if (TREE_USED (old)) 1771 { 1772 warning (0, "%q+D redeclared without dllimport attribute " 1773 "after being referenced with dll linkage", new_tree); 1774 /* If we have used a variable's address with dllimport linkage, 1775 keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the 1776 decl may already have had TREE_CONSTANT computed. 1777 We still remove the attribute so that assembler code refers 1778 to '&foo rather than '_imp__foo'. */ 1779 if (VAR_P (old) && TREE_ADDRESSABLE (old)) 1780 DECL_DLLIMPORT_P (new_tree) = 1; 1781 } 1782 1783 /* Let an inline definition silently override the external reference, 1784 but otherwise warn about attribute inconsistency. */ 1785 else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree)) 1786 warning (OPT_Wattributes, "%q+D redeclared without dllimport " 1787 "attribute: previous dllimport ignored", new_tree); 1788 } 1789 else 1790 delete_dllimport_p = 0; 1791 1792 a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree)); 1793 1794 if (delete_dllimport_p) 1795 a = remove_attribute ("dllimport", a); 1796 1797 return a; 1798 } 1799 1800 /* Handle a "dllimport" or "dllexport" attribute; arguments as in 1801 struct attribute_spec.handler. */ 1802 1803 tree 1804 handle_dll_attribute (tree * pnode, tree name, tree args, int flags, 1805 bool *no_add_attrs) 1806 { 1807 tree node = *pnode; 1808 bool is_dllimport; 1809 1810 /* These attributes may apply to structure and union types being created, 1811 but otherwise should pass to the declaration involved. */ 1812 if (!DECL_P (node)) 1813 { 1814 if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT 1815 | (int) ATTR_FLAG_ARRAY_NEXT)) 1816 { 1817 *no_add_attrs = true; 1818 return tree_cons (name, args, NULL_TREE); 1819 } 1820 if (TREE_CODE (node) == RECORD_TYPE 1821 || TREE_CODE (node) == UNION_TYPE) 1822 { 1823 node = TYPE_NAME (node); 1824 if (!node) 1825 return NULL_TREE; 1826 } 1827 else 1828 { 1829 warning (OPT_Wattributes, "%qE attribute ignored", 1830 name); 1831 *no_add_attrs = true; 1832 return NULL_TREE; 1833 } 1834 } 1835 1836 if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL) 1837 { 1838 *no_add_attrs = true; 1839 warning (OPT_Wattributes, "%qE attribute ignored", 1840 name); 1841 return NULL_TREE; 1842 } 1843 1844 if (TREE_CODE (node) == TYPE_DECL 1845 && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE 1846 && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE) 1847 { 1848 *no_add_attrs = true; 1849 warning (OPT_Wattributes, "%qE attribute ignored", 1850 name); 1851 return NULL_TREE; 1852 } 1853 1854 is_dllimport = is_attribute_p ("dllimport", name); 1855 1856 /* Report error on dllimport ambiguities seen now before they cause 1857 any damage. */ 1858 if (is_dllimport) 1859 { 1860 /* Honor any target-specific overrides. */ 1861 if (!targetm.valid_dllimport_attribute_p (node)) 1862 *no_add_attrs = true; 1863 1864 else if (TREE_CODE (node) == FUNCTION_DECL 1865 && DECL_DECLARED_INLINE_P (node)) 1866 { 1867 warning (OPT_Wattributes, "inline function %q+D declared as " 1868 "dllimport: attribute ignored", node); 1869 *no_add_attrs = true; 1870 } 1871 /* Like MS, treat definition of dllimported variables and 1872 non-inlined functions on declaration as syntax errors. */ 1873 else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node)) 1874 { 1875 error ("function %q+D definition is marked dllimport", node); 1876 *no_add_attrs = true; 1877 } 1878 1879 else if (VAR_P (node)) 1880 { 1881 if (DECL_INITIAL (node)) 1882 { 1883 error ("variable %q+D definition is marked dllimport", 1884 node); 1885 *no_add_attrs = true; 1886 } 1887 1888 /* `extern' needn't be specified with dllimport. 1889 Specify `extern' now and hope for the best. Sigh. */ 1890 DECL_EXTERNAL (node) = 1; 1891 /* Also, implicitly give dllimport'd variables declared within 1892 a function global scope, unless declared static. */ 1893 if (current_function_decl != NULL_TREE && !TREE_STATIC (node)) 1894 TREE_PUBLIC (node) = 1; 1895 /* Clear TREE_STATIC because DECL_EXTERNAL is set, unless 1896 it is a C++ static data member. */ 1897 if (DECL_CONTEXT (node) == NULL_TREE 1898 || !RECORD_OR_UNION_TYPE_P (DECL_CONTEXT (node))) 1899 TREE_STATIC (node) = 0; 1900 } 1901 1902 if (*no_add_attrs == false) 1903 DECL_DLLIMPORT_P (node) = 1; 1904 } 1905 else if (TREE_CODE (node) == FUNCTION_DECL 1906 && DECL_DECLARED_INLINE_P (node) 1907 && flag_keep_inline_dllexport) 1908 /* An exported function, even if inline, must be emitted. */ 1909 DECL_EXTERNAL (node) = 0; 1910 1911 /* Report error if symbol is not accessible at global scope. */ 1912 if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node)) 1913 { 1914 error ("external linkage required for symbol %q+D because of " 1915 "%qE attribute", node, name); 1916 *no_add_attrs = true; 1917 } 1918 1919 /* A dllexport'd entity must have default visibility so that other 1920 program units (shared libraries or the main executable) can see 1921 it. A dllimport'd entity must have default visibility so that 1922 the linker knows that undefined references within this program 1923 unit can be resolved by the dynamic linker. */ 1924 if (!*no_add_attrs) 1925 { 1926 if (DECL_VISIBILITY_SPECIFIED (node) 1927 && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT) 1928 error ("%qE implies default visibility, but %qD has already " 1929 "been declared with a different visibility", 1930 name, node); 1931 DECL_VISIBILITY (node) = VISIBILITY_DEFAULT; 1932 DECL_VISIBILITY_SPECIFIED (node) = 1; 1933 } 1934 1935 return NULL_TREE; 1936 } 1937 1938 #endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES */ 1939 1940 /* Given two lists of attributes, return true if list l2 is 1941 equivalent to l1. */ 1942 1943 int 1944 attribute_list_equal (const_tree l1, const_tree l2) 1945 { 1946 if (l1 == l2) 1947 return 1; 1948 1949 return attribute_list_contained (l1, l2) 1950 && attribute_list_contained (l2, l1); 1951 } 1952 1953 /* Given two lists of attributes, return true if list L2 is 1954 completely contained within L1. */ 1955 /* ??? This would be faster if attribute names were stored in a canonicalized 1956 form. Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method 1957 must be used to show these elements are equivalent (which they are). */ 1958 /* ??? It's not clear that attributes with arguments will always be handled 1959 correctly. */ 1960 1961 int 1962 attribute_list_contained (const_tree l1, const_tree l2) 1963 { 1964 const_tree t1, t2; 1965 1966 /* First check the obvious, maybe the lists are identical. */ 1967 if (l1 == l2) 1968 return 1; 1969 1970 /* Maybe the lists are similar. */ 1971 for (t1 = l1, t2 = l2; 1972 t1 != 0 && t2 != 0 1973 && get_attribute_name (t1) == get_attribute_name (t2) 1974 && TREE_VALUE (t1) == TREE_VALUE (t2); 1975 t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) 1976 ; 1977 1978 /* Maybe the lists are equal. */ 1979 if (t1 == 0 && t2 == 0) 1980 return 1; 1981 1982 for (; t2 != 0; t2 = TREE_CHAIN (t2)) 1983 { 1984 const_tree attr; 1985 /* This CONST_CAST is okay because lookup_attribute does not 1986 modify its argument and the return value is assigned to a 1987 const_tree. */ 1988 for (attr = lookup_ident_attribute (get_attribute_name (t2), 1989 CONST_CAST_TREE (l1)); 1990 attr != NULL_TREE && !attribute_value_equal (t2, attr); 1991 attr = lookup_ident_attribute (get_attribute_name (t2), 1992 TREE_CHAIN (attr))) 1993 ; 1994 1995 if (attr == NULL_TREE) 1996 return 0; 1997 } 1998 1999 return 1; 2000 } 2001 2002 /* The backbone of lookup_attribute(). ATTR_LEN is the string length 2003 of ATTR_NAME, and LIST is not NULL_TREE. 2004 2005 The function is called from lookup_attribute in order to optimize 2006 for size. */ 2007 2008 tree 2009 private_lookup_attribute (const char *attr_name, size_t attr_len, tree list) 2010 { 2011 while (list) 2012 { 2013 tree attr = get_attribute_name (list); 2014 size_t ident_len = IDENTIFIER_LENGTH (attr); 2015 if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr), 2016 ident_len)) 2017 break; 2018 list = TREE_CHAIN (list); 2019 } 2020 2021 return list; 2022 } 2023 2024 /* Return true if the function decl or type NODE has been declared 2025 with attribute ANAME among attributes ATTRS. */ 2026 2027 static bool 2028 has_attribute (tree node, tree attrs, const char *aname) 2029 { 2030 if (!strcmp (aname, "const")) 2031 { 2032 if (DECL_P (node) && TREE_READONLY (node)) 2033 return true; 2034 } 2035 else if (!strcmp (aname, "malloc")) 2036 { 2037 if (DECL_P (node) && DECL_IS_MALLOC (node)) 2038 return true; 2039 } 2040 else if (!strcmp (aname, "noreturn")) 2041 { 2042 if (DECL_P (node) && TREE_THIS_VOLATILE (node)) 2043 return true; 2044 } 2045 else if (!strcmp (aname, "nothrow")) 2046 { 2047 if (TREE_NOTHROW (node)) 2048 return true; 2049 } 2050 else if (!strcmp (aname, "pure")) 2051 { 2052 if (DECL_P (node) && DECL_PURE_P (node)) 2053 return true; 2054 } 2055 2056 return lookup_attribute (aname, attrs); 2057 } 2058 2059 /* Return the number of mismatched function or type attributes between 2060 the "template" function declaration TMPL and DECL. The word "template" 2061 doesn't necessarily refer to a C++ template but rather a declaration 2062 whose attributes should be matched by those on DECL. For a non-zero 2063 return value set *ATTRSTR to a string representation of the list of 2064 mismatched attributes with quoted names. 2065 ATTRLIST is a list of additional attributes that SPEC should be 2066 taken to ultimately be declared with. */ 2067 2068 unsigned 2069 decls_mismatched_attributes (tree tmpl, tree decl, tree attrlist, 2070 const char* const blacklist[], 2071 pretty_printer *attrstr) 2072 { 2073 if (TREE_CODE (tmpl) != FUNCTION_DECL) 2074 return 0; 2075 2076 /* Avoid warning if either declaration or its type is deprecated. */ 2077 if (TREE_DEPRECATED (tmpl) 2078 || TREE_DEPRECATED (decl)) 2079 return 0; 2080 2081 const tree tmpls[] = { tmpl, TREE_TYPE (tmpl) }; 2082 const tree decls[] = { decl, TREE_TYPE (decl) }; 2083 2084 if (TREE_DEPRECATED (tmpls[1]) 2085 || TREE_DEPRECATED (decls[1]) 2086 || TREE_DEPRECATED (TREE_TYPE (tmpls[1])) 2087 || TREE_DEPRECATED (TREE_TYPE (decls[1]))) 2088 return 0; 2089 2090 tree tmpl_attrs[] = { DECL_ATTRIBUTES (tmpl), TYPE_ATTRIBUTES (tmpls[1]) }; 2091 tree decl_attrs[] = { DECL_ATTRIBUTES (decl), TYPE_ATTRIBUTES (decls[1]) }; 2092 2093 if (!decl_attrs[0]) 2094 decl_attrs[0] = attrlist; 2095 else if (!decl_attrs[1]) 2096 decl_attrs[1] = attrlist; 2097 2098 /* Avoid warning if the template has no attributes. */ 2099 if (!tmpl_attrs[0] && !tmpl_attrs[1]) 2100 return 0; 2101 2102 /* Avoid warning if either declaration contains an attribute on 2103 the white list below. */ 2104 const char* const whitelist[] = { 2105 "error", "warning" 2106 }; 2107 2108 for (unsigned i = 0; i != 2; ++i) 2109 for (unsigned j = 0; j != sizeof whitelist / sizeof *whitelist; ++j) 2110 if (lookup_attribute (whitelist[j], tmpl_attrs[i]) 2111 || lookup_attribute (whitelist[j], decl_attrs[i])) 2112 return 0; 2113 2114 /* Put together a list of the black-listed attributes that the template 2115 is declared with and the declaration is not, in case it's not apparent 2116 from the most recent declaration of the template. */ 2117 unsigned nattrs = 0; 2118 2119 for (unsigned i = 0; blacklist[i]; ++i) 2120 { 2121 /* Attribute leaf only applies to extern functions. Avoid mentioning 2122 it when it's missing from a static declaration. */ 2123 if (!TREE_PUBLIC (decl) 2124 && !strcmp ("leaf", blacklist[i])) 2125 continue; 2126 2127 for (unsigned j = 0; j != 2; ++j) 2128 { 2129 if (!has_attribute (tmpls[j], tmpl_attrs[j], blacklist[i])) 2130 continue; 2131 2132 bool found = false; 2133 unsigned kmax = 1 + !!decl_attrs[1]; 2134 for (unsigned k = 0; k != kmax; ++k) 2135 { 2136 if (has_attribute (decls[k], decl_attrs[k], blacklist[i])) 2137 { 2138 found = true; 2139 break; 2140 } 2141 } 2142 2143 if (!found) 2144 { 2145 if (nattrs) 2146 pp_string (attrstr, ", "); 2147 pp_begin_quote (attrstr, pp_show_color (global_dc->printer)); 2148 pp_string (attrstr, blacklist[i]); 2149 pp_end_quote (attrstr, pp_show_color (global_dc->printer)); 2150 ++nattrs; 2151 } 2152 2153 break; 2154 } 2155 } 2156 2157 return nattrs; 2158 } 2159 2160 /* Issue a warning for the declaration ALIAS for TARGET where ALIAS 2161 specifies either attributes that are incompatible with those of 2162 TARGET, or attributes that are missing and that declaring ALIAS 2163 with would benefit. */ 2164 2165 void 2166 maybe_diag_alias_attributes (tree alias, tree target) 2167 { 2168 /* Do not expect attributes to match between aliases and ifunc 2169 resolvers. There is no obvious correspondence between them. */ 2170 if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (alias))) 2171 return; 2172 2173 const char* const blacklist[] = { 2174 "alloc_align", "alloc_size", "cold", "const", "hot", "leaf", "malloc", 2175 "nonnull", "noreturn", "nothrow", "pure", "returns_nonnull", 2176 "returns_twice", NULL 2177 }; 2178 2179 pretty_printer attrnames; 2180 if (warn_attribute_alias > 1) 2181 { 2182 /* With -Wattribute-alias=2 detect alias declarations that are more 2183 restrictive than their targets first. Those indicate potential 2184 codegen bugs. */ 2185 if (unsigned n = decls_mismatched_attributes (alias, target, NULL_TREE, 2186 blacklist, &attrnames)) 2187 { 2188 auto_diagnostic_group d; 2189 if (warning_n (DECL_SOURCE_LOCATION (alias), 2190 OPT_Wattribute_alias_, n, 2191 "%qD specifies more restrictive attribute than " 2192 "its target %qD: %s", 2193 "%qD specifies more restrictive attributes than " 2194 "its target %qD: %s", 2195 alias, target, pp_formatted_text (&attrnames))) 2196 inform (DECL_SOURCE_LOCATION (target), 2197 "%qD target declared here", alias); 2198 return; 2199 } 2200 } 2201 2202 /* Detect alias declarations that are less restrictive than their 2203 targets. Those suggest potential optimization opportunities 2204 (solved by adding the missing attribute(s) to the alias). */ 2205 if (unsigned n = decls_mismatched_attributes (target, alias, NULL_TREE, 2206 blacklist, &attrnames)) 2207 { 2208 auto_diagnostic_group d; 2209 if (warning_n (DECL_SOURCE_LOCATION (alias), 2210 OPT_Wmissing_attributes, n, 2211 "%qD specifies less restrictive attribute than " 2212 "its target %qD: %s", 2213 "%qD specifies less restrictive attributes than " 2214 "its target %qD: %s", 2215 alias, target, pp_formatted_text (&attrnames))) 2216 inform (DECL_SOURCE_LOCATION (target), 2217 "%qD target declared here", alias); 2218 } 2219 } 2220 2221 /* Initialize a mapping RWM for a call to a function declared with 2222 attribute access in ATTRS. Each attribute positional operand 2223 inserts one entry into the mapping with the operand number as 2224 the key. */ 2225 2226 void 2227 init_attr_rdwr_indices (rdwr_map *rwm, tree attrs) 2228 { 2229 if (!attrs) 2230 return; 2231 2232 for (tree access = attrs; 2233 (access = lookup_attribute ("access", access)); 2234 access = TREE_CHAIN (access)) 2235 { 2236 /* The TREE_VALUE of an attribute is a TREE_LIST whose TREE_VALUE 2237 is the attribute argument's value. */ 2238 tree mode = TREE_VALUE (access); 2239 if (!mode) 2240 return; 2241 2242 /* The (optional) list of VLA bounds. */ 2243 tree vblist = TREE_CHAIN (mode); 2244 mode = TREE_VALUE (mode); 2245 if (TREE_CODE (mode) != STRING_CST) 2246 continue; 2247 gcc_assert (TREE_CODE (mode) == STRING_CST); 2248 2249 if (vblist) 2250 vblist = nreverse (copy_list (TREE_VALUE (vblist))); 2251 2252 for (const char *m = TREE_STRING_POINTER (mode); *m; ) 2253 { 2254 attr_access acc = { }; 2255 2256 /* Skip the internal-only plus sign. */ 2257 if (*m == '+') 2258 ++m; 2259 2260 acc.str = m; 2261 acc.mode = acc.from_mode_char (*m); 2262 acc.sizarg = UINT_MAX; 2263 2264 const char *end; 2265 acc.ptrarg = strtoul (++m, const_cast<char**>(&end), 10); 2266 m = end; 2267 2268 if (*m == '[') 2269 { 2270 /* Forms containing the square bracket are internal-only 2271 (not specified by an attribute declaration), and used 2272 for various forms of array and VLA parameters. */ 2273 acc.internal_p = true; 2274 2275 /* Search to the closing bracket and look at the preceding 2276 code: it determines the form of the most significant 2277 bound of the array. Others prior to it encode the form 2278 of interior VLA bounds. They're not of interest here. */ 2279 end = strchr (m, ']'); 2280 const char *p = end; 2281 gcc_assert (p); 2282 2283 while (ISDIGIT (p[-1])) 2284 --p; 2285 2286 if (ISDIGIT (*p)) 2287 { 2288 /* A digit denotes a constant bound (as in T[3]). */ 2289 acc.static_p = p[-1] == 's'; 2290 acc.minsize = strtoull (p, NULL, 10); 2291 } 2292 else if (' ' == p[-1]) 2293 { 2294 /* A space denotes an ordinary array of unspecified bound 2295 (as in T[]). */ 2296 acc.minsize = 0; 2297 } 2298 else if ('*' == p[-1] || '$' == p[-1]) 2299 { 2300 /* An asterisk denotes a VLA. When the closing bracket 2301 is followed by a comma and a dollar sign its bound is 2302 on the list. Otherwise it's a VLA with an unspecified 2303 bound. */ 2304 acc.static_p = p[-2] == 's'; 2305 acc.minsize = HOST_WIDE_INT_M1U; 2306 } 2307 2308 m = end + 1; 2309 } 2310 2311 if (*m == ',') 2312 { 2313 ++m; 2314 do 2315 { 2316 if (*m == '$') 2317 { 2318 ++m; 2319 if (!acc.size && vblist) 2320 { 2321 /* Extract the list of VLA bounds for the current 2322 parameter, store it in ACC.SIZE, and advance 2323 to the list of bounds for the next VLA parameter. 2324 */ 2325 acc.size = TREE_VALUE (vblist); 2326 vblist = TREE_CHAIN (vblist); 2327 } 2328 } 2329 2330 if (ISDIGIT (*m)) 2331 { 2332 /* Extract the positional argument. It's absent 2333 for VLAs whose bound doesn't name a function 2334 parameter. */ 2335 unsigned pos = strtoul (m, const_cast<char**>(&end), 10); 2336 if (acc.sizarg == UINT_MAX) 2337 acc.sizarg = pos; 2338 m = end; 2339 } 2340 } 2341 while (*m == '$'); 2342 } 2343 2344 acc.end = m; 2345 2346 bool existing; 2347 auto &ref = rwm->get_or_insert (acc.ptrarg, &existing); 2348 if (existing) 2349 { 2350 /* Merge the new spec with the existing. */ 2351 if (acc.minsize == HOST_WIDE_INT_M1U) 2352 ref.minsize = HOST_WIDE_INT_M1U; 2353 2354 if (acc.sizarg != UINT_MAX) 2355 ref.sizarg = acc.sizarg; 2356 2357 if (acc.mode) 2358 ref.mode = acc.mode; 2359 } 2360 else 2361 ref = acc; 2362 2363 /* Unconditionally add an entry for the required pointer 2364 operand of the attribute, and one for the optional size 2365 operand when it's specified. */ 2366 if (acc.sizarg != UINT_MAX) 2367 rwm->put (acc.sizarg, acc); 2368 } 2369 } 2370 } 2371 2372 /* Return the access specification for a function parameter PARM 2373 or null if the current function has no such specification. */ 2374 2375 attr_access * 2376 get_parm_access (rdwr_map &rdwr_idx, tree parm, 2377 tree fndecl /* = current_function_decl */) 2378 { 2379 tree fntype = TREE_TYPE (fndecl); 2380 init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype)); 2381 2382 if (rdwr_idx.is_empty ()) 2383 return NULL; 2384 2385 unsigned argpos = 0; 2386 tree fnargs = DECL_ARGUMENTS (fndecl); 2387 for (tree arg = fnargs; arg; arg = TREE_CHAIN (arg), ++argpos) 2388 if (arg == parm) 2389 return rdwr_idx.get (argpos); 2390 2391 return NULL; 2392 } 2393 2394 /* Return the internal representation as STRING_CST. Internal positional 2395 arguments are zero-based. */ 2396 2397 tree 2398 attr_access::to_internal_string () const 2399 { 2400 return build_string (end - str, str); 2401 } 2402 2403 /* Return the human-readable representation of the external attribute 2404 specification (as it might appear in the source code) as STRING_CST. 2405 External positional arguments are one-based. */ 2406 2407 tree 2408 attr_access::to_external_string () const 2409 { 2410 char buf[80]; 2411 gcc_assert (mode != access_deferred); 2412 int len = snprintf (buf, sizeof buf, "access (%s, %u", 2413 mode_names[mode], ptrarg + 1); 2414 if (sizarg != UINT_MAX) 2415 len += snprintf (buf + len, sizeof buf - len, ", %u", sizarg + 1); 2416 strcpy (buf + len, ")"); 2417 return build_string (len + 2, buf); 2418 } 2419 2420 /* Return the number of specified VLA bounds and set *nunspec to 2421 the number of unspecified ones (those designated by [*]). */ 2422 2423 unsigned 2424 attr_access::vla_bounds (unsigned *nunspec) const 2425 { 2426 unsigned nbounds = 0; 2427 *nunspec = 0; 2428 /* STR points to the beginning of the specified string for the current 2429 argument that may be followed by the string for the next argument. */ 2430 for (const char* p = strchr (str, ']'); p && *p != '['; --p) 2431 { 2432 if (*p == '*') 2433 ++*nunspec; 2434 else if (*p == '$') 2435 ++nbounds; 2436 } 2437 return nbounds; 2438 } 2439 2440 /* Reset front end-specific attribute access data from ATTRS. 2441 Called from the free_lang_data pass. */ 2442 2443 /* static */ void 2444 attr_access::free_lang_data (tree attrs) 2445 { 2446 for (tree acs = attrs; (acs = lookup_attribute ("access", acs)); 2447 acs = TREE_CHAIN (acs)) 2448 { 2449 tree vblist = TREE_VALUE (acs); 2450 vblist = TREE_CHAIN (vblist); 2451 if (!vblist) 2452 continue; 2453 2454 for (vblist = TREE_VALUE (vblist); vblist; vblist = TREE_CHAIN (vblist)) 2455 { 2456 tree *pvbnd = &TREE_VALUE (vblist); 2457 if (!*pvbnd || DECL_P (*pvbnd)) 2458 continue; 2459 2460 /* VLA bounds that are expressions as opposed to DECLs are 2461 only used in the front end. Reset them to keep front end 2462 trees leaking into the middle end (see pr97172) and to 2463 free up memory. */ 2464 *pvbnd = NULL_TREE; 2465 } 2466 } 2467 2468 for (tree argspec = attrs; (argspec = lookup_attribute ("arg spec", argspec)); 2469 argspec = TREE_CHAIN (argspec)) 2470 { 2471 /* Same as above. */ 2472 tree *pvblist = &TREE_VALUE (argspec); 2473 *pvblist = NULL_TREE; 2474 } 2475 } 2476 2477 /* Defined in attr_access. */ 2478 constexpr char attr_access::mode_chars[]; 2479 constexpr char attr_access::mode_names[][11]; 2480 2481 /* Format an array, including a VLA, pointed to by TYPE and used as 2482 a function parameter as a human-readable string. ACC describes 2483 an access to the parameter and is used to determine the outermost 2484 form of the array including its bound which is otherwise obviated 2485 by its decay to pointer. Return the formatted string. */ 2486 2487 std::string 2488 attr_access::array_as_string (tree type) const 2489 { 2490 std::string typstr; 2491 2492 if (type == error_mark_node) 2493 return std::string (); 2494 2495 if (this->str) 2496 { 2497 /* For array parameters (but not pointers) create a temporary array 2498 type that corresponds to the form of the parameter including its 2499 qualifiers even though they apply to the pointer, not the array 2500 type. */ 2501 const bool vla_p = minsize == HOST_WIDE_INT_M1U; 2502 tree eltype = TREE_TYPE (type); 2503 tree index_type = NULL_TREE; 2504 2505 if (minsize == HOST_WIDE_INT_M1U) 2506 { 2507 /* Determine if this is a VLA (an array whose most significant 2508 bound is nonconstant and whose access string has "$]" in it) 2509 extract the bound expression from SIZE. */ 2510 const char *p = end; 2511 for ( ; p != str && *p-- != ']'; ); 2512 if (*p == '$') 2513 /* SIZE may have been cleared. Use it with care. */ 2514 index_type = build_index_type (size ? TREE_VALUE (size) : size); 2515 } 2516 else if (minsize) 2517 index_type = build_index_type (size_int (minsize - 1)); 2518 2519 tree arat = NULL_TREE; 2520 if (static_p || vla_p) 2521 { 2522 tree flag = static_p ? integer_one_node : NULL_TREE; 2523 /* Hack: there's no language-independent way to encode 2524 the "static" specifier or the "*" notation in an array type. 2525 Add a "fake" attribute to have the pretty-printer add "static" 2526 or "*". The "[static N]" notation is only valid in the most 2527 significant bound but [*] can be used for any bound. Because 2528 [*] is represented the same as [0] this hack only works for 2529 the most significant bound like static and the others are 2530 rendered as [0]. */ 2531 arat = build_tree_list (get_identifier ("array"), flag); 2532 } 2533 2534 const int quals = TYPE_QUALS (type); 2535 type = build_array_type (eltype, index_type); 2536 type = build_type_attribute_qual_variant (type, arat, quals); 2537 } 2538 2539 /* Format the type using the current pretty printer. The generic tree 2540 printer does a terrible job. */ 2541 pretty_printer *pp = global_dc->printer->clone (); 2542 pp_printf (pp, "%qT", type); 2543 typstr = pp_formatted_text (pp); 2544 delete pp; 2545 2546 return typstr; 2547 } 2548 2549 #if CHECKING_P 2550 2551 namespace selftest 2552 { 2553 2554 /* Helper types to verify the consistency attribute exclusions. */ 2555 2556 typedef std::pair<const char *, const char *> excl_pair; 2557 2558 struct excl_hash_traits: typed_noop_remove<excl_pair> 2559 { 2560 typedef excl_pair value_type; 2561 typedef value_type compare_type; 2562 2563 static hashval_t hash (const value_type &x) 2564 { 2565 hashval_t h1 = htab_hash_string (x.first); 2566 hashval_t h2 = htab_hash_string (x.second); 2567 return h1 ^ h2; 2568 } 2569 2570 static bool equal (const value_type &x, const value_type &y) 2571 { 2572 return !strcmp (x.first, y.first) && !strcmp (x.second, y.second); 2573 } 2574 2575 static void mark_deleted (value_type &x) 2576 { 2577 x = value_type (NULL, NULL); 2578 } 2579 2580 static const bool empty_zero_p = false; 2581 2582 static void mark_empty (value_type &x) 2583 { 2584 x = value_type ("", ""); 2585 } 2586 2587 static bool is_deleted (const value_type &x) 2588 { 2589 return !x.first && !x.second; 2590 } 2591 2592 static bool is_empty (const value_type &x) 2593 { 2594 return !*x.first && !*x.second; 2595 } 2596 }; 2597 2598 2599 /* Self-test to verify that each attribute exclusion is symmetric, 2600 meaning that if attribute A is encoded as incompatible with 2601 attribute B then the opposite relationship is also encoded. 2602 This test also detects most cases of misspelled attribute names 2603 in exclusions. */ 2604 2605 static void 2606 test_attribute_exclusions () 2607 { 2608 /* Iterate over the array of attribute tables first (with TI0 as 2609 the index) and over the array of attribute_spec in each table 2610 (with SI0 as the index). */ 2611 const size_t ntables = ARRAY_SIZE (attribute_tables); 2612 2613 /* Set of pairs of mutually exclusive attributes. */ 2614 typedef hash_set<excl_pair, false, excl_hash_traits> exclusion_set; 2615 exclusion_set excl_set; 2616 2617 for (size_t ti0 = 0; ti0 != ntables; ++ti0) 2618 for (size_t s0 = 0; attribute_tables[ti0][s0].name; ++s0) 2619 { 2620 const attribute_spec::exclusions *excl 2621 = attribute_tables[ti0][s0].exclude; 2622 2623 /* Skip each attribute that doesn't define exclusions. */ 2624 if (!excl) 2625 continue; 2626 2627 const char *attr_name = attribute_tables[ti0][s0].name; 2628 2629 /* Iterate over the set of exclusions for every attribute 2630 (with EI0 as the index) adding the exclusions defined 2631 for each to the set. */ 2632 for (size_t ei0 = 0; excl[ei0].name; ++ei0) 2633 { 2634 const char *excl_name = excl[ei0].name; 2635 2636 if (!strcmp (attr_name, excl_name)) 2637 continue; 2638 2639 excl_set.add (excl_pair (attr_name, excl_name)); 2640 } 2641 } 2642 2643 /* Traverse the set of mutually exclusive pairs of attributes 2644 and verify that they are symmetric. */ 2645 for (exclusion_set::iterator it = excl_set.begin (); 2646 it != excl_set.end (); 2647 ++it) 2648 { 2649 if (!excl_set.contains (excl_pair ((*it).second, (*it).first))) 2650 { 2651 /* An exclusion for an attribute has been found that 2652 doesn't have a corresponding exclusion in the opposite 2653 direction. */ 2654 char desc[120]; 2655 sprintf (desc, "'%s' attribute exclusion '%s' must be symmetric", 2656 (*it).first, (*it).second); 2657 fail (SELFTEST_LOCATION, desc); 2658 } 2659 } 2660 } 2661 2662 void 2663 attribs_cc_tests () 2664 { 2665 test_attribute_exclusions (); 2666 } 2667 2668 } /* namespace selftest */ 2669 2670 #endif /* CHECKING_P */ 2671