From patchwork Tue Aug 8 16:13:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 799309 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-460036-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="XejdfAKS"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xRfcS03TNz9s71 for ; Wed, 9 Aug 2017 02:14:46 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; q=dns; s= default; b=NKEm+1fKT7BsK6V5OfXPzk73I8gvqFZF1F1a5iFBt+unT82p5GKij mmah/La58wkrahbIGlEFOw434XpADOIabqtJBVI8w3TFd4JhnFBzVs7FdGJXbHDm KTHTwRYgcseRyaFpOBwOu5ZLmzk2aN4AJzaPm0F//wlveQIGyrK3lE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; s= default; bh=SUnXqW7Kk+swVthH1kaeYG0KIc8=; b=XejdfAKSfTExhKUBHGEN rmD4QNiqRmHcZPGPZY6K1eIePw6D6Op+OKrpPNfR38EFvJYPsVGFygAfdoFO99av OXoillKqjCUig8ZB83K1v6niHz+wPExEGmY+jk+K/MBPXoymGsEMzojavroz90YG s4FsDBuk/wJLmdzXu/0xKTE= Received: (qmail 88237 invoked by alias); 8 Aug 2017 16:14:15 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 83251 invoked by uid 89); 8 Aug 2017 16:13:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.0 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=bark X-HELO: mail-qk0-f170.google.com Received: from mail-qk0-f170.google.com (HELO mail-qk0-f170.google.com) (209.85.220.170) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 08 Aug 2017 16:13:11 +0000 Received: by mail-qk0-f170.google.com with SMTP id d136so22227499qkg.3 for ; Tue, 08 Aug 2017 09:13:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:subject:to:message-id:date:user-agent :mime-version; bh=2IhXuLlAtz2r1Cowq9xLBJDABNWIVDJWzS5sbv5MvK4=; b=Cp6oSUOTe4VYO5P5tseZdZy2ergH0U88UdOMKgYuihv4K9LLZtYggUYR65NIVR3UK7 1bYLw1DLMhyTuT3QgLiDSd/CtrtvWtwJWR3GjtnBE9XKCKnONpyB0pKv+13WisqGRkIP cV98Z8CBfm892Pr7S9/RlTHnCWaLjAiYQCOgdCEpJjSCI5NC/+kj0NFwOOFrW35EwKdD QTEDrUWQ/Te3GhDuDTC0yH/iofu8nprYbYI5rIKzGp1lXojrbOgDm5PVfWlklPYldN+H Hia2k1WBO6vMsBy6wjLyB/T/dK1tZoFPFATXxUzrFyRESsNrkg9FA1fUm8vpAlsPYzsC Ir+g== X-Gm-Message-State: AHYfb5gf2VJ9KGX4Eg+Hzmk6+Mt5DmyjT+EwOiP0X3sYa3GnyOGqwzgw F3zU+F9gO65ugA== X-Received: by 10.55.86.199 with SMTP id k190mr5983729qkb.125.1502208790057; Tue, 08 Aug 2017 09:13:10 -0700 (PDT) Received: from localhost.localdomain (174-16-105-12.hlrn.qwest.net. [174.16.105.12]) by smtp.gmail.com with ESMTPSA id f55sm852596qtc.18.2017.08.08.09.13.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 08 Aug 2017 09:13:09 -0700 (PDT) From: Martin Sebor Subject: [PATCH 1/3] improve detection of attribute conflicts (PR 81544) To: Gcc Patch List , Marek Polacek , Joseph Myers , Jason Merrill Message-ID: Date: Tue, 8 Aug 2017 10:13:07 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0 MIME-Version: 1.0 X-IsSubscribed: yes Part 1 of the patch series is the core of the enhancement without the (trivial) changes to the back ends and front ends other than C and C++. Marek, I tried to follow what we discussed in IRC. Please let me know if I missed something. Joseph, I read your comments on Marek's patch for the same bug: https://gcc.gnu.org/ml/gcc-patches/2017-07/msg02077.html I had to make some changes to meet that expectation, in part because decl_attributes reorders attributes, but with those I believe it does what you expect. Jason, I'd appreciate your review of the C++ bits. I couldn't find a better way of finding an existing declaration of a function given one that's about to be introduced, but it feels like there ought to be an existing API somewhere that I missed. Martin PR c/81544 - attribute noreturn and warn_unused_result on the same function accepted gcc/c/ChangeLog: PR c/81544 * c-decl.c (c_decl_attributes): Look up existing declaration and pass it to decl_attributes. gcc/c-family/ChangeLog: PR c/81544 * c-attribs.c (attr_aligned_exclusions): New array. (attr_alloc_exclusions, attr_cold_hot_exclusions): Same. (attr_common_exclusions, attr_const_pure_exclusions): Same. (attr_gnu_inline_exclusions, attr_inline_exclusions): Same. (attr_noreturn_exclusions, attr_returns_twice_exclusions): Same. (attr_warn_unused_result_exclusions): Same. (handle_hot_attribute, handle_cold_attribute): Simplify. (handle_const_attribute): Warn on function returning void. (handle_pure_attribute): Same. (handle_aligned_attribute): Warn on conflicting specifications. * c-warn.c (diagnose_mismatched_attributes): Simplify. gcc/cp/ChangeLog: PR c/81544 * decl2.c (cplus_decl_attributes): Look up existing declaration and pass it to decl_attributes. * name-lookup.c (find_decl): New function. * name-lookup.h (find_decl): Declare it. * tree.c (cxx_attribute_table): Initialize new member of struct attribute_spec. gcc/testsuite/ChangeLog: PR c/81544 * c-c++-common/Wattributes-2.c: New test. * c-c++-common/Wattributes.c: New test. * c-c++-common/attributes-3.c: Adjust. * g++.dg/ext/mv11.s: New test. * gcc.dg/attr-noinline.c: Adjust. * gcc.dg/pr44964.c: Same. * gcc.dg/torture/pr42363.c: Same. * gcc.dg/tree-ssa/ssa-ccp-2.c: Same. libstdc++-v3/ChangeLog: PR c/81544 * include/ext/mt_allocator.h (_M_destroy_thread_key): Remove pointless attribute const. gcc/ChangeLog: PR c/81544 * attribs.c (empty_attribute_table): Initialize new member of struct attribute_spec. (decl_attributes): Add argument. Handle mutually exclusive combinations of attributes. * attribs.h (decl_attributes): Add default argument. * tree-core.h (attribute_spec::exclusions, exclude): New type and member. /* Associates a GNAT tree node to a GCC tree node. It is used in diff --git a/gcc/attribs.c b/gcc/attribs.c index 05fa8ef..df3104b 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -94,7 +94,7 @@ static bool attributes_initialized = false; static const struct attribute_spec empty_attribute_table[] = { - { NULL, 0, 0, false, false, false, NULL, false } + { NULL, 0, 0, false, false, false, NULL, false, NULL } }; /* Return base name of the attribute. Ie '__attr__' is turned into 'attr'. @@ -343,6 +343,97 @@ get_attribute_namespace (const_tree attr) return get_identifier ("gnu"); } +/* Check LAST_DECL and NODE of the same symbol for attributes that are + recorded in EXCL to be mutually exclusive with ATTRNAME, diagnose + them, and return true if any have been found. NODE can be a DECL + or a TYPE. */ + +static bool +diag_attr_exclusions (tree last_decl, tree node, tree attrname, + const attribute_spec *spec) +{ + const attribute_spec::exclusions *excl = spec->exclude; + + tree_code code = TREE_CODE (node); + + if ((code == FUNCTION_DECL && !excl->function + && (!excl->type || !spec->affects_type_identity)) + || (code == VAR_DECL && !excl->variable + && (!excl->type || !spec->affects_type_identity)) + || (((code == TYPE_DECL || RECORD_OR_UNION_TYPE_P (node)) && !excl->type))) + return false; + + /* True if an attribute that's mutually exclusive with ATTRNAME + has been found. */ + bool found = false; + + if (last_decl && last_decl != node && TREE_TYPE (last_decl) != node) + { + /* Check both the last DECL and its type for conflicts with + the attribute being added to the current decl or type. */ + found |= diag_attr_exclusions (last_decl, last_decl, attrname, spec); + tree decl_type = TREE_TYPE (last_decl); + found |= diag_attr_exclusions (last_decl, decl_type, attrname, spec); + } + + /* NODE is either the current DECL to which the attribute is being + applied or its TYPE. For the former, consider the attributes on + both the DECL and its type. */ + tree attrs[2]; + + if (DECL_P (node)) + { + attrs[0] = DECL_ATTRIBUTES (node); + attrs[1] = TYPE_ATTRIBUTES (TREE_TYPE (node)); + } + else + { + attrs[0] = TYPE_ATTRIBUTES (node); + attrs[1] = NULL_TREE; + } + + /* Iterate over the mutually exclusive attribute names and verify + that the symbol doesn't contain it. */ + for (unsigned i = 0; i != sizeof attrs / sizeof *attrs; ++i) + { + if (!attrs[i]) + continue; + + for ( ; excl->name; ++excl) + { + /* Avoid checking the attribute against itself. */ + if (is_attribute_p (excl->name, attrname)) + continue; + + if (lookup_attribute (excl->name, attrs[i])) + { + found = true; + + /* Print a note? */ + bool note = last_decl != NULL_TREE; + + if (TREE_CODE (node) == FUNCTION_DECL + && DECL_BUILT_IN (node)) + note &= warning (OPT_Wattributes, + "ignoring attribute %qE in declaration of " + "a built-in function qD because it conflicts " + "with attribute %qs", + attrname, node, excl->name); + else + note &= warning (OPT_Wattributes, + "ignoring attribute %qE because " + "it conflicts with attribute %qs", + attrname, excl->name); + + if (note) + inform (DECL_SOURCE_LOCATION (last_decl), + "previous declaration here"); + } + } + } + + return found; +} /* Process the attributes listed in ATTRIBUTES and install them in *NODE, which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL, @@ -354,7 +445,8 @@ get_attribute_namespace (const_tree attr) a decl attribute to the declaration rather than to its type). */ tree -decl_attributes (tree *node, tree attributes, int flags) +decl_attributes (tree *node, tree attributes, int flags, + tree last_decl /* = NULL_TREE */) { tree a; tree returned_attrs = NULL_TREE; @@ -433,6 +525,8 @@ decl_attributes (tree *node, tree attributes, int flags) targetm.insert_attributes (*node, &attributes); + /* Note that attributes on the same declaration are not necessarily + in the same order as in the source. */ for (a = attributes; a; a = TREE_CHAIN (a)) { tree ns = get_attribute_namespace (a); @@ -441,7 +535,6 @@ decl_attributes (tree *node, tree attributes, int flags) tree *anode = node; const struct attribute_spec *spec = lookup_scoped_attribute_spec (ns, name); - bool no_add_attrs = 0; int fn_ptr_quals = 0; tree fn_ptr_tmp = NULL_TREE; @@ -490,7 +583,9 @@ decl_attributes (tree *node, tree attributes, int flags) | (int) ATTR_FLAG_ARRAY_NEXT)) { /* Pass on this attribute to be tried again. */ - returned_attrs = tree_cons (name, args, returned_attrs); + tree attr = tree_cons (name, args, NULL_TREE); + returned_attrs = chainon (returned_attrs, attr); + // returned_attrs = tree_cons (name, args, returned_attrs); continue; } else @@ -535,7 +630,9 @@ decl_attributes (tree *node, tree attributes, int flags) else if (flags & (int) ATTR_FLAG_FUNCTION_NEXT) { /* Pass on this attribute to be tried again. */ - returned_attrs = tree_cons (name, args, returned_attrs); + tree attr = tree_cons (name, args, NULL_TREE); + returned_attrs = chainon (returned_attrs, attr); + // returned_attrs = tree_cons (name, args, returned_attrs); continue; } @@ -557,15 +654,55 @@ decl_attributes (tree *node, tree attributes, int flags) continue; } + bool no_add_attrs = false; + if (spec->handler != NULL) { int cxx11_flag = cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0; - returned_attrs = chainon ((*spec->handler) (anode, name, args, - flags|cxx11_flag, - &no_add_attrs), - returned_attrs); + /* Pass in an array of the current declaration followed + by the last pushed/merged declaration if one exists. + If the handler changes CUR_AND_LAST_DECL[0] replace + *ANODE with its value. */ + tree cur_and_last_decl[] = { *anode, last_decl }; + tree ret = (spec->handler) (cur_and_last_decl, name, args, + flags|cxx11_flag, &no_add_attrs); + + *anode = cur_and_last_decl[0]; + if (ret == error_mark_node) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + no_add_attrs = true; + } + else + returned_attrs = chainon (ret, returned_attrs); + } + + /* If the attribute was sussceefully handled on its own and is + about to be added check for exclusions with other attributes + on the current declation as well as the last declaration of + the same symbol already processed (if one exists). */ + bool built_in = flags & ATTR_FLAG_BUILT_IN; + if (spec->exclude + && !no_add_attrs + && (flag_checking || !built_in)) + { + /* Always check attributes on user-defined functions. + Check them on built-ins only when -fchecking is set. + Ignore __builtin_unreachable -- it's both const and + noreturn. */ + + if (!built_in + || !DECL_P (*anode) + || (DECL_FUNCTION_CODE (*anode) != BUILT_IN_UNREACHABLE + && DECL_FUNCTION_CODE (*anode) != BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE)) + { + bool no_add = diag_attr_exclusions (last_decl, *anode, name, spec); + if (!no_add && anode != node) + no_add = diag_attr_exclusions (last_decl, *node, name, spec); + no_add_attrs |= no_add; + } } /* Layout the decl in case anything changed. */ diff --git a/gcc/attribs.h b/gcc/attribs.h index d4a790b..a9eba0a 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -31,7 +31,7 @@ extern void init_attributes (void); from tree.h. Depending on these flags, some attributes may be returned to be applied at a later stage (for example, to apply a decl attribute to the declaration rather than to its type). */ -extern tree decl_attributes (tree *, tree, int); +extern tree decl_attributes (tree *, tree, int, tree = NULL_TREE); extern bool cxx11_attribute_p (const_tree); extern tree get_attribute_name (const_tree); diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 0d9ab2d..8a157f6 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-iterator.h" #include "opts.h" #include "gimplify.h" +#include "bitmap.h" static tree handle_packed_attribute (tree *, tree, tree, int, bool *); static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *); @@ -146,6 +147,92 @@ static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *); static tree handle_patchable_function_entry_attribute (tree *, tree, tree, int, bool *); +/* Helper to define attribute exclusions. */ +#define ATTR_EXCL(name, function, type, variable) \ + { name, function, type, variable } + +/* Define attributes that are mutually exclusive with one another. */ +static const struct attribute_spec::exclusions attr_aligned_exclusions[] = +{ + /* Attribute name exclusion applies to: + function, type, variable */ + ATTR_EXCL ("aligned", true, false, false), + ATTR_EXCL ("packed", true, false, false), + ATTR_EXCL (NULL, false, false, false) +}; + +static const struct attribute_spec::exclusions attr_cold_hot_exclusions[] = +{ + ATTR_EXCL ("cold", true, true, true), + ATTR_EXCL ("hot", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + +static const struct attribute_spec::exclusions attr_common_exclusions[] = +{ + ATTR_EXCL ("common", true, true, true), + ATTR_EXCL ("nocommon", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_gnu_inline_exclusions[] = +{ + ATTR_EXCL ("gnu_inline", true, true, true), + ATTR_EXCL ("noinline", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_inline_exclusions[] = +{ + ATTR_EXCL ("always_inline", true, true, true), + ATTR_EXCL ("noinline", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = +{ + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("alloc_align", true, true, true), + ATTR_EXCL ("alloc_size", true, true, true), + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("malloc", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL ("returns_twice", true, true, true), + ATTR_EXCL ("warn_unused_result", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions +attr_warn_unused_result_exclusions[] = +{ + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("warn_unused_result", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] = +{ + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +/* Exclusions that apply to attribute alloc_align, alloc_size, and malloc. */ +static const struct attribute_spec::exclusions attr_alloc_exclusions[] = +{ + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL (NULL, false, false, false), +}; + +static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = +{ + ATTR_EXCL ("const", true, true, true), + ATTR_EXCL ("noreturn", true, true, true), + ATTR_EXCL ("pure", true, true, true), + ATTR_EXCL (NULL, false, false, false) +}; + /* Table of machine-independent attributes common to all C-like languages. All attributes referencing arguments should be additionally processed @@ -157,209 +244,230 @@ const struct attribute_spec c_common_attribute_table[] = /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ { "packed", 0, 0, false, false, false, - handle_packed_attribute , false}, + handle_packed_attribute , false, + attr_aligned_exclusions }, { "nocommon", 0, 0, true, false, false, - handle_nocommon_attribute, false}, + handle_nocommon_attribute, false, + attr_common_exclusions }, { "common", 0, 0, true, false, false, - handle_common_attribute, false }, + handle_common_attribute, false, + attr_common_exclusions }, /* FIXME: logically, noreturn attributes should be listed as "false, true, true" and apply to function types. But implementing this would require all the places in the compiler that use TREE_THIS_VOLATILE on a decl to identify non-returning functions to be located and fixed to check the function type instead. */ { "noreturn", 0, 0, true, false, false, - handle_noreturn_attribute, false }, + handle_noreturn_attribute, false, + attr_noreturn_exclusions }, { "volatile", 0, 0, true, false, false, - handle_noreturn_attribute, false }, + handle_noreturn_attribute, false, NULL }, { "stack_protect", 0, 0, true, false, false, - handle_stack_protect_attribute, false }, + handle_stack_protect_attribute, false, NULL }, { "noinline", 0, 0, true, false, false, - handle_noinline_attribute, false }, + handle_noinline_attribute, false, + attr_inline_exclusions }, { "noclone", 0, 0, true, false, false, - handle_noclone_attribute, false }, + handle_noclone_attribute, false, NULL }, { "no_icf", 0, 0, true, false, false, - handle_noicf_attribute, false }, + handle_noicf_attribute, false, NULL }, { "noipa", 0, 0, true, false, false, - handle_noipa_attribute, false }, + handle_noipa_attribute, false, NULL }, { "leaf", 0, 0, true, false, false, - handle_leaf_attribute, false }, + handle_leaf_attribute, false, NULL }, { "always_inline", 0, 0, true, false, false, - handle_always_inline_attribute, false }, + handle_always_inline_attribute, false, + attr_inline_exclusions }, { "gnu_inline", 0, 0, true, false, false, - handle_gnu_inline_attribute, false }, + handle_gnu_inline_attribute, false, + attr_gnu_inline_exclusions }, { "artificial", 0, 0, true, false, false, - handle_artificial_attribute, false }, + handle_artificial_attribute, false, NULL }, { "flatten", 0, 0, true, false, false, - handle_flatten_attribute, false }, + handle_flatten_attribute, false, NULL }, { "used", 0, 0, true, false, false, - handle_used_attribute, false }, + handle_used_attribute, false, NULL }, { "unused", 0, 0, false, false, false, - handle_unused_attribute, false }, + handle_unused_attribute, false, NULL }, { "externally_visible", 0, 0, true, false, false, - handle_externally_visible_attribute, false }, + handle_externally_visible_attribute, false, + NULL }, { "no_reorder", 0, 0, true, false, false, - handle_no_reorder_attribute, false }, + handle_no_reorder_attribute, false, NULL }, /* The same comments as for noreturn attributes apply to const ones. */ { "const", 0, 0, true, false, false, - handle_const_attribute, false }, + handle_const_attribute, false, + attr_const_pure_exclusions }, { "scalar_storage_order", 1, 1, false, false, false, - handle_scalar_storage_order_attribute, false }, + handle_scalar_storage_order_attribute, false, + NULL }, { "transparent_union", 0, 0, false, false, false, - handle_transparent_union_attribute, false }, + handle_transparent_union_attribute, false, NULL }, { "constructor", 0, 1, true, false, false, - handle_constructor_attribute, false }, + handle_constructor_attribute, false, NULL }, { "destructor", 0, 1, true, false, false, - handle_destructor_attribute, false }, + handle_destructor_attribute, false, NULL }, { "mode", 1, 1, false, true, false, - handle_mode_attribute, false }, + handle_mode_attribute, false, NULL }, { "section", 1, 1, true, false, false, - handle_section_attribute, false }, + handle_section_attribute, false, NULL }, { "aligned", 0, 1, false, false, false, - handle_aligned_attribute, false }, + handle_aligned_attribute, false, + attr_aligned_exclusions }, { "weak", 0, 0, true, false, false, - handle_weak_attribute, false }, + handle_weak_attribute, false, NULL }, { "noplt", 0, 0, true, false, false, - handle_noplt_attribute, false }, + handle_noplt_attribute, false, NULL }, { "ifunc", 1, 1, true, false, false, - handle_ifunc_attribute, false }, + handle_ifunc_attribute, false, NULL }, { "alias", 1, 1, true, false, false, - handle_alias_attribute, false }, + handle_alias_attribute, false, NULL }, { "weakref", 0, 1, true, false, false, - handle_weakref_attribute, false }, + handle_weakref_attribute, false, NULL }, { "no_instrument_function", 0, 0, true, false, false, handle_no_instrument_function_attribute, - false }, + false, NULL }, { "no_profile_instrument_function", 0, 0, true, false, false, handle_no_profile_instrument_function_attribute, - false }, + false, NULL }, { "malloc", 0, 0, true, false, false, - handle_malloc_attribute, false }, + handle_malloc_attribute, false, + attr_alloc_exclusions }, { "returns_twice", 0, 0, true, false, false, - handle_returns_twice_attribute, false }, + handle_returns_twice_attribute, false, + attr_returns_twice_exclusions }, { "no_stack_limit", 0, 0, true, false, false, - handle_no_limit_stack_attribute, false }, + handle_no_limit_stack_attribute, false, NULL }, { "pure", 0, 0, true, false, false, - handle_pure_attribute, false }, + handle_pure_attribute, false, + attr_const_pure_exclusions }, { "transaction_callable", 0, 0, false, true, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, { "transaction_unsafe", 0, 0, false, true, false, - handle_tm_attribute, true }, + handle_tm_attribute, true, NULL }, { "transaction_safe", 0, 0, false, true, false, - handle_tm_attribute, true }, + handle_tm_attribute, true, NULL }, { "transaction_safe_dynamic", 0, 0, true, false, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, { "transaction_may_cancel_outer", 0, 0, false, true, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, /* ??? These two attributes didn't make the transition from the Intel language document to the multi-vendor language document. */ { "transaction_pure", 0, 0, false, true, false, - handle_tm_attribute, false }, + handle_tm_attribute, false, NULL }, { "transaction_wrap", 1, 1, true, false, false, - handle_tm_wrap_attribute, false }, + handle_tm_wrap_attribute, false, NULL }, /* For internal use (marking of builtins) only. The name contains space to prevent its usage in source code. */ { "no vops", 0, 0, true, false, false, - handle_novops_attribute, false }, + handle_novops_attribute, false, NULL }, { "deprecated", 0, 1, false, false, false, - handle_deprecated_attribute, false }, + handle_deprecated_attribute, false, NULL }, { "vector_size", 1, 1, false, true, false, - handle_vector_size_attribute, true }, + handle_vector_size_attribute, true, NULL }, { "visibility", 1, 1, false, false, false, - handle_visibility_attribute, false }, + handle_visibility_attribute, false, NULL }, { "tls_model", 1, 1, true, false, false, - handle_tls_model_attribute, false }, + handle_tls_model_attribute, false, NULL }, { "nonnull", 0, -1, false, true, true, - handle_nonnull_attribute, false }, + handle_nonnull_attribute, false, NULL }, { "nothrow", 0, 0, true, false, false, - handle_nothrow_attribute, false }, - { "may_alias", 0, 0, false, true, false, NULL, false }, + handle_nothrow_attribute, false, NULL }, + { "may_alias", 0, 0, false, true, false, NULL, false, NULL }, { "cleanup", 1, 1, true, false, false, - handle_cleanup_attribute, false }, + handle_cleanup_attribute, false, NULL }, { "warn_unused_result", 0, 0, false, true, true, - handle_warn_unused_result_attribute, false }, + handle_warn_unused_result_attribute, false, + attr_warn_unused_result_exclusions }, { "sentinel", 0, 1, false, true, true, - handle_sentinel_attribute, false }, + handle_sentinel_attribute, false, NULL }, /* For internal use (marking of builtins) only. The name contains space to prevent its usage in source code. */ { "type generic", 0, 0, false, true, true, - handle_type_generic_attribute, false }, + handle_type_generic_attribute, false, NULL }, { "alloc_size", 1, 2, false, true, true, - handle_alloc_size_attribute, false }, + handle_alloc_size_attribute, false, + attr_alloc_exclusions }, { "cold", 0, 0, true, false, false, - handle_cold_attribute, false }, + handle_cold_attribute, false, + attr_cold_hot_exclusions }, { "hot", 0, 0, true, false, false, - handle_hot_attribute, false }, + handle_hot_attribute, false, + attr_cold_hot_exclusions }, { "no_address_safety_analysis", 0, 0, true, false, false, handle_no_address_safety_analysis_attribute, - false }, + false, NULL }, { "no_sanitize", 1, 1, true, false, false, handle_no_sanitize_attribute, - false }, + false, NULL }, { "no_sanitize_address", 0, 0, true, false, false, handle_no_sanitize_address_attribute, - false }, + false, NULL }, { "no_sanitize_thread", 0, 0, true, false, false, handle_no_sanitize_thread_attribute, - false }, + false, NULL }, { "no_sanitize_undefined", 0, 0, true, false, false, handle_no_sanitize_undefined_attribute, - false }, + false, NULL }, { "asan odr indicator", 0, 0, true, false, false, handle_asan_odr_indicator_attribute, - false }, + false, NULL }, { "warning", 1, 1, true, false, false, - handle_error_attribute, false }, + handle_error_attribute, false, NULL }, { "error", 1, 1, true, false, false, - handle_error_attribute, false }, + handle_error_attribute, false, NULL }, { "target", 1, -1, true, false, false, - handle_target_attribute, false }, + handle_target_attribute, false, NULL }, { "target_clones", 1, -1, true, false, false, - handle_target_clones_attribute, false }, + handle_target_clones_attribute, false, NULL }, { "optimize", 1, -1, true, false, false, - handle_optimize_attribute, false }, + handle_optimize_attribute, false, NULL }, /* For internal use only. The leading '*' both prevents its usage in source code and signals that it may be overridden by machine tables. */ { "*tm regparm", 0, 0, false, true, true, - ignore_attribute, false }, + ignore_attribute, false, NULL }, { "no_split_stack", 0, 0, true, false, false, - handle_no_split_stack_attribute, false }, + handle_no_split_stack_attribute, false, NULL }, /* For internal use (marking of builtins and runtime functions) only. The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, - handle_fnspec_attribute, false }, + handle_fnspec_attribute, false, NULL }, { "warn_unused", 0, 0, false, false, false, - handle_warn_unused_attribute, false }, + handle_warn_unused_attribute, false, NULL }, { "returns_nonnull", 0, 0, false, true, true, - handle_returns_nonnull_attribute, false }, + handle_returns_nonnull_attribute, false, NULL }, { "omp declare simd", 0, -1, true, false, false, - handle_omp_declare_simd_attribute, false }, + handle_omp_declare_simd_attribute, false, NULL }, { "cilk simd function", 0, -1, true, false, false, - handle_omp_declare_simd_attribute, false }, + handle_omp_declare_simd_attribute, false, NULL }, { "simd", 0, 1, true, false, false, - handle_simd_attribute, false }, + handle_simd_attribute, false, NULL }, { "omp declare target", 0, 0, true, false, false, - handle_omp_declare_target_attribute, false }, + handle_omp_declare_target_attribute, false, + NULL }, { "omp declare target link", 0, 0, true, false, false, - handle_omp_declare_target_attribute, false }, + handle_omp_declare_target_attribute, false, + NULL }, { "alloc_align", 1, 1, false, true, true, - handle_alloc_align_attribute, false }, + handle_alloc_align_attribute, false, + attr_alloc_exclusions }, { "assume_aligned", 1, 2, false, true, true, - handle_assume_aligned_attribute, false }, + handle_assume_aligned_attribute, false, NULL }, { "designated_init", 0, 0, false, true, false, - handle_designated_init_attribute, false }, + handle_designated_init_attribute, false, NULL }, { "bnd_variable_size", 0, 0, true, false, false, - handle_bnd_variable_size_attribute, false }, + handle_bnd_variable_size_attribute, false, NULL }, { "bnd_legacy", 0, 0, true, false, false, - handle_bnd_legacy, false }, + handle_bnd_legacy, false, NULL }, { "bnd_instrument", 0, 0, true, false, false, - handle_bnd_instrument, false }, + handle_bnd_instrument, false, NULL }, { "fallthrough", 0, 0, false, false, false, - handle_fallthrough_attribute, false }, + handle_fallthrough_attribute, false, NULL }, { "patchable_function_entry", 1, 2, true, false, false, handle_patchable_function_entry_attribute, - false }, - { NULL, 0, 0, false, false, false, NULL, false } + false, NULL }, + { NULL, 0, 0, false, false, false, NULL, false, NULL } }; /* Give the specifications for the format attributes, used by C and all @@ -374,10 +482,10 @@ const struct attribute_spec c_common_format_attribute_table[] = /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ { "format", 3, 3, false, true, true, - handle_format_attribute, false }, + handle_format_attribute, false, NULL }, { "format_arg", 1, 1, false, true, true, - handle_format_arg_attribute, false }, - { NULL, 0, 0, false, false, false, NULL, false } + handle_format_arg_attribute, false, NULL }, + { NULL, 0, 0, false, false, false, NULL, false, NULL } }; /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain @@ -515,14 +623,7 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), if (TREE_CODE (*node) == FUNCTION_DECL || TREE_CODE (*node) == LABEL_DECL) { - if (lookup_attribute ("cold", DECL_ATTRIBUTES (*node)) != NULL) - { - warning (OPT_Wattributes, "%qE attribute ignored due to conflict " - "with attribute %qs", name, "cold"); - *no_add_attrs = true; - } - /* Most of the rest of the hot processing is done later with - lookup_attribute. */ + /* Attribute hot processing is done later with lookup_attribute. */ } else { @@ -543,14 +644,7 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), if (TREE_CODE (*node) == FUNCTION_DECL || TREE_CODE (*node) == LABEL_DECL) { - if (lookup_attribute ("hot", DECL_ATTRIBUTES (*node)) != NULL) - { - warning (OPT_Wattributes, "%qE attribute ignored due to conflict " - "with attribute %qs", name, "hot"); - *no_add_attrs = true; - } - /* Most of the rest of the cold processing is done later with - lookup_attribute. */ + /* Attribute cold processing is done later with lookup_attribute. */ } else { @@ -1064,7 +1158,7 @@ handle_no_reorder_attribute (tree *pnode, static tree handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), - int ARG_UNUSED (flags), bool *no_add_attrs) + int flags, bool *no_add_attrs) { tree type = TREE_TYPE (*node); @@ -1085,6 +1179,14 @@ handle_const_attribute (tree *node, tree name, tree ARG_UNUSED (args), *no_add_attrs = true; } + /* void __builtin_unreachable(void) is const. Accept other such + built-ins but warn on user-defined functions that return void. */ + if (!(flags & ATTR_FLAG_BUILT_IN) + && TREE_CODE (*node) == FUNCTION_DECL + && VOID_TYPE_P (TREE_TYPE (type))) + warning (OPT_Wattributes, "%qE attribute on function " + "returning %", name); + return NULL_TREE; } @@ -1667,14 +1769,18 @@ check_cxx_fundamental_alignment_constraints (tree node, struct attribute_spec.handler. */ static tree -handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, +handle_aligned_attribute (tree *node, tree name, tree args, int flags, bool *no_add_attrs) { tree decl = NULL_TREE; tree *type = NULL; - int is_type = 0; + bool is_type = false; tree align_expr; - int i; + + /* The last (already pushed) declaration with all validated attributes + merged in or the current about-to-be-pushed one if one hassn't been + yet. */ + tree last_decl = node[1] ? node[1] : *node; if (args) { @@ -1693,10 +1799,21 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, is_type = TREE_CODE (*node) == TYPE_DECL; } else if (TYPE_P (*node)) - type = node, is_type = 1; + type = node, is_type = true; + + /* Log2 of specified alignment. */ + int pow2align = check_user_alignment (align_expr, true); + + /* The alignment in bits corresponding to the specified alignment. */ + unsigned bitalign = (1U << pow2align) * BITS_PER_UNIT; + + /* The alignment of the current declaration and that of the last + pushed declaration, determined on demand below. */ + unsigned curalign = 0; + unsigned lastalign = 0; - if ((i = check_user_alignment (align_expr, true)) == -1 - || !check_cxx_fundamental_alignment_constraints (*node, i, flags)) + if (pow2align == -1 + || !check_cxx_fundamental_alignment_constraints (*node, pow2align, flags)) *no_add_attrs = true; else if (is_type) { @@ -1717,7 +1834,7 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, else *type = build_variant_type_copy (*type); - SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT); + SET_TYPE_ALIGN (*type, bitalign); TYPE_USER_ALIGN (*type) = 1; } else if (! VAR_OR_FUNCTION_DECL_P (decl) @@ -1726,8 +1843,34 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, error ("alignment may not be specified for %q+D", decl); *no_add_attrs = true; } + else if (TREE_CODE (decl) == FUNCTION_DECL + && ((curalign = DECL_ALIGN (decl)) > bitalign + || ((lastalign = DECL_ALIGN (last_decl)) > bitalign))) + { + /* Either a prior attribute on the same declaration or one + on a prior declaration of the same function specifies + stricter alignment than this attribute. */ + bool note = lastalign != 0; + if (lastalign) + curalign = lastalign; + + curalign /= BITS_PER_UNIT; + bitalign /= BITS_PER_UNIT; + + if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl)) + warning (OPT_Wattributes, + "ignoring attribute %<%E (%u)%> because it conflicts with " + "attribute %<%E (%u)%>", name, bitalign, name, curalign); + else + error ("alignment for %q+D must be at least %d", decl, curalign); + + if (note) + inform (DECL_SOURCE_LOCATION (last_decl), "previous declaration here"); + + *no_add_attrs = true; + } else if (DECL_USER_ALIGN (decl) - && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) + && DECL_ALIGN (decl) > bitalign) /* C++-11 [dcl.align/4]: When multiple alignment-specifiers are specified for an @@ -1737,21 +1880,9 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, This formally comes from the c++11 specification but we are doing it for the GNU attribute syntax as well. */ *no_add_attrs = true; - else if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) - { - if (DECL_USER_ALIGN (decl)) - error ("alignment for %q+D was previously specified as %d " - "and may not be decreased", decl, - DECL_ALIGN (decl) / BITS_PER_UNIT); - else - error ("alignment for %q+D must be at least %d", decl, - DECL_ALIGN (decl) / BITS_PER_UNIT); - *no_add_attrs = true; - } else { - SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT); + SET_DECL_ALIGN (decl, bitalign); DECL_USER_ALIGN (decl) = 1; } @@ -2476,8 +2607,15 @@ handle_pure_attribute (tree *node, tree name, tree ARG_UNUSED (args), int ARG_UNUSED (flags), bool *no_add_attrs) { if (TREE_CODE (*node) == FUNCTION_DECL) - DECL_PURE_P (*node) = 1; - /* ??? TODO: Support types. */ + { + tree type = TREE_TYPE (*node); + if (VOID_TYPE_P (TREE_TYPE (type))) + warning (OPT_Wattributes, "%qE attribute on function " + "returning %", name); + + DECL_PURE_P (*node) = 1; + /* ??? TODO: Support types. */ + } else { warning (OPT_Wattributes, "%qE attribute ignored", name); diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c index e970ab2..8bbfcb5 100644 --- a/gcc/c-family/c-warn.c +++ b/gcc/c-family/c-warn.c @@ -2143,36 +2143,19 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl) newdecl); /* Diagnose inline __attribute__ ((noinline)) which is silly. */ + const char* noinline = "noinline"; + if (DECL_DECLARED_INLINE_P (newdecl) && DECL_UNINLINABLE (olddecl) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) + && lookup_attribute (noinline, DECL_ATTRIBUTES (olddecl))) warned |= warning (OPT_Wattributes, "inline declaration of %qD follows " - "declaration with attribute noinline", newdecl); + "declaration with attribute %qs", newdecl, noinline); else if (DECL_DECLARED_INLINE_P (olddecl) && DECL_UNINLINABLE (newdecl) && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl))) warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "noinline follows inline declaration ", newdecl); - else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("always_inline", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "noinline", "always_inline"); - else if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "always_inline", "noinline"); - else if (lookup_attribute ("cold", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("hot", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "cold", "hot"); - else if (lookup_attribute ("hot", DECL_ATTRIBUTES (newdecl)) - && lookup_attribute ("cold", DECL_ATTRIBUTES (olddecl))) - warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute " - "%qs follows declaration with attribute %qs", - newdecl, "hot", "cold"); + "%qs follows inline declaration ", newdecl, noinline); + return warned; } diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index a54e121..5852c0d 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -4589,7 +4589,16 @@ c_decl_attributes (tree *node, tree attributes, int flags) attributes = tree_cons (get_identifier ("omp declare target"), NULL_TREE, attributes); } - return decl_attributes (node, attributes, flags); + + /* Look up the current declaration with all the attributes merged + so far so that attributes on the current declaration that's + about to be pushed that conflict with the former can be detected, + diagnosed, and rejected as appropriate. */ + tree last_decl = lookup_name (DECL_NAME (*node)); + if (!last_decl) + last_decl = lookup_name_in_scope (DECL_NAME (*node), external_scope); + + return decl_attributes (node, attributes, flags, last_decl); } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 115cdaf..f2bac2a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6080,7 +6080,7 @@ extern void finish_scope (void); extern void push_switch (tree); extern void pop_switch (void); extern tree make_lambda_name (void); -extern int decls_match (tree, tree); +extern int decls_match (tree, tree, bool = true); extern tree duplicate_decls (tree, tree, bool); extern tree declare_local_label (tree); extern tree define_label (location_t, tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index aab2019..c9c8cd1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -993,7 +993,7 @@ push_local_name (tree decl) `const int&'. */ int -decls_match (tree newdecl, tree olddecl) +decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */) { int types_match; @@ -1088,6 +1088,7 @@ decls_match (tree newdecl, tree olddecl) if (types_match && !DECL_EXTERN_C_P (newdecl) && !DECL_EXTERN_C_P (olddecl) + && record_versions && targetm.target_option.function_versions (newdecl, olddecl)) { /* Mark functions as versions if necessary. Modify the mangled decl diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 2a52f8c..585822e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1404,7 +1404,10 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) attributes, flags); } else - decl_attributes (decl, attributes, flags); + { + tree last_decl = find_decl (*decl); + decl_attributes (decl, attributes, flags, last_decl); + } if (TREE_CODE (*decl) == TYPE_DECL) SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl)); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 4dc19da..e18e3fa 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -2291,6 +2291,71 @@ set_local_extern_decl_linkage (tree decl, bool shadowed) } } +/* Given a new DECL that hasn't been pushed yet, try to find the last + DECL for the same symbol and return it, oterwise return null. */ + +tree +find_decl (tree decl) +{ + if (!DECL_P (decl)) + return NULL_TREE; + + /* if (!DECL_TEMPLATE_PARM_P (decl) && current_function_decl) */ + /* set_decl_context_in_fn (current_function_decl, decl); */ + + /* The binding level we will be pushing into. During local class + pushing, we want to push to the containing scope. */ + cp_binding_level *level = current_binding_level; + while (level->kind == sk_class) + level = level->level_chain; + + tree name = DECL_NAME (decl); + if (!name) + return NULL_TREE; + + cxx_binding *binding = NULL; /* Local scope binding. */ + tree ns = NULL_TREE; /* Searched namespace. */ + tree *slot = NULL; /* Binding slot in namespace. */ + tree old = NULL_TREE; + + if (level->kind == sk_namespace) + { + /* We look in the decl's namespace for an existing + declaration, even though we push into the current + namespace. */ + ns = (DECL_NAMESPACE_SCOPE_P (decl) + ? CP_DECL_CONTEXT (decl) : current_namespace); + /* Create the binding, if this is current namespace, because + that's where we'll be pushing anyway. */ + slot = find_namespace_slot (ns, name, ns == current_namespace); + if (slot) + old = MAYBE_STAT_DECL (*slot); + } + else + { + binding = find_local_binding (level, name); + if (binding) + old = binding->value; + } + + /* if (current_function_decl && VAR_OR_FUNCTION_DECL_P (decl) */ + /* && DECL_EXTERNAL (decl)) */ + /* set_local_extern_decl_linkage (decl, old != NULL_TREE); */ + + if (old == error_mark_node) + old = NULL_TREE; + + for (ovl_iterator iter (old); iter; ++iter) + { + if (iter.using_p ()) + ; /* Ignore using decls here. */ + else if (decls_match (decl, *iter, /*record_decls=*/false)) + return *iter; + } + + return NULL_TREE; +} + /* Record DECL as belonging to the current lexical scope. Check for errors (such as an incompatible declaration for the same name already seen in the same scope). IS_FRIEND is true if DECL is diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 2e2075c..ce0826e 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -339,4 +339,6 @@ extern void pop_nested_namespace (tree); extern void push_to_top_level (void); extern void pop_from_top_level (void); +extern tree find_decl (tree); + #endif /* GCC_CP_NAME_LOOKUP_H */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8f18665..6cbf4b2 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4314,10 +4314,10 @@ const struct attribute_spec cxx_attribute_table[] = /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ { "init_priority", 1, 1, true, false, false, - handle_init_priority_attribute, false }, + handle_init_priority_attribute, false, NULL }, { "abi_tag", 1, -1, false, false, false, - handle_abi_tag_attribute, true }, - { NULL, 0, 0, false, false, false, NULL, false } + handle_abi_tag_attribute, true, NULL }, + { NULL, 0, 0, false, false, false, NULL, false, NULL } }; /* Table of C++ standard attributes. */ @@ -4326,10 +4326,10 @@ const struct attribute_spec std_attribute_table[] = /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ { "maybe_unused", 0, 0, false, false, false, - handle_unused_attribute, false }, + handle_unused_attribute, false, NULL }, { "nodiscard", 0, 0, false, false, false, - handle_nodiscard_attribute, false }, - { NULL, 0, 0, false, false, false, NULL, false } + handle_nodiscard_attribute, false, NULL }, + { NULL, 0, 0, false, false, false, NULL, false, NULL } }; /* Handle an "init_priority" attribute; arguments as in diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 278d0c9..943b349 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1933,6 +1933,20 @@ struct attribute_spec { int flags, bool *no_add_attrs); /* Specifies if attribute affects type's identity. */ bool affects_type_identity; + + /* Specifies the name of an attribute that's mutually exclusive with + this one, and whether the relationship applies to the function, + variable, or type form of the attribute. */ + struct exclusions { + const char* name; + bool function; + bool variable; + bool type; + }; + + /* An array of attribute exclusions describing names of other attributes + that this attribute is mutually exclusive with. */ + const exclusions* exclude; }; /* These functions allow a front-end to perform a manual layout of a diff --git a/libstdc++-v3/include/ext/mt_allocator.h b/libstdc++-v3/include/ext/mt_allocator.h index effb13b..f349ff8 100644 --- a/libstdc++-v3/include/ext/mt_allocator.h +++ b/libstdc++-v3/include/ext/mt_allocator.h @@ -355,7 +355,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } // XXX GLIBCXX_ABI Deprecated - _GLIBCXX_CONST void + void _M_destroy_thread_key(void*) throw (); size_t diff --git a/gcc/testsuite/c-c++-common/Wattributes-2.c b/gcc/testsuite/c-c++-common/Wattributes-2.c new file mode 100644 index 0000000..0904742 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wattributes-2.c @@ -0,0 +1,74 @@ +/* PR c/81566 - invalid attribute aligned accepted on functions + { dg-do compile } + { dg-options "-Wall -Wattributes -ftrack-macro-expansion=0" } */ + +#define ATTR(list) __attribute__ (list) +#define ALIGN(n) ATTR ((aligned (n))) + +/* It's okay to increase the alignment of a function. */ + +void ALIGN (16) ALIGN (32) +falign32_1 (void); + +void ALIGN (16) falign32_2 (void); +void ALIGN (32) falign32_2 (void); + +void falign32_2 (void) { } + +void ALIGN (32) falign32_2 (void); + +/* It's not okay to decrease it. */ + +void ALIGN (32) ALIGN (16) +falign64_3 (void); /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */ + +void ALIGN (32) +falign64_3 (void); + +void falign64_3 (void); + +void falign64_3 (void) { } + + +void ALIGN (32) +falign64_4 (void); /* { dg-message "previous declaration here" } */ + +void ALIGN (16) +falign64_4 (void); /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */ + +void ALIGN (32) +falign64_4 (void); /* { dg-message "previous declaration here" } */ + +void ALIGN (16) +falign64_4 (void); /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */ + +void ALIGN (64) +falign64_4 (void); + +void ALIGN (32) +falign64_4 (void); /* { dg-warning "ignoring attribute .aligned \\(32\\). because it conflicts with attribute .aligned \\(64\\)." } */ + +void falign64_4 (void); + +void ALIGN (64) +falign64_4 (void) { } + +void falign64_4 (void); + +void ALIGN (64) +falign64_4 (void); + + +void ATTR ((aligned (16), aligned (32))) +falign64_5 (void); + +void ATTR ((aligned (32), aligned (64))) +falign64_5 (void); + +void ATTR ((aligned (16), aligned (32), aligned (64))) +falign64_5 (void); /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(64\\)." } */ + /* { dg-warning "ignoring attribute .aligned \\(32\\). because it conflicts with attribute .aligned \\(64\\)." "" { target *-*-* } .-1 } */ + + +void ATTR ((aligned (16), aligned (32), aligned (16))) +falign64_6 (void); /* { dg-warning "ignoring attribute .aligned \\(16\\). because it conflicts with attribute .aligned \\(32\\)." } */ diff --git a/gcc/testsuite/c-c++-common/Wattributes.c b/gcc/testsuite/c-c++-common/Wattributes.c new file mode 100644 index 0000000..d0c4d06 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wattributes.c @@ -0,0 +1,437 @@ +/* { dg-do compile } + { dg-options "-Wall -Wattributes -ftrack-macro-expansion=0" } */ + +#define ATTR(attrlist) __attribute__ (attrlist) + +/* Exercise the handling of the mutually exclusive attributes + aligned and packed. */ + +/* Pointless but benign. */ +struct ATTR ((aligned, aligned)) +AlignedAligned { int i; }; + +struct ATTR ((aligned, packed)) +AlignedPacked { int i; }; /* { dg-warning "ignoring attribute .packed. because it conflicts with attribute .aligned." } */ + +struct ATTR ((packed, aligned)) +PackedAligned { int i; }; /* { dg-warning "ignoring attribute .aligned. because it conflicts with attribute .packed." } */ + +/* Silly but benign. */ +struct ATTR ((packed, packed)) +PackedPacked { int i; }; + + +/* Exercise the handling of the mutually exclusive attributes + always_inline and noinline. */ + +inline void ATTR ((always_inline)) +falways_inline1 (void); + +inline void ATTR ((__always_inline__)) +falways_inline1 (void); + +inline void ATTR ((always_inline, __always_inline__)) +falways_inline1 (void); + +/* Verify that repeating attribute always_inline doesn't trigger a warning. */ +inline void ATTR ((always_inline)) +falways_inline1 (void); /* { dg-message "previous declaration here" } */ + +void ATTR ((noinline)) +falways_inline1 (void) { } /* { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */ + +/* And again. */ +void ATTR ((always_inline)) +falways_inline (void); + + +/* Exercise the handling of the mutually exclusive attributes + noreturn and warn_unused_result. */ + +int ATTR ((__noreturn__)) +fnoret1 (void); + +int ATTR ((noreturn)) +fnoret1 (void); /* { dg-message "previous declaration here" } */ + +int ATTR ((warn_unused_result)) +fnoret1 (void); /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */ + +/* Verify that repeating attribute noreturn doesn't trigger a warning. */ +int ATTR ((noreturn)) fnoret1 (void); + +int call_noret1 (void) +{ + /* Verify that attribute warn_unused_result was, in fact, ignored + on the second declaration of fnoret1. */ + fnoret1 (); +} + +int ATTR ((noreturn, warn_unused_result)) +fnoret2 (void); /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */ + +/* Verify that repeating attribute noreturn doesn't trigger a warning. */ +int ATTR ((noreturn)) fnoret2 (void); + +int call_noret2 (void) +{ + /* Verify that attribute warn_unused_result was, in fact, ignored + on the second declaration of fnoret2. */ + fnoret2 (); +} + +/* Verify again but this time in different scopes. */ + +int ATTR ((noreturn)) +fnoret3 (void); /* { dg-message "previous declaration here" } */ + +void declare_noret3 (void) +{ + int ATTR ((warn_unused_result)) + fnoret3 (void); /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */ +} + +void declare_noret4 (void) +{ + int ATTR ((warn_unused_result)) + fnoret4 (void); /* { dg-message "previous declaration here" } */ +} + +int ATTR ((noreturn)) +fnoret4 (void); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .warn_unused_result." } */ + + +/* And again, but with both declared in a different local scope. */ + +void declare_noret5_1 (void) +{ + int ATTR ((noreturn)) + fnoret5 (void); /* { dg-message "previous declaration here" } */ +} + +int declare_noret5_2 (void) +{ + int ATTR ((warn_unused_result)) + fnoret5 (void); /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */ + + /* Verify that no warning is issued below (because the warn_unused_result + attribute above was dropped). */ + fnoret5 (); +} + +/* Verify that attribute noreturn isn't diagnosed on a declaration + that was previously declared warn_unused_result and that attribute + was dropped (because the function returs void). */ + +void ATTR ((warn_unused_result)) +fnorety6 (void); /* { dg-warning ".warn_unused_result. attribute ignored" } */ + +void ATTR ((noreturn)) +fnoret6 (void); + + +/* Exercise the handling of the mutually exclusive attributes + noreturn and alloc_align. */ + +void* ATTR ((noreturn)) +fnoret_alloc_align1 (int); /* { dg-message "previous declaration here" } */ + +void* ATTR ((alloc_align (1))) +fnoret_alloc_align1 (int); /* { dg-warning "ignoring attribute .alloc_align. because it conflicts with attribute .noreturn." } */ + +void* ATTR ((noreturn, alloc_align (1))) +fnoret_alloc_align2 (int); /* { dg-warning "ignoring attribute .alloc_align. because it conflicts with attribute .noreturn." } */ + + +void* ATTR ((noreturn)) ATTR ((alloc_align (1))) +fnoret_alloc_align3 (int); /* { dg-warning "ignoring attribute .alloc_align. because it conflicts with attribute .noreturn." } */ + + +void* ATTR ((alloc_align (1))) +falloc_align_noret1 (int); /* { dg-message "previous declaration here" } */ + +void* ATTR ((noreturn)) +falloc_align_noret1 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_align." } */ + + +void* ATTR ((alloc_align (1), noreturn)) +falloc_align_noret2 (int); /* { dg-warning "ignoring attribute .(noreturn|alloc_align). because it conflicts with attribute .(alloc_align|noreturn)." } */ + +void* ATTR ((alloc_align (1))) ATTR ((noreturn)) +falloc_align_noret3 (int); /* { dg-warning "ignoring attribute .(noreturn|alloc_align). because it conflicts with attribute .(noreturn|alloc_align)." } */ + + +/* Exercise the handling of the mutually exclusive attributes + noreturn and alloc_size. */ + +void* ATTR ((noreturn)) +fnoret_alloc_size1 (int); /* { dg-message "previous declaration here" } */ + +void* ATTR ((alloc_size (1))) +fnoret_alloc_size1 (int); /* { dg-warning "ignoring attribute .alloc_size. because it conflicts with attribute .noreturn." } */ + +void* ATTR ((noreturn, alloc_size (1))) +fnoret_alloc_size2 (int); /* { dg-warning "ignoring attribute .alloc_size. because it conflicts with attribute .noreturn." } */ + + +void* ATTR ((noreturn)) ATTR ((alloc_size (1))) +fnoret_alloc_size3 (int); /* { dg-warning "ignoring attribute .alloc_size. because it conflicts with attribute .noreturn." } */ + + +void* ATTR ((alloc_size (1))) +falloc_size_noret1 (int); /* { dg-message "previous declaration here" } */ + +void* ATTR ((noreturn)) +falloc_size_noret1 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_size." } */ + + +void* ATTR ((alloc_size (1), noreturn)) +falloc_size_noret2 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_size." } */ + +void* ATTR ((alloc_size (1))) ATTR ((noreturn)) +falloc_size_noret3 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .alloc_size." } */ + + +/* Exercise the handling of the mutually exclusive attributes + noreturn and const. */ + +int ATTR ((noreturn)) +fnoret_const1 (int); /* { dg-message "previous declaration here" } */ + +int ATTR ((const)) +fnoret_const1 (int); /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */ + +/* Unfortunately, attributes on a single declarations may not be processed + in the same order as specified... */ +int ATTR ((noreturn, const)) +fnoret_const2 (int); /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */ + + +int ATTR ((noreturn)) ATTR ((const)) +fnoret_const3 (int); /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */ + + +int ATTR ((const)) +fconst_noret1 (int); /* { dg-message "previous declaration here" } */ + +int ATTR ((noreturn)) +fconst_noret1 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .const." } */ + + +int ATTR ((const, noreturn)) +fconst_noret2 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .const." } */ + +int ATTR ((const)) ATTR ((noreturn)) +fconst_noret3 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .const." } */ + + +/* Exercise the handling of the mutually exclusive attributes + noreturn and malloc. */ + +void* ATTR ((noreturn)) +fnoret_malloc1 (int); /* { dg-message "previous declaration here" } */ + +void* ATTR ((malloc)) +fnoret_malloc1 (int); /* { dg-warning "ignoring attribute .malloc. because it conflicts with attribute .noreturn." } */ + +/* Unfortunately, attributes on a single declarations may not be processed + in the same order as specified... */ +void* ATTR ((noreturn, malloc)) +fnoret_malloc2 (int); /* { dg-warning "ignoring attribute .malloc. because it conflicts with attribute .noreturn." } */ + + +void* ATTR ((noreturn)) ATTR ((malloc)) +fnoret_malloc3 (int); /* { dg-warning "ignoring attribute .malloc. because it conflicts with attribute .noreturn." } */ + + +void* ATTR ((__malloc__)) +fmalloc_noret1 (int); + +void* ATTR ((malloc)) +fmalloc_noret1 (int); /* { dg-message "previous declaration here" } */ + +void* ATTR ((noreturn)) +fmalloc_noret1 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .malloc." } */ + + +void* ATTR ((malloc, noreturn)) +fmalloc_noret2 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .malloc." } */ + +void* ATTR ((malloc)) ATTR ((noreturn)) +fmalloc_noret3 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .malloc." } */ + + +/* Exercise the handling of the mutually exclusive attributes + noreturn and pure. */ + +int ATTR ((noreturn)) +fnoret_pure1 (int); /* { dg-message "previous declaration here" } */ + +int ATTR ((pure)) +fnoret_pure1 (int); /* { dg-warning "ignoring attribute .pure. because it conflicts with attribute .noreturn." } */ + +/* Unfortunately, attributes on a single declarations may not be processed + in the same order as specified... */ +int ATTR ((noreturn, pure)) +fnoret_pure2 (int); /* { dg-warning "ignoring attribute .pure. because it conflicts with attribute .noreturn." } */ + + +int ATTR ((noreturn)) ATTR ((pure)) +fnoret_pure3 (int); /* { dg-warning "ignoring attribute .pure. because it conflicts with attribute .noreturn." } */ + + +int ATTR ((__pure__)) +fpure_noret1 (int); + +int ATTR ((pure)) +fpure_noret1 (int); /* { dg-message "previous declaration here" } */ + +int ATTR ((noreturn)) +fpure_noret1 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .pure." } */ + + +int ATTR ((pure, noreturn)) +fpure_noret2 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .pur." } */ + +int ATTR ((pure)) ATTR ((noreturn)) +fpure_noret3 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .pure." } */ + + +/* Exercise the handling of the mutually exclusive attributes + noreturn and returns_twice. */ + +int ATTR ((noreturn)) +fnoret_returns_twice1 (int); /* { dg-message "previous declaration here" } */ + +int ATTR ((returns_twice)) +fnoret_returns_twice1 (int); /* { dg-warning "ignoring attribute .returns_twice. because it conflicts with attribute .noreturn." } */ + +/* Unfortunately, attributes on a single declarations may not be processed + in the same order as specified... */ +int ATTR ((noreturn, returns_twice)) +fnoret_returns_twice2 (int); /* { dg-warning "ignoring attribute .returns_twice. because it conflicts with attribute .noreturn." } */ + + +int ATTR ((noreturn)) ATTR ((returns_twice)) +fnoret_returns_twice3 (int); /* { dg-warning "ignoring attribute .returns_twice. because it conflicts with attribute .noreturn." } */ + + +int ATTR ((returns_twice)) +freturns_twice_noret1 (int); /* { dg-message "previous declaration here" } */ + +int ATTR ((noreturn)) +freturns_twice_noret1 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .returns_twice." } */ + + +int ATTR ((returns_twice, noreturn)) +freturns_twice_noret2 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .returns_twice." } */ + +int ATTR ((returns_twice)) ATTR ((noreturn)) +freturns_twice_noret3 (int); /* { dg-warning "ignoring attribute .noreturn. because it conflicts with attribute .returns_twice." } */ + + +/* Exercise the interaction of multiple combinations of mutually + exclusive attributes specified on distinct declarations. */ + +inline int ATTR ((always_inline)) +finline_cold_noreturn (int); + +inline int ATTR ((cold)) +finline_cold_noreturn (int); + +inline int ATTR ((noreturn)) +finline_cold_noreturn (int); + +inline int ATTR ((noinline)) +finline_cold_noreturn (int); /* { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */ + +inline int ATTR ((hot)) +finline_cold_noreturn (int); /* { dg-warning "ignoring attribute .hot. because it conflicts with attribute .cold." } */ + +inline int ATTR ((warn_unused_result)) +finline_cold_noreturn (int); /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */ + +inline int ATTR ((always_inline)) +finline_cold_noreturn (int); + +/* Expect no warning for the missing return statement below because + the function is noreturn. */ +inline int ATTR ((noreturn)) +finline_cold_noreturn (int i) { (void)&i; __builtin_abort (); } + + +/* Exercise the interaction of multiple combinations of mutually + exclusive attributes with some specified on the same declaration + and some on distinct declarations. */ + +inline int ATTR ((always_inline, hot)) +finline_hot_noret_align (int); + +inline int ATTR ((noreturn, noinline)) +finline_hot_noret_align (int); /* { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */ + +inline int ATTR ((cold, aligned (8))) +finline_hot_noret_align (int); /* { dg-warning "ignoring attribute .cold. because it conflicts with attribute .hot." } */ + +inline int ATTR ((warn_unused_result)) +finline_hot_noret_align (int); /* { dg-warning "ignoring attribute .warn_unused_result. because it conflicts with attribute .noreturn." } */ + +inline int ATTR ((aligned (4))) +finline_hot_noret_align (int); /* { dg-warning "ignoring attribute .aligned \\(4\\). because it conflicts with attribute .aligned \\(8\\)." } */ + +inline int ATTR ((aligned (8))) +finline_hot_noret_align (int); + +inline int ATTR ((const)) +finline_hot_noret_align (int); /* { dg-warning "ignoring attribute .const. because it conflicts with attribute .noreturn." } */ + +/* Expect no warning for the missing return statement below because + the function is noreturn. */ +inline int ATTR ((noreturn)) +finline_hot_noret_align (int i) { (void)&i; __builtin_abort (); } + + +/* Exercise variable attributes. */ + +extern int ATTR ((common)) +decl_common1; /* { dg-message "previous declaration here" } */ + +extern int ATTR ((nocommon)) +decl_common1; /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */ + + +extern int ATTR ((nocommon)) +decl_common2; /* { dg-message "previous declaration here" } */ + +extern int ATTR ((common)) +decl_common2; /* { dg-warning "ignoring attribute .common. because it conflicts with attribute .nocommon." } */ + + +extern int ATTR ((common, nocommon)) +decl_common3; /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */ + + +extern int ATTR ((common, nocommon)) +decl_common4; /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */ + + +void declare_common5_in_local_scope (void) +{ + extern int ATTR ((common)) + decl_common5; /* { dg-message "previous declaration here" } */ + (void)&decl_common5; +} + +extern int ATTR ((nocommon)) +decl_common5; /* { dg-warning "ignoring attribute .nocommon. because it conflicts with attribute .common." } */ + + +extern int ATTR ((nocommon)) +decl_common6; /* { dg-message "previous declaration here" } */ + +void declare_common6_in_local_scope (void) +{ + extern int ATTR ((common)) + decl_common6; /* { dg-warning "ignoring attribute .common. because it conflicts with attribute .nocommon." } */ + (void)&decl_common6; +} diff --git a/gcc/testsuite/c-c++-common/attributes-3.c b/gcc/testsuite/c-c++-common/attributes-3.c index 821278c..9d3a61c 100644 --- a/gcc/testsuite/c-c++-common/attributes-3.c +++ b/gcc/testsuite/c-c++-common/attributes-3.c @@ -12,16 +12,16 @@ extern __attribute__((noinline)) int fn1 (void); /* { dg-message "previous decla extern inline int fn1 (void); /* { dg-warning "inline declaration of" } */ extern inline int fn2 (void); /* { dg-message "previous declaration" } */ -extern __attribute__((noinline)) int fn2 (void); /* { dg-warning "attribute noinline follows inline declaration" } */ +extern __attribute__((noinline)) int fn2 (void); /* { dg-warning "attribute .noinline. follows inline declaration" } */ extern __attribute__((always_inline)) int fn3 (void); /* { dg-message "previous declaration" } */ -extern __attribute__((noinline)) int fn3 (void); /* { dg-warning "attribute .noinline. follows declaration with attribute .always_inline." } */ +extern __attribute__((noinline)) int fn3 (void); /* { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." } */ extern __attribute__((noinline)) int fn4 (void); /* { dg-message "previous declaration" } */ -extern __attribute__((always_inline)) int fn4 (void); /* { dg-warning "attribute .always_inline. follows declaration with attribute .noinline." } */ +extern __attribute__((always_inline)) int fn4 (void); /* { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .noinline." } */ extern __attribute__((hot)) int fn5 (void); /* { dg-message "previous declaration" } */ -extern __attribute__((cold)) int fn5 (void); /* { dg-warning "attribute .cold. follows declaration with attribute .hot." } */ +extern __attribute__((cold)) int fn5 (void); /* { dg-warning "ignoring attribute .cold. because it conflicts with attribute .hot." } */ extern __attribute__((cold)) int fn6 (void); /* { dg-message "previous declaration" } */ -extern __attribute__((hot)) int fn6 (void); /* { dg-warning "attribute .hot. follows declaration with attribute .cold." } */ +extern __attribute__((hot)) int fn6 (void); /* { dg-warning "ignoring attribute .hot. because it conflicts with attribute .cold." } */ diff --git a/gcc/testsuite/g++.dg/ext/mv11.s b/gcc/testsuite/g++.dg/ext/mv11.s new file mode 100644 index 0000000..32e8940 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/mv11.s @@ -0,0 +1 @@ + .file "mv11.C" diff --git a/gcc/testsuite/gcc.dg/attr-noinline.c b/gcc/testsuite/gcc.dg/attr-noinline.c index c2a5b1d..13cc660 100644 --- a/gcc/testsuite/gcc.dg/attr-noinline.c +++ b/gcc/testsuite/gcc.dg/attr-noinline.c @@ -17,7 +17,7 @@ static void function_declaration_both_after(void) {t();} static void function_declaration_noinline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */ -static inline void function_declaration_noinline_before(void) {t();} /* { dg-warning "follows declaration with attribute noinline" } */ +static inline void function_declaration_noinline_before(void) {t();} /* { dg-warning "follows declaration with attribute .noinline." } */ static inline void function_declaration_noinline_after(void) {t();} /* { dg-message "note: previous definition" } */ @@ -41,7 +41,7 @@ static void function_declaration_inline_noinline_after(void) __attribute__((__no static void function_declaration_noinline_inline_before(void) __attribute__((__noinline__)); /* { dg-message "note: previous declaration" } */ -static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute noinline" } */ +static inline void function_declaration_noinline_inline_before(void); /* { dg-warning "follows declaration with attribute .noinline." } */ static void function_declaration_noinline_inline_before(void) {t();} diff --git a/gcc/testsuite/gcc.dg/pr44964.c b/gcc/testsuite/gcc.dg/pr44964.c index 1df1bde..6c252ee 100644 --- a/gcc/testsuite/gcc.dg/pr44964.c +++ b/gcc/testsuite/gcc.dg/pr44964.c @@ -2,8 +2,9 @@ /* { dg-options "-fkeep-inline-functions -O" } */ static inline __attribute__ ((const)) -void baz (int i) +int baz (int i) { + return i; } static __attribute__ ((always_inline)) diff --git a/gcc/testsuite/gcc.dg/torture/pr42363.c b/gcc/testsuite/gcc.dg/torture/pr42363.c index 9c9da13..ad0eac8 100644 --- a/gcc/testsuite/gcc.dg/torture/pr42363.c +++ b/gcc/testsuite/gcc.dg/torture/pr42363.c @@ -46,16 +46,18 @@ int bizr (void) return i + 1; } -/* This might be regarded as pure and folded, rather than inlined. - It's pure evil. */ +/* This might be regarded as pure and folded, rather than inlined, + but because it's pure evil it's diagnosed and the noreturn attribute + is dropped. The const attribute is dropped as well because it's + mutually exclusive with pure. */ static int __attribute__ ((pure, const, noreturn)) -barf (void) -{ +barf (void) { + /* { dg-warning "ignoring attribute .const." "const" { target *-*-* } .-1 } */ + /* { dg-warning "ignoring attribute .noreturn." "noreturn" { target *-*-* } .-2 } */ } /* { dg-warning "does return" } */ static int __attribute__ ((pure, const)) -bark (void) -{ +bark (void) { /* { dg-warning "ignoring attribute .const." } */ barf (); } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c index 146b76c..58a4742 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-2.c @@ -113,7 +113,7 @@ int test9 (int *intarr) int test99 (int *intarr) { - extern int foo9 (int) __attribute__ ((pure)); + extern int foo9 (int) __attribute__ ((const)); int h, v; g9 = 9; h = foo9 (g9);