From patchwork Tue Sep 18 13:51:49 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 184724 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 D67B02C0091 for ; Tue, 18 Sep 2012 23:52:59 +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=1348581180; 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=iIbxL4H9iEYO8M0FHam1nqS/D1I=; b=qQbmu681Zpd36KcnmdM9C6T6QHeo3BdZv1z443uHmkVdPKHmxzL6b6lgg0rV1y 33ZJHXHvTGUr9HDdVkRKgDbp484jFsoOBZyuIOE6XRP2gE4xuhVASiN/WlKbR9ce OmUGEEab/smAlTZBDxi8rrIRxJYhoV6W5xc7W5db9bHlo= 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=VCSR/mvt7aprgK5yuwec2IwosT3ACiXU4tvs0l1eN6HkHdkejiQRRcrEfC624C WFKVXG0TB86Qro0D52W42wdGTJxvgtDg/rp65iYhCuPhLBPi3r+Zh7HJslQjI7qD F+vwmws+iOCSkoiR4mkiN0XSnpFpEs+fFjRKbKCrmfMww=; Received: (qmail 3550 invoked by alias); 18 Sep 2012 13:52:52 -0000 Received: (qmail 3516 invoked by uid 22791); 18 Sep 2012 13:52:36 -0000 X-SWARE-Spam-Status: No, hits=-6.1 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_CD, TW_CX 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; Tue, 18 Sep 2012 13:51:56 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q8IDpqTE026593 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 18 Sep 2012 09:51:53 -0400 Received: from localhost (ovpn-116-41.ams2.redhat.com [10.36.116.41]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q8IDpo4T012873 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 18 Sep 2012 09:51:52 -0400 Received: by localhost (Postfix, from userid 500) id 0EF1329C051; Tue, 18 Sep 2012 15:51:49 +0200 (CEST) From: Dodji Seketeli To: Jason Merrill Cc: "Joseph S. Myers" , Richard Henderson , GCC Patches Subject: Re: [PATCH] PR 53528 c++/ C++11 Generalized Attribute support References: <501312EF.9060405@redhat.com> <5027342D.8000207@redhat.com> <5035A398.6040701@redhat.com> <87pq5kfyrk.fsf@redhat.com> <50576D3E.8040505@redhat.com> X-URL: http://www.redhat.com Date: Tue, 18 Sep 2012 15:51:49 +0200 In-Reply-To: <50576D3E.8040505@redhat.com> (Jason Merrill's message of "Mon, 17 Sep 2012 14:34:38 -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 > Did you send me an old patch by mistake? Yes, sorry for that. I am replying here to the comments that apply to the new patch I should have sent, and I am sending you that new patch, hopefully appropriately amended. > > + found_attrs = true; > > You don't need a separate found_attrs variable; you can just check > whether attrs is set or not. VEC_iterate sets the element pointer to > NULL at the end of the vector. You should also be able to share more > of the code between the cases where you do or do not already have the > appropriate namespace set up. > Done. > > +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); > > + } > > Rather than write the code to search the table in two places, let's > call this function from register_scoped_attributes. > > You don't need to do another VEC_index since you already have the > pointer you want in 'iter'. Done. > > +attributes_array_length (const struct attribute_spec *attributes_array) > > Rather than calculate this first and then pass it to > register_scoped_attributes, why not just have > register_scoped_attributes stop at a null entry? Fixed. > > + if (name_space->attribute_hash == NULL) > > + name_space->attribute_hash = htab_create (200, hash_attr, eq_attr, NULL); > > Why do we need this both here and in find_attribute_namespace? I have removed it from find_attribute_namespace. > > } > > +/* > > + If in c++-11, check if the c++-11 alignment constraint with respect > > Need a blank line after the }. Fixed. Tested on x86_64-unknown-linux-gnu and powerpc64-unknown-linux-gnu. 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. * 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): 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 choose strictest alignment among many. Use new check_cxx_fundamental_alignment_constraints. (handle_unused_attribute): In c++11 attribute syntax, make this apply to decls only class definitions only. (handle_transparent_union_attribute): In c++11 attribute syntax, don't look through typedefs. 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, warn_misplaced_attr_for_class_type): Declare new functions. (check_tag_decl): Take an extra parameter for explicit instantiations. * decl.c (warn_misplaced_attr_for_class_type): Extract from ... (check_tag_decl): ... here. Add check for c++11 attributes being applied to an explicit instantiation. Take an extra parameter for explicit instantiations. (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 take an extra parameter for attributes. (cp_parser_block_declaration): Use cp_nth_tokens_can_be_std_attribute_p here. (cp_parser_decl_specifier_seq): Likewise. Forbid C++11 attributes in decl specifiers, unless it's at the very beginning of the declaration. Emit proper warning about misplaced c++11 attributes. (cp_parser_explicit_instantiation): Adjust call to check_tag_decl. (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, unless when calling cp_parser_label_for_labeled_statement. (cp_parser_label_for_labeled_statement): Take c++11 attributes in parameter. * 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-2-1.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-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-47-1.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. WIP address last review comments --- gcc/attribs.c | 216 +++++++++- gcc/c-family/c-common.c | 134 ++++++- gcc/c-family/c-common.h | 1 + gcc/cp/cp-tree.h | 21 +- gcc/cp/decl.c | 85 ++++- gcc/cp/decl2.c | 2 +- gcc/cp/error.c | 5 + gcc/cp/parser.c | 615 ++++++++++++++++++++++++--- gcc/cp/pt.c | 2 +- gcc/cp/typeck.c | 44 ++ 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.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-1.C | 3 + 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 | 30 ++ 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 | 4 + 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-1.C | 8 + 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 | 39 ++ 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 | 30 +- 71 files changed, 1872 insertions(+), 119 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.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-1.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-1.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.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..ed4c4a3 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); +DEF_VEC_ALLOC_O (attribute_spec, heap); + +/* Scoped attribute name representation. */ + +struct scoped_attributes +{ + const char *ns; + VEC (attribute_spec, heap) *attributes; + htab_t attribute_hash; +}; + +DEF_VEC_O (scoped_attributes); +DEF_VEC_ALLOC_O (scoped_attributes, heap); + +/* The table of scope attributes. */ +static VEC(scoped_attributes, heap) *attributes_table; + +static scoped_attributes* find_attribute_namespace (const char*); +static void register_scoped_attribute (const struct attribute_spec *, + scoped_attributes *); + static bool attributes_initialized = false; /* Default empty table of attributes. */ @@ -102,6 +121,65 @@ 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. This + array must be NULL terminated. NS is the name of attribute + namespace. The function returns the namespace into which the + attributes have been registered. */ + +scoped_attributes* +register_scoped_attributes (const struct attribute_spec * attributes, + const char* ns) +{ + scoped_attributes *result = NULL; + + /* See if we already have attributes in the namespace NS. */ + result = find_attribute_namespace (ns); + + if (result == NULL) + { + /* We don't have any namespace NS yet. Create one. */ + scoped_attributes sa; + + if (attributes_table == NULL) + attributes_table = VEC_alloc (scoped_attributes, heap, 64); + + memset (&sa, 0, sizeof (sa)); + sa.ns = ns; + sa.attributes = VEC_alloc (attribute_spec, heap, 64); + VEC_safe_push (scoped_attributes, heap, attributes_table, sa); + result = &VEC_last (scoped_attributes, attributes_table); + } + + /* Really add the attributes to their namespace now. */ + for (unsigned i = 0; attributes[i].name != NULL; ++i) + { + VEC_safe_push (attribute_spec, heap, + result->attributes, attributes[i]); + register_scoped_attribute (&attributes[i], result); + } + + gcc_assert (result != NULL); + + return result; +} + +/* Return the namespace which name is NS, NULL if none exist. */ + +static scoped_attributes* +find_attribute_namespace (const char* ns) +{ + unsigned ix; + scoped_attributes *iter; + + FOR_EACH_VEC_ELT (scoped_attributes, attributes_table, ix, iter) + if (ns == iter->ns + || (iter->ns != NULL + && ns != NULL + && !strcmp (iter->ns, ns))) + return iter; + return NULL; +} + /* Initialize attribute tables, and make some sanity checks if --enable-checking. */ @@ -109,7 +187,6 @@ void init_attributes (void) { size_t i; - int k; if (attributes_initialized) return; @@ -181,12 +258,10 @@ 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], "gnu"); + invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL); attributes_initialized = true; } @@ -196,9 +271,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 *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 +295,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 *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 +350,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 +409,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 +422,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 +522,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 +610,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 6de2f1c..fa513a8 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 }, @@ -6588,6 +6589,18 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), } else { + if ((flags & ATTR_FLAG_CXX11) + && !(flags & ATTR_FLAG_TYPE_IN_PLACE + && (TREE_CODE (*node) == RECORD_TYPE + || TREE_CODE (*node) == UNION_TYPE))) + { + /* unused is being used as a c++11 attribute. In this mode + we prevent it from applying to types, unless it's for a + class defintion. */ + warning (OPT_Wattributes, + "attribute %qE cannot be applied to a non-class type", name); + return NULL_TREE; + } if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) *node = build_variant_type_copy (*node); TREE_USED (*node) = 1; @@ -6665,7 +6678,9 @@ handle_transparent_union_attribute (tree *node, tree name, *no_add_attrs = true; - if (TREE_CODE (*node) == TYPE_DECL) + + if (TREE_CODE (*node) == TYPE_DECL + && ! (flags & ATTR_FLAG_CXX11)) node = &TREE_TYPE (*node); type = *node; @@ -7137,6 +7152,90 @@ 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; + unsigned requested_alignment = 1U << align_log; + unsigned max_align = 0; + + if ((!(flags & ATTR_FLAG_CXX11) && !warn_cxx_compat) + || (node == NULL_TREE || node == error_mark_node)) + return true; + + if (cxx_fundamental_alignment_p (requested_alignment)) + 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 (requested_alignment > (max_align = 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. */ + max_align = MAX_TARGET_FIELD_ALIGNMENT; + if (TREE_CODE (node) == FIELD_DECL + && requested_alignment > (max_align = 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 + && requested_alignment > (max_align = MAX_STACK_ALIGNMENT)) + alignment_too_large_p = true; + } + } + else if (TYPE_P (node)) + { + /* Let's be liberal for types. */ + if (requested_alignment > (max_align = BIGGEST_ALIGNMENT)) + alignment_too_large_p = true; + } + + if (alignment_too_large_p) + { + error ("requested alignment %d is larger than %d", + requested_alignment, max_align); + } + + return !alignment_too_large_p; +} + /* Handle a "aligned" attribute; arguments as in struct attribute_spec.handler. */ @@ -7160,7 +7259,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) { @@ -7190,6 +7290,17 @@ 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 (DECL_USER_ALIGN (decl) + && 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. + + This formally comes from the c++11 specification but we are + doing it for the GNU attribute syntax as well. */ + *no_add_attrs = true; else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ALIGN (decl) > (1U << i) * BITS_PER_UNIT) { @@ -11154,4 +11265,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(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 9298e3d..87c1da8 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -790,6 +790,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 ded247d..f120d0b 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. */ @@ -4668,6 +4670,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. */ @@ -4686,6 +4689,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; @@ -4754,8 +4759,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; @@ -5052,7 +5063,9 @@ extern tree build_cp_library_fn_ptr (const char *, tree); extern tree push_library_fn (tree, tree, tree); extern tree push_void_library_fn (tree, tree); extern tree push_throw_library_fn (tree, tree); -extern tree check_tag_decl (cp_decl_specifier_seq *); +extern void warn_misplaced_attr_for_class_type (source_location location, + tree class_type); +extern tree check_tag_decl (cp_decl_specifier_seq *, bool); extern tree shadow_tag (cp_decl_specifier_seq *); extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *, bool); extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, tree *); @@ -5394,6 +5407,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); @@ -5812,6 +5826,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 6b5b986..ecc8970 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4125,13 +4125,32 @@ fixup_anonymous_aggr (tree t) } } +/* Warn for an attribute located at LOCATION that appertains to the + class type CLASS_TYPE that has not been properly placed after its + class-key, in it class-specifier. */ + +void +warn_misplaced_attr_for_class_type (source_location location, + tree class_type) +{ + gcc_assert (TAGGED_TYPE_P (class_type)); + + warning_at (location, OPT_Wattributes, + "attribute ignored in declaration " + "of %q#T", class_type); + inform (location, + "attribute for %q#T must follow the %qs keyword", + class_type, class_key_or_enum_as_string (class_type)); +} + /* Make sure that a declaration with no declarator is well-formed, i.e. just declares a tagged type or anonymous union. Returns the type declared; or NULL_TREE if none. */ tree -check_tag_decl (cp_decl_specifier_seq *declspecs) +check_tag_decl (cp_decl_specifier_seq *declspecs, + bool explicit_type_instantiation_p) { int saw_friend = decl_spec_seq_has_spec_p (declspecs, ds_friend); int saw_typedef = decl_spec_seq_has_spec_p (declspecs, ds_typedef); @@ -4240,10 +4259,22 @@ 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 (explicit_type_instantiation_p) + /* [dcl.attr.grammar]/4: + + No attribute-specifier-seq shall appertain to an explicit + instantiation. */ + { + warning_at (loc, OPT_Wattributes, + "attribute ignored in explicit instantiation %q#T", + declared_type); + inform (loc, + "no attribute can be applied to " + "an explicit instantiation"); + } + else + warn_misplaced_attr_for_class_type (loc, declared_type); } return declared_type; @@ -4265,7 +4296,8 @@ check_tag_decl (cp_decl_specifier_seq *declspecs) tree shadow_tag (cp_decl_specifier_seq *declspecs) { - tree t = check_tag_decl (declspecs); + tree t = check_tag_decl (declspecs, + /*explicit_type_instantiation_p=*/false); if (!t) return NULL_TREE; @@ -9124,6 +9156,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) @@ -9161,6 +9202,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: @@ -9357,6 +9405,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; @@ -9519,6 +9574,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; @@ -9644,6 +9710,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 0df4613..065c436 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 30fa018..3dd37aa 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -3372,6 +3372,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 e8c0378..886f54e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1231,6 +1231,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; @@ -1853,7 +1854,7 @@ static void cp_parser_lambda_body static void cp_parser_statement (cp_parser *, tree, bool, bool *); static void cp_parser_label_for_labeled_statement - (cp_parser *); +(cp_parser *, tree); static tree cp_parser_expression_statement (cp_parser *, tree); static tree cp_parser_compound_statement @@ -1957,7 +1958,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 @@ -2099,9 +2100,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 *); @@ -5605,6 +5626,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, @@ -6849,13 +6877,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)) { @@ -6864,8 +6892,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. */ @@ -8604,6 +8635,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: @@ -8620,15 +8663,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. */ @@ -8646,7 +8694,7 @@ 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. */ - cp_parser_label_for_labeled_statement (parser); + cp_parser_label_for_labeled_statement (parser, std_attrs); goto restart; case RID_IF: @@ -8709,7 +8757,8 @@ 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. */ - cp_parser_label_for_labeled_statement (parser); + + cp_parser_label_for_labeled_statement (parser, std_attrs); goto restart; } } @@ -8745,6 +8794,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); @@ -8759,6 +8816,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. @@ -8775,7 +8839,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, have to return the label. */ static void -cp_parser_label_for_labeled_statement (cp_parser* parser) +cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) { cp_token *token; tree label = NULL_TREE; @@ -8855,21 +8919,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; } @@ -10295,8 +10361,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 @@ -10526,6 +10591,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 @@ -10560,6 +10626,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; @@ -10573,7 +10640,6 @@ cp_parser_decl_specifier_seq (cp_parser* parser, while (true) { bool constructor_p; - bool found_decl_spec; cp_token *token; ds = ds_last; @@ -10585,12 +10651,55 @@ 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. In that case + [dcl.spec]/1 says: + + The attribute-specifier-seq affects the type only for + the declaration it appears in, not other declarations + involving the same type. + + But for now let's force the user to position the + attribute either at the beginning of the declaration or + after the declarator-id, which would clearly mean that it + applies to the declarator. */ + 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 + { + if (decl_specs->type && CLASS_TYPE_P (decl_specs->type)) + { + /* This is an attribute following a + class-specifier. */ + if (decl_specs->type_definition_p) + warn_misplaced_attr_for_class_type (token->location, + decl_specs->type); + } + else + { + warning_at (token->location, OPT_Wattributes, + "attribute ignored"); + inform (token->location, + "an attribute for a declaration should be either " + "at the begining of the declaration or after " + "the declarator-id"); + } + attrs = NULL_TREE; + } + } + + decl_specs->attributes + = chainon (decl_specs->attributes, + attrs); if (decl_specs->locations[ds_attribute] == 0) decl_specs->locations[ds_attribute] = token->location; continue; @@ -11317,13 +11426,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)) { @@ -11332,8 +11442,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; @@ -13161,7 +13274,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) { tree type; - type = check_tag_decl (&decl_specifiers); + type = check_tag_decl (&decl_specifiers, + /*explicit_type_instantiation_p=*/true); /* Turn access control back on for names used during template instantiation. */ pop_deferring_access_checks (); @@ -14592,7 +14706,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, @@ -15494,7 +15608,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; @@ -15560,22 +15674,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); @@ -15904,7 +16016,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. */ @@ -15912,14 +16024,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)) { @@ -15946,6 +16060,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 @@ -15958,9 +16081,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; } @@ -16100,6 +16222,7 @@ cp_parser_direct_declarator (cp_parser* parser, cp_virt_specifiers virt_specifiers; tree exception_specification; tree late_return; + tree attrs; is_declarator = true; @@ -16113,6 +16236,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)); @@ -16126,6 +16251,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. */ @@ -16175,10 +16301,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; @@ -16231,13 +16358,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; @@ -16304,6 +16434,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) { @@ -16418,6 +16550,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; @@ -16465,9 +16598,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: @@ -16487,10 +16622,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; @@ -16521,6 +16658,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 { @@ -16558,6 +16699,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); } @@ -16917,7 +17062,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, @@ -18023,7 +18168,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) @@ -18044,6 +18189,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: @@ -18894,8 +19045,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)) @@ -18927,7 +19076,8 @@ cp_parser_member_declaration (cp_parser* parser) friend_p = cp_parser_friend_p (&decl_specifiers); /* If there were decl-specifiers, check to see if there was a class-declaration. */ - type = check_tag_decl (&decl_specifiers); + type = check_tag_decl (&decl_specifiers, + /*explicit_type_instantiation_p=*/false); /* Nested classes have already been added to the class, but a `friend' needs to be explicitly registered. */ if (friend_p) @@ -18994,6 +19144,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); @@ -20100,6 +20256,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: @@ -20108,10 +20339,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; @@ -20137,7 +20368,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. */ @@ -20158,7 +20389,7 @@ cp_parser_attributes_opt (cp_parser* parser) return attributes; } -/* Parse an attribute-list. +/* Parse a GNU attribute-list. attribute-list: attribute @@ -20176,7 +20407,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; @@ -20255,6 +20486,276 @@ 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 = NULL_TREE, 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 if (token->flags & NAMED_OP) + attr_id = get_identifier (cpp_type2name (token->type, token->flags)); + + if (attr_id == NULL_TREE) + 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 clause 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; + + /* 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, tf_warning_or_error); + 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 16952bf..bf1fdb1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5020,7 +5020,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 ad4b090..b0d2036 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1701,6 +1701,50 @@ 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 (TYPE_P (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 = fold_non_dependent_expr_sfinae (e, complain); + 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..c514e67 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 *, + 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.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..4adefdb --- /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..636f9a9 --- /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 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..566461b0 --- /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 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-1.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2-1.C new file mode 100644 index 0000000..2f47b32 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-2-1.C @@ -0,0 +1,3 @@ +// { dg-do compile { target c++11 } } + +struct [[gnu::unused]] A {}; 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