summaryrefslogtreecommitdiffstats
path: root/gcc/attribs.c
diff options
context:
space:
mode:
authordodji <dodji@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-08 09:29:05 +0000
committerdodji <dodji@138bc75d-0d04-0410-961f-82ee72b054a4>2012-10-08 09:29:05 +0000
commitffcdbf9cfa1e6df483fc5aa5885eb3121cd60638 (patch)
tree1a1442f932577112e42d0c3a2bb905d3ce01d5de /gcc/attribs.c
parent1d5c6f91c7cbd950ceee380e3711b4bcb067a552 (diff)
downloadppe42-gcc-ffcdbf9cfa1e6df483fc5aa5885eb3121cd60638.tar.gz
ppe42-gcc-ffcdbf9cfa1e6df483fc5aa5885eb3121cd60638.zip
PR c++/53528 C++11 attribute support
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. Note that this patch follows a conservative understanding of the specification by disallowing attributes appertaining to types, unless they apply to a type definition. 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. (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. Forbid c++11 attributes appertaining to type-specifiers. (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_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. (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 appertains 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. Store C++11 attributes that appears in in decl specifiers in cp_decl_specifier_seq::std_attributes. declaration. Emit proper warning about misplaced c++11 attributes for class type. (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 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. (make_pointer_declarator, make_reference_declarator) (make_ptrmem_declarator, cp_parser_make_indirect_declarator): Take attributes that appertain to the pointer/reference in argument. (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. 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. 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192199 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/attribs.c')
-rw-r--r--gcc/attribs.c229
1 files changed, 207 insertions, 22 deletions
diff --git a/gcc/attribs.c b/gcc/attribs.c
index d3af4141f4e..b330f27d89d 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,64 @@ 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);
+ result = VEC_safe_push (scoped_attributes, heap, attributes_table, sa);
+ }
+
+ /* 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 +186,6 @@ void
init_attributes (void)
{
size_t i;
- int k;
if (attributes_initialized)
return;
@@ -181,12 +257,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 +270,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 +294,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 +349,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 +408,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 +421,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
@@ -327,6 +442,20 @@ decl_attributes (tree *node, tree attributes, int flags)
}
gcc_assert (is_attribute_p (spec->name, name));
+ if (TYPE_P (*node)
+ && cxx11_attribute_p (a)
+ && !(flags & ATTR_FLAG_TYPE_IN_PLACE))
+ {
+ /* This is a c++11 attribute that appertains to a
+ type-specifier, outside of the definition of, a class
+ type. Ignore it. */
+ warning (OPT_Wattributes, "attribute ignored");
+ inform (input_location,
+ "an attribute that appertains to a type-specifier "
+ "is ignored");
+ continue;
+ }
+
if (spec->decl_required && !DECL_P (*anode))
{
if (flags & ((int) ATTR_FLAG_DECL_NEXT
@@ -406,9 +535,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 +623,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. */
OpenPOWER on IntegriCloud