From patchwork Fri Aug 10 20:04:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 176622 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 265E22C0084 for ; Sat, 11 Aug 2012 06:06:05 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1345233967; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Cc:Subject:References:Date:In-Reply-To: Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List: Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:Sender:Delivered-To; bh=uVj67e4Hwu9URPdVxVTHEiawjbA=; b=gU07+JfE6NwLsO2n/1+ziblKujY0Uh66qrjI3AwWGTEUNYKtsCExg+yFU0nCeq TmVpkK9StzGCwT1IamxPRTkpdYllC/mgrrwYEc5CgRwl0NL5vtKH9Qa56AA8oYFn zKT0EIJSSr6dco4yGn+tLmPwtniu2xbKlqQHi9IEG40wE= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:From:To:Cc:Subject:References:X-URL:Date:In-Reply-To:Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=w1wMItraDRzHPAId1XyD7XfLHGVlpW6+gh1t/La/jLYgxV/NyLI1Q/mpje3HCR MYDvN9liBY7qzR6QWCipvsxbRMCbwQ7dPZi+jslSqnH0rR5AW/FPxS0Izj6hxX24 FCUpyFkQA2/EEvA/Sr9a4BQ77bgCGwHxekoorRM2Kgmns=; Received: (qmail 5918 invoked by alias); 10 Aug 2012 20:05:54 -0000 Received: (qmail 5892 invoked by uid 22791); 10 Aug 2012 20:05:36 -0000 X-SWARE-Spam-Status: No, hits=-4.9 required=5.0 tests=AWL, BAYES_40, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, SPF_HELO_PASS, TW_CD, TW_CX, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 10 Aug 2012 20:05:03 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q7AK4wpq031473 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 10 Aug 2012 16:04:58 -0400 Received: from localhost (ovpn-116-23.ams2.redhat.com [10.36.116.23]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q7AK4tDV002736 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 10 Aug 2012 16:04:57 -0400 Received: by localhost (Postfix, from userid 500) id CBED829C04D; Fri, 10 Aug 2012 22:04:54 +0200 (CEST) From: Dodji Seketeli To: Jason Merrill , "Joseph S. Myers" , Richard Henderson Cc: GCC Patches Subject: Re: [PATCH] PR 53528 c++/ C++11 Generalized Attribute support References: <501312EF.9060405@redhat.com> X-URL: http://www.redhat.com Date: Fri, 10 Aug 2012 22:04:54 +0200 In-Reply-To: <501312EF.9060405@redhat.com> (Jason Merrill's message of "Fri, 27 Jul 2012 18:15:11 -0400") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 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 Hello, I am replying to Joseph, Richard and Jason in the same message, along with the patch that hopefully addresses most of the concerns that were raised. "Joseph S. Myers" writes: > Do you handle how, in certain syntactic locations, a C++11 attribute binds > differently to a GNU attribute? (I haven't studied the patch, so feel > free to point me to testcases it adds that verify such differences, if > applicable.) > Do you handle how, in certain syntactic locations, a C++11 attribute binds > differently to a GNU attribute? (I haven't studied the patch, so feel > free to point me to testcases it adds that verify such differences, if > applicable.) This is a broad question. :-) Here is how I'd synthesize the big differences between the two kinds of attributes. In a sequence of declaration specifiers, a c++11 attribute usually applies to the type that precedes it and only for the current declaration. For class/enum types, when the attribute is in the class-head it applies to the type for any subsequent use of that type. When the attribute follows a declarator, it applies to the entity or type being declared. Last, when a c++11 attribute starts a declaration, it applies to the entity being declared, even though the declarator-id for that entity might be on the far right of the declaration. A GNU attribute that appears in a sequence of declaration specifiers or that starts a declaration applies to the entity being declared. In a declarator, what the attribute applies to varies depending on the particular kind of declarator. Examples of tests that exhibit these differences in bindings in the updated patch below are: g++.dg/cpp0x/gen-attrs-1.C vs g++.dg/ext/attrib1.C g++.dg/cpp0x/gen-attrs-3.C vs g++.dg/ext/attrib3.C g++.dg/cpp0x/gen-attrs-4.C vs g++.dg/ext/attrib4.C g++.dg/cpp0x/gen-attrs-{6,6-1}.C vs g++.dg/ext/attrib6.C g++.dg/cpp0x/gen-attrs-8.C vs g++.dg/ext/attrib8.C g++.dg/cpp0x/gen-attrs-13-1.C vs g++.dg/ext/attrib13.C g++.dg/cpp0x/gen-attrs-30.C vs g++.dg/ext/attrib30.C g++.dg/cpp0x/gen-attrs-33.C vs g++.dg/ext/attrib33.C g++.dg/cpp0x/gen-attrs-34.C vs g++.dg/ext/attrib34.C g++.dg/cpp0x/gen-attrs-{36,36-1}.C vs g++.dg/ext/attrib36.C g++.dg/cpp0x/gen-attrs-37.C vs g++.dg/ext/attrib37.C g++.dg/cpp0x/gen-attrs-38.C vs g++.dg/ext/attrib38.C g++.dg/cpp0x/gen-attrs-{39,39-1}.C vs g++.dg/ext/attrib39.C g++.dg/cpp0x/gen-attrs-41.C vs g++.dg/ext/attrib41.C g++.dg/cpp0x/gen-attrs-43.C vs g++.dg/ext/attrib43.C g++.dg/cpp0x/gen-attrs-44.C vs g++.dg/ext/attrib44.C g++.dg/cpp0x/gen-attrs-52.C g++.dg/cpp0x/gen-attrs-53.C Richard Henderson writes: > > + attributes_table->scoped = XRESIZEVEC (struct scoped_attributes, > > + attributes_table->scoped, > > + attributes_table->len + 1); > > A good clue that you want VEC's instead, with VEC_safe_push. OK. While doing this, I realized that to write: DEF_VEC_O (attribute_spec_t); DEF_VEC_ALLOC_O (attribute_spec_t, heap); We need attribute_spec_t (which is really struct attribute_spec) to be "writable". But in it current form in mainline, all of its fields are const. So I removed these consts from struct attribute_spec and did the change you suggested in the patch below. Jason Merrill writes: > On 07/26/2012 11:19 AM, Dodji Seketeli wrote: > > +// Example taken from dcl.attr.grammar: > > + > > +int p[10]; > > +void f() > > +{ > > + int x = 42, y[5]; > > + /* Here, the '[[gnu::' should have introduced an attribute, ont a > > + lambda invocation an array subscripting expression. */ > > + int(p[[gnu::x] { return x; }()]); // { dg-error "expected|consecutive" } > > + /* Likewise, the '[[gnu::' is invalid here. */ > > + y[[gnu::] { return 2; }()] = 2; // { dg-error "expected|consecutive" } > > The example in the standard doesn't have gnu:: in it. Search and > replace error? Fixed. > > > + if (cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE) == NULL > > + || cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE) == NULL) > > Let's use ! rather than == NULL so that these lines fit in 80 chars. Fixed. > > + /* If E is a constant, fold it and return it right away. > > + Otherwise, build an ALIGNOF_EXPR that will be substituted > > + into, later at template instantiation time. */ > > + tree cst = TYPE_P (e) ? NULL_TREE : cxx_constant_value (e); > > I think you want fold_non_dependent_expr_sfinae rather than > cxx_constant_value. Fixed. > > + /* > > + [dcl.align]/3 > > Extra newline. > > > +int **** [[gnu::format(printf, 1, 2)]] foo(const char *, ...); > > This seems wrong; you can't apply the format attribute to a pointer type. Correct. The issue here was that the c++11 attribute was being wrongly bound to the function, like what is done for GNU attributes. I have changed this in several steps: - I augmented the handling of the ptr-declarator construct to support parsing attributes that come after the pointer, unlike what is done for GNU attributes in that case. - I added a std_attribute field to struct cp_declarator to stick the C++11 attributes parsed as part of the declarator constructs there. - I modified grokdeclarator to apply these c++11 attributes to the pointer type itself, rather than to the pointed to type. > About your earlier question on IRC, the solution to the problem you're > having with > > > struct A {int i;} [[gnu::aligned(16)]] a; > > is that C++11 attributes after the closing brace should not be passed > to finish_struct. Instead, we should apply them to the type (without > TYPE_IN_PLACE) after the type is complete. Yes, this is what I figured after we had the chat. I have updated the patch to just avoid parsing c++11 attributes as part of the class specifier construct. Rather, I am letting them be parsed as part of the declarator specifiers, by cp_parser_decl_specifier_seq -- this complies with the decl-specifier-seq production, btw. In cp_parser_decl_specifier_seq, I first tried to apply the c++11 attribute to the (already constructed) type it follows, like what you suggest. But then I am getting the warning: warning: ignoring attributes applied to 'A' after definition issued by build_type_attribute_qual_variant when called by decl_attribute. Basically, this is because we are not allowed to build a distinct copy of a class type. Then I figured maybe I could: - do what you suggest for non-tagged types. - for tagged types apply the attribute to the decl. The aligned attribute in particular can be applied to the decl; that's a practical workaround way to comply with the requirement to apply the attribute to the type only for that declaration. I have added the test g++.dg/cpp0x/gen-attrs-52.C for this. > > > +typedef union { int i; } U [[gnu::transparent_union]]; > > For the same reason, this should also be rejected; the testcase should > put the attribute before the opening brace. We accept this with > GNU-style attributes for backward compatibility, but there's no reason > to propagate that lossage into the new syntax. Syntactically, why can't we say that the attribute applies to the typedef? My understanding is that this is syntactically allowed by the noptr-declarator production. If you want the attribute to be rejected for this particular kind of cases, how would you like to do it? > > +template struct A > > +{ > > + void foo() const; > > +} [[gnu::aligned(4)]]; > > Likewise. Now in this case shadow_tag now kicks in and displays a meaningful warning. I have updated the test case accordingly. > > > + typedef void ([[gnu::__stdcall__]] T::*F) (L*); > > I don't think a C++11 attribute can appear in this position. I think > it should be > > typedef void (T::*F)(L*) [[gnu::__stdcall__]] Fixed. > > > + virtual void [[gnu::__stdcall__]] A(L *listener) = 0; > > Similarly, here the stdcall attribute appertains to "void", which > makes no sense. Fixed. I have added more test cases in g++.dg/cpp0x/gen-attrs-36-1.C. > > +S [[gnu::__stdcall__]] getS(); > > +extern int * ([[gnu::stdcall]] *fooPtr)( void); > > +int * [[gnu::stdcall]] myFn01( void) { return 0; } > > Likewise. Fixed. > > > + typedef [[gnu::aligned (16)]] struct { > > This also seems ill-formed, as there are no type-specifiers before the > attribute, so there's nothing for it to appertain to. Fixed. > > +int > > +[[gnu::noreturn]] > > +[[gnu::unused]] > > +one(void); // OK > > noreturn doesn't make sense for "int". Nor does unused, really. > C++11 attributes that appertain to the function must either come > before any specifiers or after the declarator. Fixed the noreturn case. Now that c++11 attributes in declspecs apply to the type that precedes them, the attribute is rejected at application time b/c it has to be applied to a function declaration. A warning is emitted. For unused though, I am not sure how to do that in an appropriate manner. An idea? > > +template > > +[[gnu::packed]] > > +struct A; // { dg-warning "attribute" } > > Here the patch is giving the wrong warning; it complains about > applying the attribute to A, but actually we should be warning > about an attribute that would appertain to all the declarators in a > declaration with no declarators for it to appertain to. Fixed. > > > +[[gnu::deprecated]] enum E { E0 }; // { dg-warning "attribute ignored in declaration of" } > > +// { dg-message "must follow the" "" { target *-*-* } 3 } > > Same here. Fixed. > > + if (strcmp (attr_name, IDENTIFIER_POINTER (get_attribute_name (list))) == 0) > > + gcc_checking_assert (TREE_CODE (get_attribute_name (list)) == IDENTIFIER_NODE); > > + for (a = lookup_ident_attribute (get_attribute_name (a2), attributes); > > + a = lookup_ident_attribute (get_attribute_name (a2), TREE_CHAIN (a))) > > Line too long. Fixed. > > > + /* A given attribute has been parsed as a C++-11 generalized > > + attribute. */ > > Let's drop the word "generalized" throughout the patch. I don't see > how these attributes are any more generalized than GNU attributes; we > should just describe them as C++11 attributes. Done. > > +cxx_11_attribute_p (const_tree attr) > > Let's change cxx_11 to cxx11. Done. >> + struct scoped_attributes *ns = set_attributes_namespace (attrs, >> + attrs_len, >> + name_space); >> + if (ns == NULL) >> + return NULL; >> + >> + for (i = 0; i < attrs_len; ++i) >> + register_scoped_attribute (&attrs[i], ns); > > This looks kind of funny; setting their namespace and then registering > them sound like the same thing. Let's rename set_attributes_namespace > to register_scoped_attributes and call register_scoped_attribute from > there. Done. >> + if (TREE_STATIC (node)) >> + { >> + /* For file scope variables and static members, the target >> + supports alignments that are at most >> + MAX_OFILE_ALIGNMENT. */ > > I think this should check TREE_STATIC || DECL_EXTERNAL. Done. Patch tested on i686-pc-linux-gnu, x86_64-unknown-linux-gnu and powerpc64-unknown-linux-gnu against trunk. gcc/ * plugin.h (register_scoped_attributes): Declare new function. * tree.h (enu attribute_flags::ATTR_FLAG_CXX_11): New flag. (lookup_scoped_attribute_spec, cxx_11_attribute_p) (get_attribute_name, get_attribute_namespace): Declare new functions. (struct attribute_spec): Remove const qualifier from the members. (attribute_spec_t): New typedef qualifier. * tree.c (comp_type_attributes, private_lookup_attribute) (lookup_ident_attribute, remove_attribute, merge_attribute) (attribute_hash_list, attribute_list_contained): Use get_attribute_name. * attribs.c (decl_attributes): Don't crash on error_mark_node. (attribute_hash): Remove global variable. (attributes_table): New global variable. (find_attribute_namespace, register_scoped_attribute) (attributes_array_length): New static functions. (register_scoped_attributes, lookup_scoped_attribute_spec) (cxx11_attribute_p, get_attribute_name, get_attribute_namespace): New public functions. (init_attributes): Register all the GNU attributes into the "gnu" namespace. (register_attribute): Use register_scoped_attribute to register the attribute into the "gnu" namespace. (lookup_attribute_spec): Use lookup_scoped_attribute_spec to lookup the attribute in the "gnu" namespace. (decl_attributes): Use new get_attribute_namespace and lookup_scoped_attribute_spec to consider attribute namespaces when looking up attributes. When operating in c++-11 mode, pass flag ATTR_FLAG_CXX11 to the spec handler. gcc/c-family/ * c-common.h (bitfield_p, cxx_fundamental_alignment_p): Declare new functions. * c-common.c (check_cxx_fundamental_alignment_constraints): New static function. (handle_aligned_attribute): In c++-11 choose strictest alignment among many. Use new check_cxx_fundamental_alignment_constraints. gcc/cp/ * cp-tree.h (enum cpp0x_warn_str::CPP0X_ATTRIBUTES): New member. (enum cp_decl_spec::ds_std_attribute): New enumerator. (struct cp_decl_specifier_seq::std_attributes): New field. (fold_non_dependent_expr_sfinae): This is now public. (cxx_alignas_expr): Declare new functions. * decl.c (check_tag_decl): Add check for c++11 attributes being applied to a missing declarator. (grokdeclarator): Make sure a c++11 attribute after an array declarator appertains to the array, an attribute after a function declarator appertains to the function type, an attribute after a declarator-id appertains to the entity being declared, and an attribute after a pointer declarator appertain to the pointer. * decl2.c (is_late_template_attribute): Use get_attribute_name. * error.c (maybe_warn_cpp0x): Support CPP0X_GENERALIZED_ATTRIBUTES. * parser.c (cp_next_tokens_can_be_attribute_p) (cp_next_tokens_can_be_gnu_attribute_p) (cp_next_tokens_can_be_std_attribute_p) (cp_nth_tokens_can_be_attribute_p) (cp_nth_tokens_can_be_gnu_attribute_p) (cp_nth_tokens_can_be_std_attribute_p) (cp_parser_gnu_attribute_list, cp_parser_std_attribute) (cp_parser_std_attribute_spec, cp_parser_std_attribute_spec_seq) (cp_parser_attributes_opt, cp_parser_std_attribute_list): New static functions. (cp_parser_gnu_attributes_opt): Replace cp_parser_attributes_opt. (cp_parser_gnu_attribute_list): Replace cp_parser_attribute_list. (cp_parser_postfix_expression): Disallow "[[" tokens here. (cp_parser_label_for_labeled_statement): Use cp_next_tokens_can_be_std_attribute_p here. (cp_parser_block_declaration): Use cp_nth_tokens_can_be_std_attribute_p here. (cp_parser_decl_specifier_seq): Likewise. C++11 attributes appertain to the type that precedes them and only for the current declaration. Get out when C++11 attributes follow the class specifier. (cp_parser_init_declarator): Parsing attributes here is no more a GNU extension in c++-11. (cp_parser_type_specifier_seq): Use cp_next_tokens_can_be_attribute_p. (cp_parser_direct_declarator): Likewise. Hang c++11 attributes off of following the declarator to its syntactic construct. It'll later be applied to the proper appertaining entity by grokdeclarator. (cp_parser_ptr_operator): Likewise. (make_declarator): Initialize cp_declarator::std_attribute. (cp_parser_ptr_operator): Take an out parameter for c++11 attributes. Update comments. (cp_parser_new_declarator_opt) (cp_parser_conversion_declarator_opt): Adjust. (cp_parser_declarator): Likewise. Handle C++11 attributes; set them to cp_declarator::std_attribute. Rename attributes to gnu_attribute for better legibility. (cp_parser_simple_declaration): Update comment. (cp_parser_class_specifier_1): Parse GNU attributes specifically (cp_parser_enum_specifier): Accept only gnu attributes after the specifier. (cp_parser_member_declaration): Don't clear attributes -- intended for the entity being declared -- too early because check_tag_decl needs them. (cp_parser_statement): Update comment. Parse optional c++11 attributes at the beginning of the relevant kind of statements and ignore them, for now. (cp_parser_label_for_labeled_statement): Parse optional c++11 attributes before the label and apply them to it. * semantics.c (potential_constant_expression_1): Likewise. * typeck.c (fundamental_alignment_p, cxx_alignas_expr): New public functions. * pt.c (fold_non_dependent_expr_sfinae): Make this public. gcc/testsuite/ * g++.dg/cpp0x/gen-attrs-1.C: New test. * g++.dg/cpp0x/gen-attrs-2.C: Likewise. * g++.dg/cpp0x/gen-attrs-3.C: Likewise. * g++.dg/cpp0x/gen-attrs-4.C: Likewise. * g++.dg/cpp0x/gen-attrs-5.C: Likewise. * g++.dg/cpp0x/gen-attrs-6.C: Likewise. * g++.dg/cpp0x/gen-attrs-6-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-7.C: Likewise. * g++.dg/cpp0x/gen-attrs-8.C: Likewise. * g++.dg/cpp0x/gen-attrs-9.C: Likewise. * g++.dg/cpp0x/gen-attrs-10.C: Likewise. * g++.dg/cpp0x/gen-attrs-11.C: Likewise. * g++.dg/cpp0x/gen-attrs-12.C: Likewise. * g++.dg/cpp0x/gen-attrs-13.C: Likewise. * g++.dg/cpp0x/gen-attrs-14.C: Likewise. * g++.dg/cpp0x/gen-attrs-15.C: Likewise. * g++.dg/cpp0x/gen-attrs-16.C: Likewise. * g++.dg/cpp0x/gen-attrs-17.C: Likewise. * g++.dg/cpp0x/gen-attrs-18.C: Likewise. * g++.dg/cpp0x/gen-attrs-19.C: Likewise. * g++.dg/cpp0x/gen-attrs-20.C: Likewise. * g++.dg/cpp0x/gen-attrs-21.C: Likewise. * g++.dg/cpp0x/gen-attrs-22.C: Likewise. * g++.dg/cpp0x/gen-attrs-23.C: Likewise. * g++.dg/cpp0x/gen-attrs-24.C: Likewise. * g++.dg/cpp0x/gen-attrs-25.C: Likewise. * g++.dg/cpp0x/gen-attrs-26.C: Likewise. * g++.dg/cpp0x/gen-attrs-27.C: Likewise. * g++.dg/cpp0x/gen-attrs-28.C: Likewise. * g++.dg/cpp0x/gen-attrs-29.C: Likewise. * g++.dg/cpp0x/gen-attrs-30.C: Likewise. * g++.dg/cpp0x/gen-attrs-31.C: Likewise. * g++.dg/cpp0x/gen-attrs-32.C: Likewise. * g++.dg/cpp0x/gen-attrs-33.C: Likewise. * g++.dg/cpp0x/gen-attrs-34.C: Likewise. * g++.dg/cpp0x/gen-attrs-35.C: Likewise. * g++.dg/cpp0x/gen-attrs-36.C: Likewise. * g++.dg/cpp0x/gen-attrs-36-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-37.C: Likewise. * g++.dg/cpp0x/gen-attrs-38.C: Likewise. * g++.dg/cpp0x/gen-attrs-39.C: Likewise. * g++.dg/cpp0x/gen-attrs-39-1.C: Likewise. * g++.dg/cpp0x/gen-attrs-40.C: Likewise. * g++.dg/cpp0x/gen-attrs-41.C: Likewise. * g++.dg/cpp0x/gen-attrs-42.C: Likewise. * g++.dg/cpp0x/gen-attrs-43.C: Likewise. * g++.dg/cpp0x/gen-attrs-44.C: Likewise. * g++.dg/cpp0x/gen-attrs-45.C: Likewise. * g++.dg/cpp0x/gen-attrs-46.C: Likewise. * g++.dg/cpp0x/gen-attrs-47.C: Likewise. * g++.dg/cpp0x/gen-attrs-48.C: Likewise. * g++.dg/cpp0x/gen-attrs-49.C: Likewise. * g++.dg/cpp0x/gen-attrs-50.C: Likewise. * g++.dg/cpp0x/gen-attrs-51.C: Likewise. * g++.dg/cpp0x/gen-attrs-52.C: Likewise. * g++.dg/cpp0x/gen-attrs-53.C: Likewise. --- gcc/attribs.c | 269 +++++++++++- gcc/c-family/c-common.c | 108 +++++- gcc/c-family/c-common.h | 1 + gcc/cp/cp-tree.h | 17 +- gcc/cp/decl.c | 56 +++- gcc/cp/decl2.c | 2 +- gcc/cp/error.c | 5 + gcc/cp/parser.c | 635 ++++++++++++++++++++++++--- gcc/cp/pt.c | 2 +- gcc/cp/typeck.c | 59 +++ gcc/plugin.h | 3 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C | 3 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C | 9 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C | 17 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C | 17 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-13-1.C | 4 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C | 5 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C | 14 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C | 9 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C | 8 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C | 19 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C | 19 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C | 10 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C | 11 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C | 11 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C | 22 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-21.C | 21 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-22.C | 7 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-23.C | 11 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-24.C | 4 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-25.C | 12 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-26.C | 15 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-27.C | 6 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-28.C | 13 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-29.C | 10 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-3.C | 21 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-30.C | 9 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-31.C | 16 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-32.C | 37 ++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-33.C | 19 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-34.C | 19 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-35.C | 20 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-36-1.C | 13 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-36.C | 23 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-37.C | 15 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-38.C | 12 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C | 10 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-39.C | 10 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C | 40 ++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-40.C | 5 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-41.C | 20 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-42.C | 13 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-43.C | 6 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-44.C | 3 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-45.C | 4 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-46.C | 5 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-47.C | 13 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-48.C | 17 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-49.C | 17 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-5.C | 23 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-50.C | 22 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-51.C | 9 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C | 21 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-53.C | 32 ++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-6-1.C | 16 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-6.C | 20 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-7.C | 4 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-8.C | 6 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C | 12 + gcc/tree.c | 38 +- gcc/tree.h | 34 +- 71 files changed, 1927 insertions(+), 111 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-13-1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-21.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-22.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-23.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-24.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-25.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-26.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-27.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-28.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-29.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-30.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-31.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-32.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-33.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-34.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-35.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-36-1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-36.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-37.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-38.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-39-1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-39.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-40.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-41.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-42.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-43.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-44.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-45.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-46.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-47.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-48.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-49.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-5.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-50.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-51.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-52.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-53.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-6-1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-6.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-7.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-8.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C diff --git a/gcc/attribs.c b/gcc/attribs.c index d3af414..5347eb4 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -38,9 +38,6 @@ along with GCC; see the file COPYING3. If not see searched. */ static const struct attribute_spec *attribute_tables[4]; -/* Hashtable mapping names (represented as substrings) to attribute specs. */ -static htab_t attribute_hash; - /* Substring representation. */ struct substring @@ -49,6 +46,28 @@ struct substring int length; }; +DEF_VEC_O (attribute_spec_t); +DEF_VEC_ALLOC_O (attribute_spec_t, heap); + +/* Scoped attribute name representation. */ + +typedef struct scoped_attributes +{ + const char *ns; + VEC (attribute_spec_t, heap) *attributes; + htab_t attribute_hash; +} scoped_attributes_t; + +DEF_VEC_O (scoped_attributes_t); +DEF_VEC_ALLOC_O (scoped_attributes_t, heap); + +/* The table of scope attributes. */ +static VEC(scoped_attributes_t, heap) *attributes_table; + +static scoped_attributes_t* find_attribute_namespace (const char*); +static void register_scoped_attribute (const struct attribute_spec *, + scoped_attributes_t *); + static bool attributes_initialized = false; /* Default empty table of attributes. */ @@ -102,6 +121,116 @@ eq_attr (const void *p, const void *q) return (!strncmp (spec->name, str->str, str->length) && !spec->name[str->length]); } +/* Insert an array of attributes ATTRIBUTES into a namespace. + ATTRIBUTES_LENGTH is the length of the ATTRIBUTES array. NS is the + name of attribute namespace. The function returns the namespace + into which the attributes have been registered. */ + +scoped_attributes_t* +register_scoped_attributes (const struct attribute_spec * attributes, + unsigned attributes_length, + const char* ns) +{ + unsigned index; + scoped_attributes_t *result = NULL, *attrs; + bool found_attrs = false; + + /* See if we already have attributes in the namespace NS. */ + FOR_EACH_VEC_ELT (scoped_attributes_t, + attributes_table, + index, attrs) + { + if (strcmp (attrs->ns, ns) == 0) + { + found_attrs = true; + break; + } + } + + if (found_attrs) + { + /* We already have attributes in the namespace NS. Add + ATTRIBUTES to that namespace. */ + + unsigned i; + + gcc_assert (strcmp (attrs->ns, ns) == 0); + + result = VEC_index (scoped_attributes_t, attributes_table, index); + + for (i = 0; i < attributes_length; ++i) + VEC_safe_push (attribute_spec_t, heap, + result->attributes, &attributes[i]); + } + else + { + /* We don't have any namespace NS yet. Create one and add + ATTRIBUTES into it. */ + + scoped_attributes_t sa; + unsigned i; + + if (attributes_table == NULL) + attributes_table = VEC_alloc (scoped_attributes_t, heap, 64); + + memset (&sa, 0, sizeof (sa)); + sa.ns = ns; + sa.attributes = VEC_alloc (attribute_spec_t, heap, 64); + for (i = 0; i < attributes_length; ++i) + VEC_safe_push (attribute_spec_t, heap, sa.attributes, &attributes[i]); + VEC_safe_push (scoped_attributes_t, heap, attributes_table, &sa); + result = VEC_last (scoped_attributes_t, attributes_table); + } + + if (result != NULL) + { + unsigned i; + for (i = 0; i < attributes_length; ++i) + register_scoped_attribute (&attributes[i], result); + } + return result; +} + +/* Return the namespace which name is NS, NULL if none exist. */ + +static scoped_attributes_t* +find_attribute_namespace (const char* ns) +{ + unsigned ix; + scoped_attributes_t *iter; + + FOR_EACH_VEC_ELT (scoped_attributes_t, attributes_table, ix, iter) + if (ns == iter->ns + || (iter->ns != NULL + && ns != NULL + && !strcmp (iter->ns, ns))) + { + if (iter->attribute_hash == 0) + iter->attribute_hash = + htab_create (200, hash_attr, eq_attr, NULL); + return VEC_index (scoped_attributes_t, attributes_table, ix); + } + + return NULL; +} + +/* Return the length of the NULL terminated array of struct + attribute_spec. */ + +static unsigned +attributes_array_length (const struct attribute_spec *attributes_array) +{ + unsigned i; + + if (attributes_array == NULL || attributes_array[0].name == NULL) + return 0; + + for (i = 0; attributes_array[i].name != NULL; ++i) + ; + + return i; +} + /* Initialize attribute tables, and make some sanity checks if --enable-checking. */ @@ -109,7 +238,6 @@ void init_attributes (void) { size_t i; - int k; if (attributes_initialized) return; @@ -181,12 +309,12 @@ init_attributes (void) } #endif - attribute_hash = htab_create (200, hash_attr, eq_attr, NULL); - for (i = 0; i < ARRAY_SIZE (attribute_tables); i++) - for (k = 0; attribute_tables[i][k].name != NULL; k++) - { - register_attribute (&attribute_tables[i][k]); - } + for (i = 0; i < ARRAY_SIZE (attribute_tables); ++i) + /* Put all the GNU attributes into the "gnu" namespace. */ + register_scoped_attributes (attribute_tables[i], + attributes_array_length (attribute_tables[i]), + "gnu"); + invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL); attributes_initialized = true; } @@ -196,9 +324,23 @@ init_attributes (void) void register_attribute (const struct attribute_spec *attr) { + register_scoped_attribute (attr, find_attribute_namespace ("gnu")); +} + +/* Insert a single attribute ATTR into a namespace of attributes. */ + +static void +register_scoped_attribute (const struct attribute_spec *attr, + scoped_attributes_t *name_space) +{ struct substring str; void **slot; + gcc_assert (attr != NULL && name_space != NULL); + + if (name_space->attribute_hash == NULL) + name_space->attribute_hash = htab_create (200, hash_attr, eq_attr, NULL); + str.str = attr->name; str.length = strlen (str.str); @@ -206,27 +348,45 @@ register_attribute (const struct attribute_spec *attr) in the form '__text__'. */ gcc_assert (str.length > 0 && str.str[0] != '_'); - slot = htab_find_slot_with_hash (attribute_hash, &str, + slot = htab_find_slot_with_hash (name_space->attribute_hash, &str, substring_hash (str.str, str.length), INSERT); gcc_assert (!*slot || attr->name[0] == '*'); *slot = (void *) CONST_CAST (struct attribute_spec *, attr); } -/* Return the spec for the attribute named NAME. */ +/* Return the spec for the scoped attribute with namespace NS and + name NAME. */ const struct attribute_spec * -lookup_attribute_spec (const_tree name) +lookup_scoped_attribute_spec (const_tree ns, const_tree name) { struct substring attr; + scoped_attributes_t *attrs; + + const char *ns_str = (ns != NULL_TREE) ? IDENTIFIER_POINTER (ns): NULL; + + attrs = find_attribute_namespace (ns_str); + + if (attrs == NULL) + return NULL; attr.str = IDENTIFIER_POINTER (name); attr.length = IDENTIFIER_LENGTH (name); extract_attribute_substring (&attr); return (const struct attribute_spec *) - htab_find_with_hash (attribute_hash, &attr, + htab_find_with_hash (attrs->attribute_hash, &attr, substring_hash (attr.str, attr.length)); } + +/* Return the spec for the attribute named NAME. */ + +const struct attribute_spec * +lookup_attribute_spec (const_tree name) +{ + return lookup_scoped_attribute_spec (get_identifier ("gnu"), name); +} + /* 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, @@ -243,7 +403,7 @@ decl_attributes (tree *node, tree attributes, int flags) tree a; tree returned_attrs = NULL_TREE; - if (TREE_TYPE (*node) == error_mark_node) + if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node) return NULL_TREE; if (!attributes_initialized) @@ -302,10 +462,12 @@ decl_attributes (tree *node, tree attributes, int flags) for (a = attributes; a; a = TREE_CHAIN (a)) { - tree name = TREE_PURPOSE (a); + tree ns = get_attribute_namespace (a); + tree name = get_attribute_name (a); tree args = TREE_VALUE (a); tree *anode = node; - const struct attribute_spec *spec = lookup_attribute_spec (name); + 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; @@ -313,8 +475,15 @@ decl_attributes (tree *node, tree attributes, int flags) if (spec == NULL) { if (!(flags & (int) ATTR_FLAG_BUILT_IN)) - warning (OPT_Wattributes, "%qE attribute directive ignored", - name); + { + if (ns == NULL_TREE || !cxx11_attribute_p (a)) + warning (OPT_Wattributes, "%qE attribute directive ignored", + name); + else + warning (OPT_Wattributes, + "%<%E::%E%> scoped attribute directive ignored", + ns, name); + } continue; } else if (list_length (args) < spec->min_length @@ -406,9 +575,15 @@ decl_attributes (tree *node, tree attributes, int flags) } if (spec->handler != NULL) - returned_attrs = chainon ((*spec->handler) (anode, name, args, - flags, &no_add_attrs), - returned_attrs); + { + 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); + } /* Layout the decl in case anything changed. */ if (spec->type_required && DECL_P (*node) @@ -488,6 +663,56 @@ decl_attributes (tree *node, tree attributes, int flags) return returned_attrs; } +/* Return TRUE iff ATTR has been parsed by the front-end as a C++-11 + attribute. + + When G++ parses a C++11 attribute, it is represented as + a TREE_LIST which TREE_PURPOSE is itself a TREE_LIST. TREE_PURPOSE + (TREE_PURPOSE (ATTR)) is the namespace of the attribute, and the + TREE_VALUE (TREE_PURPOSE (ATTR)) is its non-qualified name. Please + use get_attribute_namespace and get_attribute_name to retrieve the + namespace and name of the attribute, as these accessors work with + GNU attributes as well. */ + +bool +cxx11_attribute_p (const_tree attr) +{ + if (attr == NULL_TREE + || TREE_CODE (attr) != TREE_LIST) + return false; + + return (TREE_CODE (TREE_PURPOSE (attr)) == TREE_LIST); +} + +/* Return the name of the attribute ATTR. This accessor works on GNU + and C++11 (scoped) attributes. + + Please read the comments of cxx11_attribute_p to understand the + format of attributes. */ + +tree +get_attribute_name (const_tree attr) +{ + if (cxx11_attribute_p (attr)) + return TREE_VALUE (TREE_PURPOSE (attr)); + return TREE_PURPOSE (attr); +} + +/* Return the namespace of the attribute ATTR. This accessor works on + GNU and C++11 (scoped) attributes. On GNU attributes, + it returns an identifier tree for the string "gnu". + + Please read the comments of cxx11_attribute_p to understand the + format of attributes. */ + +tree +get_attribute_namespace (const_tree attr) +{ + if (cxx11_attribute_p (attr)) + return TREE_PURPOSE (TREE_PURPOSE (attr)); + return get_identifier ("gnu"); +} + /* Subroutine of set_method_tm_attributes. Apply TM attribute ATTR to the method FNDECL. */ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index a002541..fd135d5 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -484,6 +484,7 @@ const struct c_common_resword c_common_reswords[] = { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY }, { "__volatile", RID_VOLATILE, 0 }, { "__volatile__", RID_VOLATILE, 0 }, + { "alignas", RID_ALIGNAS, D_CXXONLY | D_CXX0X | D_CXXWARN }, { "alignof", RID_ALIGNOF, D_CXXONLY | D_CXX0X | D_CXXWARN }, { "asm", RID_ASM, D_ASM }, { "auto", RID_AUTO, 0 }, @@ -6993,6 +6994,84 @@ check_user_alignment (const_tree align, bool allow_zero) } return i; } +/* + If in c++-11, check if the c++-11 alignment constraint with respect + to fundamental alignment (in [dcl.align]) are satisfied. If not in + c++-11 mode, does nothing. + + [dcl.align]2/ says: + + [* if the constant expression evaluates to a fundamental alignment, + the alignment requirement of the declared entity shall be the + specified fundamental alignment. + + * if the constant expression evaluates to an extended alignment + and the implementation supports that alignment in the context + of the declaration, the alignment of the declared entity shall + be that alignment + + * if the constant expression evaluates to an extended alignment + and the implementation does not support that alignment in the + context of the declaration, the program is ill-formed]. */ + +static bool +check_cxx_fundamental_alignment_constraints (tree node, + unsigned align_log, + int flags) +{ + bool alignment_too_large_p = false; + + if (!(flags & ATTR_FLAG_CXX11) + || (node == NULL_TREE || node == error_mark_node)) + return true; + + if (cxx_fundamental_alignment_p ((1U << align_log))) + return true; + + if (DECL_P (node)) + { + if (TREE_STATIC (node)) + { + /* For file scope variables and static members, the target + supports alignments that are at most + MAX_OFILE_ALIGNMENT. */ + if ((1U << align_log) > MAX_OFILE_ALIGNMENT) + alignment_too_large_p = true; + } + else + { +#ifdef BIGGEST_FIELD_ALIGNMENT +#define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_FIELD_ALIGNMENT +#else +#define MAX_TARGET_FIELD_ALIGNMENT BIGGEST_ALIGNMENT +#endif + /* For non-static members, the target supports either + alignments that at most either BIGGEST_FIELD_ALIGNMENT + if it is defined or BIGGEST_ALIGNMENT. */ + if (TREE_CODE (node) == FIELD_DECL + && decl_function_context (node) + && (1U << align_log) > MAX_TARGET_FIELD_ALIGNMENT) + alignment_too_large_p = true; +#undef MAX_TARGET_FIELD_ALIGNMENT + /* For stack variables, the target supports at most + MAX_STACK_ALIGNMENT. */ + else if (decl_function_context (node) != NULL + && (1U << align_log) > MAX_STACK_ALIGNMENT) + alignment_too_large_p = true; + } + } + else if (TYPE_P (node)) + { + /* Let's be liberal for types. */ + if ((1U << align_log) > BIGGEST_ALIGNMENT) + alignment_too_large_p = true; + } + + if (alignment_too_large_p) + error ("requested alignment is too large"); + + return !alignment_too_large_p; +} /* Handle a "aligned" attribute; arguments as in struct attribute_spec.handler. */ @@ -7017,7 +7096,8 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, else if (TYPE_P (*node)) type = node, is_type = 1; - if ((i = check_user_alignment (align_expr, false)) == -1) + if ((i = check_user_alignment (align_expr, false)) == -1 + || !check_cxx_fundamental_alignment_constraints (*node, i, flags)) *no_add_attrs = true; else if (is_type) { @@ -7047,6 +7127,13 @@ 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 (flags & ATTR_FLAG_CXX11 + && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) + /* C++-11 [dcl.align/4]: + [When multiple alignment-specifiers are specified for an + entity, the alignment requirement shall be set to the + strictest specified alignment]. */ + *no_add_attrs = true; else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) { @@ -11011,4 +11098,23 @@ convert_vector_to_pointer_for_subscript (location_t loc, } } +/* Return true iff ALIGN is an integral constant that is a fundamental + alignment, as defined by [basic.align] in the c++-11 + specifications. + + That is: + + [A fundamental alignment is represented by an alignment less than or + equal to the greatest alignment supported by the implementation + in all contexts, which is equal to + alignof(std::max_align_t)]. */ + +bool +cxx_fundamental_alignment_p (unsigned align) +{ + + return (align <= MAX (TYPE_ALIGN (long_long_integer_type_node), + TYPE_ALIGN (long_double_type_node))); +} + #include "gt-c-family-c-common.h" diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 050112e..691593f 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -787,6 +787,7 @@ extern bool keyword_begins_type_specifier (enum rid); extern bool keyword_is_storage_class_specifier (enum rid); extern bool keyword_is_type_qualifier (enum rid); extern bool keyword_is_decl_specifier (enum rid); +extern bool cxx_fundamental_alignment_p (unsigned); #define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, 1) #define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, 1) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 44f3ac1..9437197 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -411,7 +411,9 @@ typedef enum cpp0x_warn_str /* user defined literals */ CPP0X_USER_DEFINED_LITERALS, /* delegating constructors */ - CPP0X_DELEGATING_CTORS + CPP0X_DELEGATING_CTORS, + /* C++11 attributes */ + CPP0X_ATTRIBUTES } cpp0x_warn_str; /* The various kinds of operation used by composite_pointer_type. */ @@ -4680,6 +4682,7 @@ typedef enum cp_decl_spec { ds_type_spec, ds_redefined_builtin_type_spec, ds_attribute, + ds_std_attribute, ds_storage_class, ds_long_long, ds_last /* This enumerator must always be the last one. */ @@ -4698,6 +4701,8 @@ typedef struct cp_decl_specifier_seq { tree type; /* The attributes, if any, provided with the specifier sequence. */ tree attributes; + /* The c++11 attributes that follows the type specifier. */ + tree std_attributes; /* If non-NULL, a built-in type that the user attempted to redefine to some other type. */ tree redefined_builtin_type; @@ -4766,8 +4771,14 @@ struct cp_declarator { to indicate this is a parameter pack. */ BOOL_BITFIELD parameter_pack_p : 1; location_t id_loc; /* Currently only set for cdk_id and cdk_function. */ - /* Attributes that apply to this declarator. */ + /* GNU Attributes that apply to this declarator. If the declarator + is a pointer or a reference, these attribute apply to the type + pointed to. */ tree attributes; + /* Standard C++11 attributes that apply to this declarator. If the + declarator is a pointer or a reference, these attributes apply + to the pointer, rather than to the type pointed to. */ + tree std_attributes; /* For all but cdk_id and cdk_error, the contained declarator. For cdk_id and cdk_error, guaranteed to be NULL. */ cp_declarator *declarator; @@ -5399,6 +5410,7 @@ extern tree build_non_dependent_expr (tree); extern void make_args_non_dependent (VEC(tree,gc) *); extern bool reregister_specialization (tree, tree, tree); extern tree fold_non_dependent_expr (tree); +extern tree fold_non_dependent_expr_sfinae (tree, tsubst_flags_t); extern bool alias_type_or_template_p (tree); extern bool alias_template_specialization_p (tree); extern bool explicit_class_specialization_p (tree); @@ -5817,6 +5829,7 @@ extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qual_signature (tree, tree); extern tree cxx_sizeof_or_alignof_expr (tree, enum tree_code, bool); extern tree cxx_sizeof_or_alignof_type (tree, enum tree_code, bool); +extern tree cxx_alignas_expr (tree, tsubst_flags_t); extern tree cxx_sizeof_nowarn (tree); extern tree is_bitfield_expr_with_lowered_type (const_tree); extern tree unlowered_expr_type (const_tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b637643..038628a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4238,10 +4238,17 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) /* For a template class (an explicit instantiation), use the current location. */ loc = input_location; - warning_at (loc, OPT_Wattributes, "attribute ignored in declaration " - "of %q#T", declared_type); - inform (loc, "attribute for %q#T must follow the %qs keyword", - declared_type, class_key_or_enum_as_string (declared_type)); + if (cxx11_attribute_p (declspecs->attributes)) + warning_at (declspecs->locations[ds_attribute], + OPT_Wattributes, + "ignoring attribute applying to missing declarator"); + else + { + warning_at (loc, OPT_Wattributes, "attribute ignored in declaration " + "of %q#T", declared_type); + inform (loc, "attribute for %q#T must follow the %qs keyword", + declared_type, class_key_or_enum_as_string (declared_type)); + } } return declared_type; @@ -9111,6 +9118,15 @@ grokdeclarator (const cp_declarator *declarator, } } + if (declspecs->std_attributes) + { + /* Apply the c++11 attributes to the type preceding them. */ + source_location saved_loc = input_location; + input_location = declspecs->locations[ds_std_attribute]; + decl_attributes (&type, declspecs->std_attributes, 0); + input_location = saved_loc; + } + /* Determine the type of the entity declared by recurring on the declarator. */ for (; declarator; declarator = declarator->declarator) @@ -9148,6 +9164,13 @@ grokdeclarator (const cp_declarator *declarator, case cdk_array: type = create_array_type_for_decl (dname, type, declarator->u.array.bounds); + if (declarator->std_attributes) + /* [dcl.array]/1: + + The optional attribute-specifier-seq appertains to the + array. */ + returned_attrs = chainon (returned_attrs, + declarator->std_attributes); break; case cdk_function: @@ -9344,6 +9367,13 @@ grokdeclarator (const cp_declarator *declarator, } type = build_function_type (type, arg_types); + if (declarator->std_attributes) + /* [dcl.fct]/2: + + The optional attribute-specifier-seq appertains to + the function type. */ + decl_attributes (&type, declarator->std_attributes, + 0); } break; @@ -9506,6 +9536,17 @@ grokdeclarator (const cp_declarator *declarator, declarator->u.pointer.qualifiers); type_quals = cp_type_quals (type); } + + /* Apply C++11 attributes to the pointer, and not to the + type pointed to. This is unlike like what is done for + GNU attributes above. It is to comply with [dcl.ptr]/1: + + [the optional attribute-specifier-seq (7.6.1) appertains + to the pointer and not to the object pointed to]. */ + if (declarator->std_attributes) + decl_attributes (&type, declarator->std_attributes, + 0); + ctype = NULL_TREE; break; @@ -9658,6 +9699,13 @@ grokdeclarator (const cp_declarator *declarator, attrlist = &returned_attrs; } + if (declarator + && declarator->kind == cdk_id + && declarator->std_attributes) + /* [dcl.meaning]/1: The optional attribute-specifier-seq following + a declarator-id appertains to the entity that is declared. */ + *attrlist = chainon (*attrlist, declarator->std_attributes); + /* Handle parameter packs. */ if (parameter_pack_p) { diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 281f6ff..50d466c 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1091,7 +1091,7 @@ grokbitfield (const cp_declarator *declarator, static bool is_late_template_attribute (tree attr, tree decl) { - tree name = TREE_PURPOSE (attr); + tree name = get_attribute_name (attr); tree args = TREE_VALUE (attr); const struct attribute_spec *spec = lookup_attribute_spec (name); tree arg; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 58f0aff..fe20e836 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3368,6 +3368,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str) "delegating constructors " "only available with -std=c++11 or -std=gnu++11"); break; + case CPP0X_ATTRIBUTES: + pedwarn (input_location, 0, + "c++11 attributes " + "only available with -std=c++11 or -std=gnu++11"); + break; default: gcc_unreachable (); } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d8c3305..eccf31b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1232,6 +1232,7 @@ make_declarator (cp_declarator_kind kind) declarator = (cp_declarator *) alloc_declarator (sizeof (cp_declarator)); declarator->kind = kind; declarator->attributes = NULL_TREE; + declarator->std_attributes = NULL_TREE; declarator->declarator = NULL; declarator->parameter_pack_p = false; declarator->id_loc = UNKNOWN_LOCATION; @@ -1961,7 +1962,7 @@ static cp_declarator *cp_parser_declarator static cp_declarator *cp_parser_direct_declarator (cp_parser *, cp_parser_declarator_kind, int *, bool); static enum tree_code cp_parser_ptr_operator - (cp_parser *, tree *, cp_cv_quals *); + (cp_parser *, tree *, cp_cv_quals *, tree *); static cp_cv_quals cp_parser_cv_qualifier_seq_opt (cp_parser *); static cp_virt_specifiers cp_parser_virt_specifier_seq_opt @@ -2103,9 +2104,29 @@ static tree cp_parser_asm_clobber_list (cp_parser *); static tree cp_parser_asm_label_list (cp_parser *); +static bool cp_next_tokens_can_be_attribute_p + (cp_parser *); +static bool cp_next_tokens_can_be_gnu_attribute_p + (cp_parser *); +static bool cp_next_tokens_can_be_std_attribute_p + (cp_parser *); +static bool cp_nth_tokens_can_be_std_attribute_p + (cp_parser *, size_t); +static bool cp_nth_tokens_can_be_gnu_attribute_p + (cp_parser *, size_t); +static bool cp_nth_tokens_can_be_attribute_p + (cp_parser *, size_t); static tree cp_parser_attributes_opt (cp_parser *); -static tree cp_parser_attribute_list +static tree cp_parser_gnu_attributes_opt + (cp_parser *); +static tree cp_parser_gnu_attribute_list + (cp_parser *); +static tree cp_parser_std_attribute + (cp_parser *); +static tree cp_parser_std_attribute_spec + (cp_parser *); +static tree cp_parser_std_attribute_spec_seq (cp_parser *); static bool cp_parser_extension_opt (cp_parser *, int *); @@ -5609,6 +5630,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, switch (token->type) { case CPP_OPEN_SQUARE: + if (cp_next_tokens_can_be_std_attribute_p (parser)) + { + cp_parser_error (parser, + "two consecutive %<[%> shall " + "only introduce an attribute"); + return error_mark_node; + } postfix_expression = cp_parser_postfix_open_square_expression (parser, postfix_expression, @@ -6853,13 +6881,13 @@ static cp_declarator * cp_parser_new_declarator_opt (cp_parser* parser) { enum tree_code code; - tree type; - cp_cv_quals cv_quals; + tree type, std_attributes = NULL_TREE; + cp_cv_quals cv_quals; /* We don't know if there's a ptr-operator next, or not. */ cp_parser_parse_tentatively (parser); /* Look for a ptr-operator. */ - code = cp_parser_ptr_operator (parser, &type, &cv_quals); + code = cp_parser_ptr_operator (parser, &type, &cv_quals, &std_attributes); /* If that worked, look for more new-declarators. */ if (cp_parser_parse_definitely (parser)) { @@ -6868,8 +6896,11 @@ cp_parser_new_declarator_opt (cp_parser* parser) /* Parse another optional declarator. */ declarator = cp_parser_new_declarator_opt (parser); - return cp_parser_make_indirect_declarator + declarator = cp_parser_make_indirect_declarator (code, type, cv_quals, declarator); + if (declarator != NULL && declarator != cp_error_declarator) + declarator->attributes = std_attributes; + return declarator; } /* If the next token is a `[', there is a direct-new-declarator. */ @@ -8608,6 +8639,18 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) declaration-statement try-block + C++11: + + statement: + labeled-statement + attribute-specifier-seq (opt) expression-statement + attribute-specifier-seq (opt) compound-statement + attribute-specifier-seq (opt) selection-statement + attribute-specifier-seq (opt) iteration-statement + attribute-specifier-seq (opt) jump-statement + declaration-statement + attribute-specifier-seq (opt) try-block + TM Extension: statement: @@ -8624,15 +8667,20 @@ static void cp_parser_statement (cp_parser* parser, tree in_statement_expr, bool in_compound, bool *if_p) { - tree statement; + tree statement, std_attrs = NULL_TREE; cp_token *token; - location_t statement_location; + location_t statement_location, attrs_location; restart: if (if_p != NULL) *if_p = false; /* There is no statement yet. */ statement = NULL_TREE; + + cp_lexer_save_tokens (parser->lexer); + attrs_location = cp_lexer_peek_token (parser->lexer)->location; + std_attrs = cp_parser_std_attribute_spec_seq (parser); + /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ @@ -8650,6 +8698,13 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Looks like a labeled-statement with a case label. Parse the label, and then use tail recursion to parse the statement. */ + if (std_attrs != NULL_TREE) + { + /* Attributes should be parsed as part of the the + declaration, so let's un-parse them. */ + cp_lexer_rollback_tokens (parser->lexer); + std_attrs = NULL_TREE; + } cp_parser_label_for_labeled_statement (parser); goto restart; @@ -8713,6 +8768,15 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Looks like a labeled-statement with an ordinary label. Parse the label, and then use tail recursion to parse the statement. */ + + if (std_attrs != NULL_TREE) + { + /* Attributes should be parsed as part of the the + declaration, so let's un-parse them. */ + cp_lexer_rollback_tokens (parser->lexer); + std_attrs = NULL_TREE; + } + cp_parser_label_for_labeled_statement (parser); goto restart; } @@ -8749,6 +8813,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, { if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) { + if (std_attrs != NULL_TREE) + { + /* Attributes should be parsed as part of the the + declaration, so let's un-parse them. */ + cp_lexer_rollback_tokens (parser->lexer); + std_attrs = NULL_TREE; + } + cp_parser_parse_tentatively (parser); /* Try to parse the declaration-statement. */ cp_parser_declaration_statement (parser); @@ -8763,6 +8835,13 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, /* Set the line number for the statement. */ if (statement && STATEMENT_CODE_P (TREE_CODE (statement))) SET_EXPR_LOCATION (statement, statement_location); + + /* Note that for now, we don't do anything with c++11 statements + parsed at this level. */ + if (std_attrs != NULL_TREE) + warning_at (attrs_location, + OPT_Wattributes, + "attributes at the beginning of statement are ignored"); } /* Parse the label for a labeled-statement, i.e. @@ -8783,6 +8862,7 @@ cp_parser_label_for_labeled_statement (cp_parser* parser) { cp_token *token; tree label = NULL_TREE; + tree attributes = cp_parser_std_attribute_spec_seq (parser); bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; /* The next token should be an identifier. */ @@ -8859,21 +8939,23 @@ cp_parser_label_for_labeled_statement (cp_parser* parser) lab: __attribute__ ((unused)) int i; we want the attribute to attach to "i", not "lab". */ if (label != NULL_TREE - && cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + && cp_next_tokens_can_be_gnu_attribute_p (parser)) { tree attrs; - cp_parser_parse_tentatively (parser); - attrs = cp_parser_attributes_opt (parser); + attrs = cp_parser_gnu_attributes_opt (parser); if (attrs == NULL_TREE || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) cp_parser_abort_tentative_parse (parser); else if (!cp_parser_parse_definitely (parser)) ; else - cplus_decl_attributes (&label, attrs, 0); + attributes = chainon (attributes, attrs); } + if (attributes != NULL_TREE) + cplus_decl_attributes (&label, attributes, 0); + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; } @@ -10299,8 +10381,7 @@ cp_parser_block_declaration (cp_parser *parser, else if (cxx_dialect >= cxx0x && token2->type == CPP_NAME && ((cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ) - || (cp_lexer_peek_nth_token (parser->lexer, 3)->keyword - == RID_ATTRIBUTE))) + || (cp_nth_tokens_can_be_attribute_p (parser, 3)))) cp_parser_alias_declaration (parser); /* Otherwise, it's a using-declaration. */ else @@ -10530,6 +10611,7 @@ cp_parser_simple_declaration (cp_parser* parser, decl-specifier-seq: decl-specifier-seq [opt] decl-specifier + decl-specifier attribute-specifier-seq [opt] (C++11) decl-specifier: storage-class-specifier @@ -10564,6 +10646,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser, int* declares_class_or_enum) { bool constructor_possible_p = !parser->in_declarator_p; + bool found_decl_spec = false; cp_token *start_token = NULL; cp_decl_spec ds; @@ -10577,7 +10660,6 @@ cp_parser_decl_specifier_seq (cp_parser* parser, while (true) { bool constructor_p; - bool found_decl_spec; cp_token *token; ds = ds_last; @@ -10589,12 +10671,75 @@ cp_parser_decl_specifier_seq (cp_parser* parser, if (!start_token) start_token = token; /* Handle attributes. */ - if (token->keyword == RID_ATTRIBUTE) + if (cp_next_tokens_can_be_attribute_p (parser)) { /* Parse the attributes. */ - decl_specs->attributes - = chainon (decl_specs->attributes, - cp_parser_attributes_opt (parser)); + tree attrs = cp_parser_attributes_opt (parser); + + /* In a sequence of declaration specifiers, c++11 attributes + appertain to the type that precede them. So the if block + below is going to apply the attributes to that type. + + However, in G++ we cannot apply attributes to an already + built *tagged* type, as that breaks some invariants. So, + for tagged types, to comply with [dcl.spec]/1 which says: + + [The attribute-specifier-seq affects the type only for + the declaration it appears in, not other declarations + involving the same type] + + we are going to apply the attributes to the declaration + that is carrying this type, just like what is done for GNU + attributes. decl_attributes then knows how to apply the + attributes to the type of that declaration only. For + non-tagged types, we are going to just apply the + attribute. */ + if (cxx11_attribute_p (attrs)) + { + if (!found_decl_spec) + /* The c++11 attribute is at the beginning of the + declaration. It appertains to the entity being + declared. */; + else + { + /* The c++11 attributes appertain to the type that + precedes. */ + if (decl_specs->type == NULL_TREE) + { + error_at (token->location, + "expected type specifier before attribute"); + attrs = NULL; + } + else + { + if (!TAGGED_TYPE_P (decl_specs->type)) + { + /* For non-tagged types, schedule these + attributes to be applied to the type that + precedes. grokdeclarator is where the + attribute is going to be applied, by + calling decl_attributes. */ + decl_specs->std_attributes = + chainon (decl_specs->attributes, attrs); + if (decl_specs->locations[ds_std_attribute] == 0) + decl_specs->locations[ds_std_attribute] + = token->location; + attrs = NULL_TREE; + } + else + { + /* For a tagged type, we apply the + attributes to the declaration, as + explained in the comment of the + enclosing 'if' block. */; + } + } + } + } + + decl_specs->attributes + = chainon (decl_specs->attributes, + attrs); if (decl_specs->locations[ds_attribute] == 0) decl_specs->locations[ds_attribute] = token->location; continue; @@ -11321,13 +11466,14 @@ static cp_declarator * cp_parser_conversion_declarator_opt (cp_parser* parser) { enum tree_code code; - tree class_type; + tree class_type, std_attributes = NULL_TREE; cp_cv_quals cv_quals; /* We don't know if there's a ptr-operator next, or not. */ cp_parser_parse_tentatively (parser); /* Try the ptr-operator. */ - code = cp_parser_ptr_operator (parser, &class_type, &cv_quals); + code = cp_parser_ptr_operator (parser, &class_type, &cv_quals, + &std_attributes); /* If it worked, look for more conversion-declarators. */ if (cp_parser_parse_definitely (parser)) { @@ -11336,8 +11482,11 @@ cp_parser_conversion_declarator_opt (cp_parser* parser) /* Parse another optional declarator. */ declarator = cp_parser_conversion_declarator_opt (parser); - return cp_parser_make_indirect_declarator + declarator = cp_parser_make_indirect_declarator (code, class_type, cv_quals, declarator); + if (declarator != NULL || declarator != cp_error_declarator) + declarator->attributes = std_attributes; + return declarator; } return NULL; @@ -14596,7 +14745,7 @@ cp_parser_enum_specifier (cp_parser* parser) apply them if appropriate. */ if (cp_parser_allow_gnu_extensions_p (parser)) { - tree trailing_attr = cp_parser_attributes_opt (parser); + tree trailing_attr = cp_parser_gnu_attributes_opt (parser); trailing_attr = chainon (trailing_attr, attributes); cplus_decl_attributes (&type, trailing_attr, @@ -15498,7 +15647,7 @@ cp_parser_init_declarator (cp_parser* parser, *attributes_start_token = NULL; cp_declarator *declarator; tree prefix_attributes; - tree attributes; + tree attributes = NULL; tree asm_specification; tree initializer; tree decl = NULL_TREE; @@ -15564,22 +15713,20 @@ cp_parser_init_declarator (cp_parser* parser, decl_specifiers->type = maybe_update_decl_type (decl_specifiers->type, scope); - /* If we're allowing GNU extensions, look for an asm-specification - and attributes. */ + /* If we're allowing GNU extensions, look for an + asm-specification. */ if (cp_parser_allow_gnu_extensions_p (parser)) { /* Look for an asm-specification. */ asm_spec_start_token = cp_lexer_peek_token (parser->lexer); asm_specification = cp_parser_asm_specification_opt (parser); - /* And attributes. */ - attributes_start_token = cp_lexer_peek_token (parser->lexer); - attributes = cp_parser_attributes_opt (parser); } else - { - asm_specification = NULL_TREE; - attributes = NULL_TREE; - } + asm_specification = NULL_TREE; + + /* Look for attributes. */ + attributes_start_token = cp_lexer_peek_token (parser->lexer); + attributes = cp_parser_attributes_opt (parser); /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); @@ -15908,7 +16055,7 @@ cp_parser_declarator (cp_parser* parser, enum tree_code code; cp_cv_quals cv_quals; tree class_type; - tree attributes = NULL_TREE; + tree gnu_attributes = NULL_TREE, std_attributes = NULL_TREE; /* Assume this is not a constructor, destructor, or type-conversion operator. */ @@ -15916,14 +16063,16 @@ cp_parser_declarator (cp_parser* parser, *ctor_dtor_or_conv_p = 0; if (cp_parser_allow_gnu_extensions_p (parser)) - attributes = cp_parser_attributes_opt (parser); + gnu_attributes = cp_parser_gnu_attributes_opt (parser); /* Check for the ptr-operator production. */ cp_parser_parse_tentatively (parser); /* Parse the ptr-operator. */ code = cp_parser_ptr_operator (parser, &class_type, - &cv_quals); + &cv_quals, + &std_attributes); + /* If that worked, then we have a ptr-operator. */ if (cp_parser_parse_definitely (parser)) { @@ -15950,6 +16099,15 @@ cp_parser_declarator (cp_parser* parser, declarator = cp_parser_make_indirect_declarator (code, class_type, cv_quals, declarator); + + /* For C++11 attributes, the standard at [decl.ptr]/1 says: + + the optional attribute-specifier-seq appertains to the + pointer and not to the object pointed to". */ + if (std_attributes + && declarator + && (declarator != cp_error_declarator)) + declarator->std_attributes = std_attributes; } /* Everything else is a direct-declarator. */ else @@ -15962,9 +16120,8 @@ cp_parser_declarator (cp_parser* parser, member_p); } - if (attributes && declarator && declarator != cp_error_declarator) - declarator->attributes = attributes; - + if (gnu_attributes && declarator && declarator != cp_error_declarator) + declarator->attributes = gnu_attributes; return declarator; } @@ -16104,6 +16261,7 @@ cp_parser_direct_declarator (cp_parser* parser, cp_virt_specifiers virt_specifiers; tree exception_specification; tree late_return; + tree attrs; is_declarator = true; @@ -16117,6 +16275,8 @@ cp_parser_direct_declarator (cp_parser* parser, exception_specification = cp_parser_exception_specification_opt (parser); + attrs = cp_parser_std_attribute_spec_seq (parser); + late_return = (cp_parser_late_return_type_opt (parser, member_p ? cv_quals : -1)); @@ -16130,6 +16290,7 @@ cp_parser_direct_declarator (cp_parser* parser, virt_specifiers, exception_specification, late_return); + declarator->std_attributes = attrs; /* Any subsequent parameter lists are to do with return type, so are not those of the declared function. */ @@ -16179,10 +16340,11 @@ cp_parser_direct_declarator (cp_parser* parser, break; } else if ((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED) - && token->type == CPP_OPEN_SQUARE) + && token->type == CPP_OPEN_SQUARE + && !cp_next_tokens_can_be_attribute_p (parser)) { /* Parse an array-declarator. */ - tree bounds; + tree bounds, attrs; if (ctor_dtor_or_conv_p) *ctor_dtor_or_conv_p = 0; @@ -16235,13 +16397,16 @@ cp_parser_direct_declarator (cp_parser* parser, break; } + attrs = cp_parser_std_attribute_spec_seq (parser); declarator = make_array_declarator (declarator, bounds); + declarator->std_attributes = attrs; } else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT) { { tree qualifying_scope; tree unqualified_name; + tree attrs; special_function_kind sfk; bool abstract_ok; bool pack_expansion_p = false; @@ -16308,6 +16473,8 @@ cp_parser_direct_declarator (cp_parser* parser, break; } + attrs = cp_parser_std_attribute_spec_seq (parser); + if (qualifying_scope && at_namespace_scope_p () && TREE_CODE (qualifying_scope) == TYPENAME_TYPE) { @@ -16422,6 +16589,7 @@ cp_parser_direct_declarator (cp_parser* parser, declarator = make_id_declarator (qualifying_scope, unqualified_name, sfk); + declarator->std_attributes = attrs; declarator->id_loc = token->location; declarator->parameter_pack_p = pack_expansion_p; @@ -16469,9 +16637,11 @@ cp_parser_direct_declarator (cp_parser* parser, /* Parse a ptr-operator. ptr-operator: + * attribute-specifier-seq [opt] cv-qualifier-seq [opt] (C++11) * cv-qualifier-seq [opt] & :: [opt] nested-name-specifier * cv-qualifier-seq [opt] + nested-name-specifier * attribute-specifier-seq [opt] cv-qualifier-seq [opt] (C++11) GNU Extension: @@ -16491,10 +16661,12 @@ cp_parser_direct_declarator (cp_parser* parser, static enum tree_code cp_parser_ptr_operator (cp_parser* parser, tree* type, - cp_cv_quals *cv_quals) + cp_cv_quals *cv_quals, + tree *attributes) { enum tree_code code = ERROR_MARK; cp_token *token; + tree attrs = NULL_TREE; /* Assume that it's not a pointer-to-member. */ *type = NULL_TREE; @@ -16525,6 +16697,10 @@ cp_parser_ptr_operator (cp_parser* parser, if (code == INDIRECT_REF || cp_parser_allow_gnu_extensions_p (parser)) *cv_quals = cp_parser_cv_qualifier_seq_opt (parser); + + attrs = cp_parser_std_attribute_spec_seq (parser); + if (attributes != NULL) + *attributes = attrs; } else { @@ -16562,6 +16738,10 @@ cp_parser_ptr_operator (cp_parser* parser, parser->scope = NULL_TREE; parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; + /* Look for optional c++11 attributes. */ + attrs = cp_parser_std_attribute_spec_seq (parser); + if (attributes != NULL) + *attributes = attrs; /* Look for the optional cv-qualifier-seq. */ *cv_quals = cp_parser_cv_qualifier_seq_opt (parser); } @@ -16921,7 +17101,7 @@ cp_parser_type_specifier_seq (cp_parser* parser, bool is_cv_qualifier; /* Check for attributes first. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)) + if (cp_next_tokens_can_be_attribute_p (parser)) { type_specifier_seq->attributes = chainon (type_specifier_seq->attributes, @@ -18027,7 +18207,7 @@ cp_parser_class_specifier_1 (cp_parser* parser) closing_brace = cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE); /* Look for trailing attributes to apply to this class. */ if (cp_parser_allow_gnu_extensions_p (parser)) - attributes = cp_parser_attributes_opt (parser); + attributes = cp_parser_gnu_attributes_opt (parser); if (type != error_mark_node) type = finish_struct (type, attributes); if (nested_name_specifier_p) @@ -18048,6 +18228,12 @@ cp_parser_class_specifier_1 (cp_parser* parser) cp_token *token = cp_lexer_peek_token (parser->lexer); bool want_semicolon = true; + if (cp_next_tokens_can_be_std_attribute_p (parser)) + /* Don't try to parse c++11 attributes here. As per the + grammar, that should be a task for + cp_parser_decl_specifier_seq. */ + want_semicolon = false; + switch (token->type) { case CPP_NAME: @@ -18898,8 +19084,6 @@ cp_parser_member_declaration (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, &declares_class_or_enum); - prefix_attributes = decl_specifiers.attributes; - decl_specifiers.attributes = NULL_TREE; /* Check for an invalid type-name. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -18998,6 +19182,12 @@ cp_parser_member_declaration (cp_parser* parser) { bool assume_semicolon = false; + /* Clear attributes from the decl_specifiers but keep them + around as prefix attributes that apply them to the entity + being declared. */ + prefix_attributes = decl_specifiers.attributes; + decl_specifiers.attributes = NULL_TREE; + /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -20104,6 +20294,81 @@ cp_parser_asm_label_list (cp_parser* parser) return nreverse (labels); } +/* Return TRUE iff the next tokens in the stream are possibly the + beginning of a GNU extension attribute. */ + +static bool +cp_next_tokens_can_be_gnu_attribute_p (cp_parser *parser) +{ + return cp_nth_tokens_can_be_gnu_attribute_p (parser, 1); +} + +/* Return TRUE iff the next tokens in the stream are possibly the + beginning of a standard C++-11 attribute. */ + +static bool +cp_next_tokens_can_be_std_attribute_p (cp_parser *parser) +{ + return cp_nth_tokens_can_be_std_attribute_p (parser, 1); +} + +/* Return TRUE iff the next Nth tokens in the stream are possibly the + beginning of a standard C++-11 attribute. */ + +static bool +cp_nth_tokens_can_be_std_attribute_p (cp_parser *parser, size_t n) +{ + cp_token *token = cp_lexer_peek_nth_token (parser->lexer, n); + + return (cxx_dialect >= cxx0x + && token->type == CPP_OPEN_SQUARE + && (token = cp_lexer_peek_nth_token (parser->lexer, n + 1)) + && token->type == CPP_OPEN_SQUARE); +} + +/* Return TRUE iff the next Nth tokens in the stream are possibly the + beginning of a GNU extension attribute. */ + +static bool +cp_nth_tokens_can_be_gnu_attribute_p (cp_parser *parser, size_t n) +{ + cp_token *token = cp_lexer_peek_nth_token (parser->lexer, n); + + return token->type == CPP_KEYWORD && token->keyword == RID_ATTRIBUTE; +} + +/* Return true iff the next tokens can be the beginning of either a + GNU attribute list, or a standard C++11 attribute sequence. */ + +static bool +cp_next_tokens_can_be_attribute_p (cp_parser *parser) +{ + return (cp_next_tokens_can_be_gnu_attribute_p (parser) + || cp_next_tokens_can_be_std_attribute_p (parser)); +} + +/* Return true iff the next Nth tokens can be the beginning of either + a GNU attribute list, or a standard C++11 attribute sequence. */ + +static bool +cp_nth_tokens_can_be_attribute_p (cp_parser *parser, size_t n) +{ + return (cp_nth_tokens_can_be_gnu_attribute_p (parser, n) + || cp_nth_tokens_can_be_std_attribute_p (parser, n)); +} + +/* Parse either a standard C++-11 attribute-specifier-seq, or a series + of GNU attributes, or return NULL. */ + +static tree +cp_parser_attributes_opt (cp_parser *parser) +{ + + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + return cp_parser_gnu_attributes_opt (parser); + return cp_parser_std_attribute_spec_seq (parser); +} + /* Parse an (optional) series of attributes. attributes: @@ -20112,10 +20377,10 @@ cp_parser_asm_label_list (cp_parser* parser) attribute: __attribute__ (( attribute-list [opt] )) - The return value is as for cp_parser_attribute_list. */ + The return value is as for cp_parser_gnu_attribute_list. */ static tree -cp_parser_attributes_opt (cp_parser* parser) +cp_parser_gnu_attributes_opt (cp_parser* parser) { tree attributes = NULL_TREE; @@ -20141,7 +20406,7 @@ cp_parser_attributes_opt (cp_parser* parser) token = cp_lexer_peek_token (parser->lexer); if (token->type != CPP_CLOSE_PAREN) /* Parse the attribute-list. */ - attribute_list = cp_parser_attribute_list (parser); + attribute_list = cp_parser_gnu_attribute_list (parser); else /* If the next token is a `)', then there is no attribute list. */ @@ -20162,7 +20427,7 @@ cp_parser_attributes_opt (cp_parser* parser) return attributes; } -/* Parse an attribute-list. +/* Parse a GNU attribute-list. attribute-list: attribute @@ -20180,7 +20445,7 @@ cp_parser_attributes_opt (cp_parser* parser) the arguments, if any. */ static tree -cp_parser_attribute_list (cp_parser* parser) +cp_parser_gnu_attribute_list (cp_parser* parser) { tree attribute_list = NULL_TREE; bool save_translate_strings_p = parser->translate_strings_p; @@ -20259,6 +20524,274 @@ cp_parser_attribute_list (cp_parser* parser) return nreverse (attribute_list); } +/* Parse a standard C++11 attribute. + + The returned representation is a TREE_LIST which TREE_PURPOSE is + the scoped name of the attribute, and the TREE_VALUE is its + arguments list. + + Note that the scoped name of the attribute is itself a TREE_LIST + which TREE_PURPOSE is the namespace of the attribute, and + TREE_VALUE its name. This is unlike a GNU attribute -- as parsed + by cp_parser_gnu_attribute_list -- that doesn't have any namespace + and which TREE_PURPOSE is directly the attribute name. + + Clients of the attribute code should use get_attribute_namespace + and get_attribute_name to get the actual namespace and name of + attributes, regardless of their being GNU or C++11 attributes. + + attribute: + attribute-token attribute-argument-clause [opt] + + attribute-token: + identifier + attribute-scoped-token + + attribute-scoped-token: + attribute-namespace :: identifier + + attribute-namespace: + identifier + + attribute-argument-clause: + ( balanced-token-seq ) + + balanced-token-seq: + balanced-token [opt] + balanced-token-seq balanced-token + + balanced-token: + ( balanced-token-seq ) + [ balanced-token-seq ] + { balanced-token-seq }. */ + +static tree +cp_parser_std_attribute (cp_parser *parser) +{ + tree attribute, attr_ns = NULL_TREE, attr_id, arguments; + cp_token *token; + + /* First, parse name of the the attribute, a.k.a + attribute-token. */ + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME) + attr_id = token->u.value; + else if (token->type == CPP_KEYWORD) + attr_id = ridpointers[(int) token->keyword]; + else + return NULL_TREE; + cp_lexer_consume_token (parser->lexer); + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_SCOPE) + { + /* We are seeing a scoped attribute token. */ + + cp_lexer_consume_token (parser->lexer); + attr_ns = attr_id; + + token = cp_lexer_consume_token (parser->lexer); + if (token->type == CPP_NAME) + attr_id = token->u.value; + else if (token->type == CPP_KEYWORD) + attr_id = ridpointers[(int) token->keyword]; + else + { + error_at (token->location, + "expected an identifier for the attribute name"); + return error_mark_node; + } + attribute = build_tree_list (build_tree_list (attr_ns, attr_id), + NULL_TREE); + token = cp_lexer_peek_token (parser->lexer); + } + else + attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id), + NULL_TREE); + + /* Now parse the optional argument close of the attribute. */ + + if (token->type != CPP_OPEN_PAREN) + return attribute; + + { + VEC(tree, gc) *vec; + int attr_flag = attribute_takes_identifier_p (attr_id) + ? id_attr + : normal_attr; + + vec = cp_parser_parenthesized_expression_list + (parser, attr_flag, /*cast_p=*/false, + /*allow_expansion_p=*/true, + /*non_constant_p=*/NULL); + if (vec == NULL) + arguments = error_mark_node; + else + { + arguments = build_tree_list_vec (vec); + release_tree_vector (vec); + } + + if (arguments == error_mark_node) + attribute = error_mark_node; + else + TREE_VALUE (attribute) = arguments; + } + + return attribute; +} + +/* Parse a list of standard C++-11 attributes. + + attribute-list: + attribute [opt] + attribute-list , attribute[opt] + attribute ... + attribute-list , attribute ... +*/ + +static tree +cp_parser_std_attribute_list (cp_parser *parser) +{ + tree attributes = NULL_TREE, attribute = NULL_TREE; + cp_token *token = NULL; + + while (true) + { + attribute = cp_parser_std_attribute (parser); + if (attribute == error_mark_node) + break; + if (attribute != NULL_TREE) + { + TREE_CHAIN (attribute) = attributes; + attributes = attribute; + } + token = cp_lexer_peek_token (parser->lexer); + if (token->type != CPP_COMMA) + break; + cp_lexer_consume_token (parser->lexer); + } + attributes = nreverse (attributes); + return attributes; +} + +/* Parse a standard C++-11 attribute specifier. + + attribute-specifier: + [ [ attribute-list ] ] + alignment-specifier + + alignment-specifier: + alignas ( type-id ... [opt] ) + alignas ( alignment-expression ... [opt] ). */ + +static tree +cp_parser_std_attribute_spec (cp_parser *parser) +{ + tree attributes = NULL_TREE; + cp_token *token = cp_lexer_peek_token (parser->lexer); + + if (token->type == CPP_OPEN_SQUARE + && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_SQUARE) + { + cp_lexer_consume_token (parser->lexer); + maybe_warn_cpp0x (CPP0X_ATTRIBUTES); + cp_lexer_consume_token (parser->lexer); + + attributes = cp_parser_std_attribute_list (parser); + + if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE) + || !cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) + cp_parser_skip_to_end_of_statement (parser); + } + else + { + tree alignas_expr; + bool complain = !cp_parser_uncommitted_to_tentative_parse_p (parser); + + /* Look for an alignment-specifier. */ + + token = cp_lexer_peek_token (parser->lexer); + + if (token->type != CPP_KEYWORD + || token->keyword != RID_ALIGNAS) + return NULL_TREE; + + cp_lexer_consume_token (parser->lexer); + maybe_warn_cpp0x (CPP0X_ATTRIBUTES); + + if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN) == NULL) + { + cp_parser_error (parser, "expected %<(%>"); + return error_mark_node; + } + + cp_parser_parse_tentatively (parser); + alignas_expr = cp_parser_type_id (parser); + + if (!cp_parser_parse_definitely (parser)) + { + gcc_assert (alignas_expr == error_mark_node + || alignas_expr == NULL_TREE); + + alignas_expr = + cp_parser_assignment_expression (parser, /*cast_p=*/false, + /**cp_id_kind=*/NULL); + if (alignas_expr == NULL_TREE + || alignas_expr == error_mark_node) + return alignas_expr; + } + + if (cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN) == NULL) + { + cp_parser_error (parser, "expected %<)%>"); + return error_mark_node; + } + + alignas_expr = + cxx_alignas_expr (alignas_expr, + complain ? tf_warning_or_error : tf_none); + alignas_expr = fold_non_dependent_expr (alignas_expr); + + /* Build the C++-11 representation of an 'aligned' + attribute. */ + attributes = + build_tree_list (build_tree_list (get_identifier ("gnu"), + get_identifier ("aligned")), + build_tree_list (NULL_TREE, alignas_expr)); + } + + return attributes; +} + +/* Parse a standard C++-11 attribute-specifier-seq. + + attribute-specifier-seq: + attribute-specifier-seq [opt] attribute-specifier + */ + +static tree +cp_parser_std_attribute_spec_seq (cp_parser *parser) +{ + tree attr_specs = NULL; + + while (true) + { + tree attr_spec = cp_parser_std_attribute_spec (parser); + if (attr_spec == NULL_TREE) + break; + if (attr_spec == error_mark_node) + return error_mark_node; + + TREE_CHAIN (attr_spec) = attr_specs; + attr_specs = attr_spec; + } + + attr_specs = nreverse (attr_specs); + return attr_specs; +} + /* Parse an optional `__extension__' keyword. Returns TRUE if it is present, and FALSE otherwise. *SAVED_PEDANTIC is set to the current value of the PEDANTIC flag, regardless of whether or not diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index ad81bab..2f21f04 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4942,7 +4942,7 @@ redeclare_class_template (tree type, tree parms) /* Simplify EXPR if it is a non-dependent expression. Returns the (possibly simplified) expression. */ -static tree +tree fold_non_dependent_expr_sfinae (tree expr, tsubst_flags_t complain) { if (expr == NULL_TREE) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 25f37e8..c50e1d2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1701,6 +1701,65 @@ cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain) else return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none); } + +/* Build a representation of an expression 'alignas(E).' Return the + folded integer value of E if it is an integral constant expression + that resolves to a valid alignment. If E depends on a template + parameter, return a syntactic representation tree of kind + ALIGNOF_EXPR. Otherwise, return an error_mark_node if the + expression is ill formed, or NULL_TREE if E is NULL_TREE. */ + +tree +cxx_alignas_expr (tree e, tsubst_flags_t complain) +{ + if (e == NULL_TREE || e == error_mark_node) + return e; + + if (processing_template_decl) + { + /* If E is a constant, fold it and return it right away. + Otherwise, build an ALIGNOF_EXPR that will be substituted + into, later at template instantiation time. */ + tree cst = TYPE_P (e) ? NULL_TREE : fold_non_dependent_expr_sfinae (e, tf_none); + if (cst != NULL && cst != error_mark_node) + return cst; + return cxx_alignof_expr (e, complain); + } + + if (TYPE_P (e)) + { + e = mark_type_use (e); + + /* [dcl.align]/3: + + When the alignment-specifier is of the form + alignas(type-id ), it shall have the same effect as + alignas( alignof(type-id )). */ + + return cxx_sizeof_or_alignof_type (e, ALIGNOF_EXPR, + complain & tf_error + || complain & tf_warning); + } + + /* If we reach this point, it means the alignas expression if of + the form "alignas(assignment-expression)", so we should follow + what is stated by [dcl.align]/2. */ + + e = mark_rvalue_use (e); + + /* [dcl.align]/2 says: + + [the assignment-expression shall be an integral constant + expression]. */ + e = cxx_constant_value (e); + if (e == NULL_TREE + || e == error_mark_node + || TREE_CODE (e) != INTEGER_CST) + return error_mark_node; + + return e; +} + /* EXPR is being used in a context that is not a function call. Enforce: diff --git a/gcc/plugin.h b/gcc/plugin.h index 4d2d12a..732c525 100644 --- a/gcc/plugin.h +++ b/gcc/plugin.h @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "gcc-plugin.h" struct attribute_spec; +struct scoped_attributes; extern void add_new_plugin (const char *); extern void parse_plugin_arg_opt (const char *); @@ -64,5 +65,7 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED, /* In attribs.c. */ extern void register_attribute (const struct attribute_spec *attr); +extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *, + unsigned, const char *); #endif /* PLUGIN_H */ diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C new file mode 100644 index 0000000..0f0ed8e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-1.C @@ -0,0 +1,3 @@ +// { dg-do compile { target c++11 } } + +int **** [[gnu::format(printf, 1, 2)]] foo(const char *, ...); // { dg-warning "attribute only applies to function types" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C new file mode 100644 index 0000000..cac568e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-10.C @@ -0,0 +1,9 @@ +// PR c++/12795 +// { dg-do compile { target c++11 } } +// { dg-require-alias "" } + +void foo() +{ + extern void bar [[gnu::__alias__ ("BAR")]] (); // { dg-warning "ignored" } + bar (); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C new file mode 100644 index 0000000..504b456 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-11.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } +// PR c++/13791 + +template struct O { + struct [[gnu::packed]] I { + int i; + char c; + }; + + I* foo(); +}; + +template +typename O::I* +O::foo() { return 0; } + +template class O; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C new file mode 100644 index 0000000..504b456 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-12.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++11 } } +// PR c++/13791 + +template struct O { + struct [[gnu::packed]] I { + int i; + char c; + }; + + I* foo(); +}; + +template +typename O::I* +O::foo() { return 0; } + +template class O; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13-1.C new file mode 100644 index 0000000..8fe5270 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13-1.C @@ -0,0 +1,4 @@ +// { dg-do compile { target c++11 } } + +extern char *f (__const char, int) throw () [[gnu::__pure__]]; // { dg-warning "does not apply to types" } +extern char *f (__const char *, int) throw () [[gnu::__pure__]]; // { dg-warning "does not apply to types" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C new file mode 100644 index 0000000..a1b4a84 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-13.C @@ -0,0 +1,5 @@ +// { dg-do compile { target c++11 } } +// PR c++/13854 + +extern char *rindex [[gnu::__pure__]] (__const char *__s, int __c) throw (); +extern char *rindex [[gnu::__pure__]] (__const char *__s, int __c) throw (); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C new file mode 100644 index 0000000..d646d27 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-14.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++11 } } +// PR c++/13170 +// The bogus attribute is ignored, but was in TYPE_ATTRIBUTES during +// parsing of the class, causing some variants to have it and some not. + +struct [[gnu::bogus]] A // { dg-warning "ignored" "" } +{ + virtual ~A(); + void foo(const A&); + void bar(const A&); +}; + +void A::foo(const A&) {} +void A::bar(const A& a) { foo(a); } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C new file mode 100644 index 0000000..bf05dbe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-15.C @@ -0,0 +1,9 @@ +// { dg-do compile { target c++11 } } +// PR c++/15317 + +struct A +{ + A(char); +}; +A::A([[gnu::unused]] char i2) +{} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C new file mode 100644 index 0000000..16080c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-16.C @@ -0,0 +1,8 @@ +// { dg-do compile { target c++11 } } +// Origin: +// PR c++/10479: use of non dependent expressions in attributes in templates + +template +struct foo2 { + float bar [[gnu::aligned(__alignof__(double))]]; +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C new file mode 100644 index 0000000..1e122b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.2.C @@ -0,0 +1,19 @@ +// { dg-do compile { target c++11 } } +// Origin: Benjamin Kosnik +// PR c++/17743: Attributes applied to typedefs. + +struct A { + typedef char layout_type[sizeof(double)] + [[gnu::aligned(__alignof__(double)]]); // { dg-error "expected" } + layout_type data; +}; + +struct B { + typedef char layout_type[sizeof(double)]; + layout_type data [[gnu::aligned(__alignof__(double))]]; +}; + +template struct StaticAssert; +template<> struct StaticAssert {}; + +StaticAssert<__alignof__(A) == __alignof__(B)> a1;// { dg-error "incomplete type and cannot be defined" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C new file mode 100644 index 0000000..8a5a798 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-17.C @@ -0,0 +1,19 @@ +// { dg-do compile { target c++11 } } +// Origin: Benjamin Kosnik +// PR c++/17743: Attributes applied to typedefs. + +struct A { + typedef char layout_type[sizeof(double)] + [[gnu::aligned(__alignof__(double))]]; + layout_type data; +}; + +struct B { + typedef char layout_type[sizeof(double)]; + layout_type data [[gnu::aligned(__alignof__(double))]]; +}; + +template struct StaticAssert; +template<> struct StaticAssert {}; + +StaticAssert<__alignof__(A) == __alignof__(B)> a1; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C new file mode 100644 index 0000000..3df13e6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-18.C @@ -0,0 +1,10 @@ +// PR c++/17542 +// Test that we warn when an attribute preceding the class-key is ignored. +// { dg-do compile { target c++11 } } + +[[gnu::packed]] struct A // { dg-warning "attribute" } +{ + char c; + int x; + void f(); +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C new file mode 100644 index 0000000..5ac93d8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-19.C @@ -0,0 +1,11 @@ +// PR c++/19739 +// { dg-do compile { target c++11 } } + +void Dummy() [[ , ]]; +void Dummy() {} + +int main (int argc, char **argv) +{ + Dummy(); + return 0; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C new file mode 100644 index 0000000..8c777c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2.C @@ -0,0 +1,11 @@ +// { dg-do compile { target c++11 } } + +struct [[gnu::packed]] A +{ + void f () const; +}; + +void +A::f () const +{ +} diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C new file mode 100644 index 0000000..f989ab2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C @@ -0,0 +1,22 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-g" } +// Origin: +// PR c++/19508: avoid attributes for template parameters + +template +struct BVector +{ + typedef T T2; + typedef T value_type [[gnu::aligned(8)]]; // { dg-bogus "attribute" "attribute" } + typedef T2 value_type2 [[gnu::aligned(8)]]; // { dg-bogus "attribute" "attribute" } + value_type v; +}; +BVector m; + +template