From patchwork Thu Jul 26 15:19:25 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dodji Seketeli X-Patchwork-Id: 173457 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 864572C0086 for ; Fri, 27 Jul 2012 01:20:34 +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=1343920836; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Cc:Subject:Date: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=Qt2bDt13tOqSY9P0aBMUSc8utFQ=; b=O8/+EcJ/c9m+/zI 8n6OD8nYlMD81YVViPPJmAgBwpJH6cTR6ky5RapTbBSYyIc3fe0VgJop7UWhTEgn so8HYUAG4qXa2e9o5r0mIcWD3ytXb2VAnkJSb9lnY2EYIl2t5uk/bRm+PT4ovJ+J QLKpwyri+YUsipSVCI+695DCWeLI= 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:X-URL:Date: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=CaGahiyC2FdgRHpLSmzOYv7tMxYTtpdLKsVCmePSZ9jRwJhgB40SwxInSBWehX +MI70UUOwqND4aqqwEpzxfkyPaCab2ap4SiTn/nAA8MzkoEa0eVcatfYl8YZDMk1 GdbqLkm57usoXVVZ/L3XUI2edAizeqLI5vvofpUauS1to=; Received: (qmail 12093 invoked by alias); 26 Jul 2012 15:20:29 -0000 Received: (qmail 12043 invoked by uid 22791); 26 Jul 2012 15:20:18 -0000 X-SWARE-Spam-Status: No, hits=-5.8 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, SPF_HELO_PASS, TW_CP, 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; Thu, 26 Jul 2012 15:19:28 +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 q6QFJRPv026513 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 26 Jul 2012 11:19:28 -0400 Received: from localhost (ovpn-116-58.ams2.redhat.com [10.36.116.58]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q6QFJP8U018793 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 26 Jul 2012 11:19:27 -0400 Received: by localhost (Postfix, from userid 500) id 37B3C29C04D; Thu, 26 Jul 2012 17:19:25 +0200 (CEST) From: Dodji Seketeli To: GCC Patches Cc: Jason Merrill Subject: [PATCH] PR 53528 c++/ C++11 Generalized Attribute support X-URL: http://www.redhat.com Date: Thu, 26 Jul 2012 17:19:25 +0200 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, This patch implements the c++-11 generalized attributes, described in the N2761 paper[1]. The idea is to modify the front-end to accept the new attribute syntax (including alignas expressions) and to build an internal representation similar to the one we already have for GNU attributes. This lets us re-use our existing GNU attribute mechanisms to support the generalized c++11 attributes. The patch does change the existing internal representation to support scoped attribute (aka attributes with namespaces), which is a concept that doesn't exist in GNU attributes. I have thus put all existing GNU extension attributes into the "gnu" namespace. For instance, in C++-11, the "unused" attribute would be represented as "[[gnu::unused]]". Because there is no syntax for scoped attributes in C, writting "__attribute__((unused))" unconditionnally refers to the "unused" attribute in the "gnu" namespace. Tested on x86_64-unknown-linux-gnu and powerpc64-unknown-linux-gnu. [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf 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. * 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 (attribute_hash): Remove global variable. (attributes_table): New global variable. (set_attributes_namespace, find_attribute_namespace) (register_scoped_attribute, attributes_array_length): New static functions. (register_scoped_attributes, lookup_scoped_attribute_spec) (cxx_11_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_CXX_11 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_GENERALIZED_ATTRIBUTES): New member. (cxx_alignas_expr): Declare new functions * 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, cp_parser_decl_specifier_seq): Use cp_nth_tokens_can_be_std_attribute_p here. (cp_parser_init_declarator): Parsing attributes here is no more a GNU extension in c++-11. (cp_parser_direct_declarator, cp_parser_type_specifier_seq): Use cp_next_tokens_can_be_attribute_p. * semantics.c (potential_constant_expression_1): Likewise. * typeck.c (fundamental_alignment_p, cxx_alignas_expr): New public functions. 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-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-37.C: Likewise. * g++.dg/cpp0x/gen-attrs-38.C: Likewise. * g++.dg/cpp0x/gen-attrs-39.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. --- gcc/attribs.c | 291 +++++++++++++++++-- gcc/c-family/c-common.c | 108 +++++++- gcc/c-family/c-common.h | 1 + gcc/cp/cp-tree.h | 5 +- gcc/cp/decl2.c | 2 +- gcc/cp/error.c | 5 + gcc/cp/parser.c | 413 +++++++++++++++++++++++++-- gcc/cp/typeck.c | 60 ++++ 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.C | 11 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-20.C | 22 ++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-21.C | 18 ++ 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 | 8 + 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.C | 21 ++ 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.C | 10 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-4.C | 32 ++ 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 | 4 + 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-6.C | 20 ++ gcc/testsuite/g++.dg/cpp0x/gen-attrs-7.C | 4 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-8.C | 11 + gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C | 12 + gcc/tree.c | 34 ++-- gcc/tree.h | 13 +- 63 files changed, 1576 insertions(+), 64 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.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.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.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-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..f75d4ee 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,30 @@ struct substring int length; }; +/* Scoped attribute name representation. */ + +struct scoped_attributes +{ + const char *ns; + unsigned len; + struct attribute_spec *attributes; + htab_t attribute_hash; +}; + +struct scoped_attributes_table +{ + unsigned len; + struct scoped_attributes *scoped; +}; + +/* The table of scope attributes. */ +static struct scoped_attributes_table *attributes_table; + +static struct scoped_attributes* set_attributes_namespace (const struct attribute_spec *, + unsigned, const char*); +static struct scoped_attributes* find_attribute_namespace (const char*); +static void register_scoped_attribute (const struct attribute_spec *, + struct scoped_attributes *); static bool attributes_initialized = false; /* Default empty table of attributes. */ @@ -102,6 +123,116 @@ eq_attr (const void *p, const void *q) return (!strncmp (spec->name, str->str, str->length) && !spec->name[str->length]); } +/* Set attributes ATTRIBUTES into the namespace NS. */ + +static struct scoped_attributes* +set_attributes_namespace (const struct attribute_spec * attributes, + unsigned attributes_length, + const char* ns) +{ + unsigned i; + struct scoped_attributes *iter = NULL; + bool found_attrs = false; + + /* See if we already have attributes in the namespace NS. */ + for (i = 0; attributes_table != NULL && i < attributes_table->len; ++i) + { + iter = &attributes_table->scoped[i]; + if (strcmp (iter->ns, ns) == 0) + { + found_attrs = true; + break; + } + } + + if (found_attrs) + { + /* We already have attributes in the namespace NS. Add + ATTRIBUTES to that namespace. */ + + unsigned j; + + gcc_assert (strcmp (iter->ns, ns) == 0); + + iter->attributes = XRESIZEVEC (struct attribute_spec, + iter->attributes, + iter->len + attributes_length); + + for (i = iter->len, j = 0; + i < iter->len + attributes_length; + ++i, ++j) + memcpy (&iter->attributes[i], &attributes[j], + sizeof (struct attribute_spec)); + iter->len += attributes_length; + } + else + { + /* We don't have any namespace NS yet. Create one and add + ATTRIBUTES into it. */ + + if (attributes_table == NULL) + attributes_table = XCNEW (struct scoped_attributes_table); + + attributes_table->scoped = XRESIZEVEC (struct scoped_attributes, + attributes_table->scoped, + attributes_table->len + 1); + iter = &attributes_table->scoped[attributes_table->len]; + memset (iter, 0, sizeof (struct scoped_attributes)); + iter->ns = ns; + iter->len = attributes_length; + iter->attributes = XCNEWVEC (struct attribute_spec, + attributes_length); + memcpy (iter->attributes, + attributes, + attributes_length * sizeof (struct attribute_spec)); + attributes_table->len++; + } + + return iter; +} + +/* Return the namespace which name is NS, NULL if none exist. */ + +static struct scoped_attributes* +find_attribute_namespace (const char* ns) +{ + unsigned i; + struct scoped_attributes * attrs = NULL; + + for (i = 0; i < attributes_table->len; ++i) + if (ns == attributes_table->scoped->ns + || (attributes_table->scoped->ns != NULL + && ns != NULL + && !strcmp (attributes_table->scoped[i].ns, ns))) + { + attrs = &attributes_table->scoped[i]; + break; + } + + if (attrs != NULL && attrs->attribute_hash == 0) + attrs->attribute_hash = + htab_create (200, hash_attr, eq_attr, NULL); + + return attrs; +} + +/* 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 +240,6 @@ void init_attributes (void) { size_t i; - int k; if (attributes_initialized) return; @@ -181,12 +311,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 +326,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, + struct 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 +350,68 @@ 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. */ +/* Insert an array of attributes ATTRS into a namespace. ATTRS_LEN is + the length of the ATTRS array. NAME_SPACE is the name of attribute + namespace. The function returns the namespace into which the + attributes have been registered. */ + +struct scoped_attributes* +register_scoped_attributes (const struct attribute_spec *attrs, + unsigned attrs_len, + const char *name_space) +{ + unsigned i; + 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); + + return ns; +} + +/* 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; + struct 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, @@ -302,10 +487,11 @@ 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 +499,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 || !cxx_11_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 +599,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 cxx_11_flag = + cxx_11_attribute_p (a) ? ATTR_FLAG_CXX_11 : 0; + + returned_attrs = chainon ((*spec->handler) (anode, name, args, + flags|cxx_11_flag, + &no_add_attrs), + returned_attrs); + } /* Layout the decl in case anything changed. */ if (spec->type_required && DECL_P (*node) @@ -488,6 +687,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 + generalized attribute. + + When G++ parses a C++11 generalized 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 +cxx_11_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 generalized (scoped) attributes. + + Please read the comments of cxx_11_attribute_p to understand the + format of attributes. */ + +tree +get_attribute_name (const_tree attr) +{ + if (cxx_11_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 generalized (scoped) attributes. On GNU attributes, + it returns an identifier tree for the string "gnu". + + Please read the comments of cxx_11_attribute_p to understand the + format of attributes. */ + +tree +get_attribute_namespace (const_tree attr) +{ + if (cxx_11_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 b72506b..e7bbf95 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 }, @@ -6990,6 +6991,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_CXX_11) + || (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 + && (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. */ @@ -7014,7 +7093,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) { @@ -7044,6 +7124,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_CXX_11 + && 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) { @@ -11008,4 +11095,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 3c1a7bf..7ac3844 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, + /* Generalized attributes */ + CPP0X_GENERALIZED_ATTRIBUTES } cpp0x_warn_str; /* The various kinds of operation used by composite_pointer_type. */ @@ -5816,6 +5818,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/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..b6b1bc9 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_GENERALIZED_ATTRIBUTES: + pedwarn (input_location, 0, + "generalized 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 70d6dac..51e3e2e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2103,9 +2103,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 +5629,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, @@ -8859,7 +8886,7 @@ 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; @@ -10299,8 +10326,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 @@ -10589,7 +10615,7 @@ 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 @@ -15498,7 +15524,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 +15590,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); @@ -16179,7 +16203,8 @@ 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; @@ -16921,7 +16946,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, @@ -20104,6 +20129,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 +20212,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 +20241,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 +20262,7 @@ cp_parser_attributes_opt (cp_parser* parser) return attributes; } -/* Parse an attribute-list. +/* Parse a GNU attribute-list. attribute-list: attribute @@ -20180,7 +20280,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 +20359,275 @@ cp_parser_attribute_list (cp_parser* parser) return nreverse (attribute_list); } +/* Parse a standard C++11 generalized 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 generalized + 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_GENERALIZED_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) == NULL + || cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE) == NULL) + 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_GENERALIZED_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/typeck.c b/gcc/cp/typeck.c index d7a719f..da5c76b 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1701,6 +1701,66 @@ 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 : cxx_constant_value (e); + 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..e43171d --- /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 *, ...); 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..23a5b37 --- /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..8d9027e --- /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 (__const char *__s, int __c) throw () [[gnu::__pure__]]; +extern char *rindex (__const char *__s, int __c) throw () [[gnu::__pure__]]; 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