This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/43407 (scoped enum attributes)
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 21 Jan 2016 15:22:14 -0500
- Subject: C++ PATCH for c++/43407 (scoped enum attributes)
- Authentication-results: sourceware.org; auth=none
We were complaining about attributes on C++11 scoped enums because
start_enum gives them an underlying type, and thereby a TYPE_SIZE,
immediately. Fixed by passing early attributes to start_enum.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 2a974c0078f1f7b39e7b4ef94fee8836faf5aa95
Author: Jason Merrill <jason@redhat.com>
Date: Tue Jan 19 17:29:04 2016 -0500
PR c++/43407
* decl.c (start_enum): Add attributes parameter.
* parser.c (cp_parser_enum_specifier): Pass it.
* pt.c (lookup_template_class_1): Pass it.
* cp-tree.h: Adjust.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 51589c3..0aeee57 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5788,7 +5788,7 @@ extern bool grok_op_properties (tree, bool);
extern tree xref_tag (enum tag_types, tree, tag_scope, bool);
extern tree xref_tag_from_type (tree, tree, tag_scope);
extern bool xref_basetypes (tree, tree);
-extern tree start_enum (tree, tree, tree, bool, bool *);
+extern tree start_enum (tree, tree, tree, tree, bool, bool *);
extern void finish_enum_value_list (tree);
extern void finish_enum (tree);
extern void build_enumerator (tree, tree, tree, tree, location_t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ceeef60..d995654 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13045,6 +13045,8 @@ copy_type_enum (tree dst, tree src)
the enumeration type. This should be NULL_TREE if no storage type
was specified.
+ ATTRIBUTES are any attributes specified after the enum-key.
+
SCOPED_ENUM_P is true if this is a scoped enumeration type.
if IS_NEW is not NULL, gets TRUE iff a new type is created.
@@ -13055,7 +13057,7 @@ copy_type_enum (tree dst, tree src)
tree
start_enum (tree name, tree enumtype, tree underlying_type,
- bool scoped_enum_p, bool *is_new)
+ tree attributes, bool scoped_enum_p, bool *is_new)
{
tree prevtype = NULL_TREE;
gcc_assert (identifier_p (name));
@@ -13163,6 +13165,8 @@ start_enum (tree name, tree enumtype, tree underlying_type,
SET_SCOPED_ENUM_P (enumtype, scoped_enum_p);
+ cplus_decl_attributes (&enumtype, attributes, (int)ATTR_FLAG_TYPE_IN_PLACE);
+
if (underlying_type)
{
if (CP_INTEGRAL_TYPE_P (underlying_type))
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8dd7e49..33f1df3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -17132,7 +17132,7 @@ cp_parser_enum_specifier (cp_parser* parser)
brace so the enum will be recorded as being on the line of its
tag (or the 'enum' keyword, if there is no tag). */
type = start_enum (identifier, type, underlying_type,
- scoped_enum_p, &is_new_type);
+ attributes, scoped_enum_p, &is_new_type);
/* If the next token is not '{' it is an opaque-enum-specifier or an
elaborated-type-specifier. */
@@ -17248,7 +17248,6 @@ cp_parser_enum_specifier (cp_parser* parser)
if (cp_parser_allow_gnu_extensions_p (parser))
{
tree trailing_attr = cp_parser_gnu_attributes_opt (parser);
- trailing_attr = chainon (trailing_attr, attributes);
cplus_decl_attributes (&type,
trailing_attr,
(int) ATTR_FLAG_TYPE_IN_PLACE);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ae60f1c..7985198 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -214,6 +214,7 @@ static tree listify_autos (tree, tree);
static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
static bool complex_alias_template_p (const_tree tmpl);
+static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
@@ -8398,6 +8399,8 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
t = start_enum (TYPE_IDENTIFIER (template_type), NULL_TREE,
tsubst (ENUM_UNDERLYING_TYPE (template_type),
arglist, complain, in_decl),
+ tsubst_attributes (TYPE_ATTRIBUTES (template_type),
+ arglist, complain, in_decl),
SCOPED_ENUM_P (template_type), NULL);
if (t == error_mark_node)
@@ -9540,6 +9543,109 @@ can_complete_type_without_circularity (tree type)
static tree tsubst_omp_clauses (tree, bool, bool, tree, tsubst_flags_t, tree);
+/* Instantiate a single dependent attribute T (a TREE_LIST), and return either
+ T or a new TREE_LIST, possibly a chain in the case of a pack expansion. */
+
+static tree
+tsubst_attribute (tree t, tree *decl_p, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ gcc_assert (ATTR_IS_DEPENDENT (t));
+
+ tree val = TREE_VALUE (t);
+ if (val == NULL_TREE)
+ /* Nothing to do. */;
+ else if ((flag_openmp || flag_openmp_simd || flag_cilkplus)
+ && is_attribute_p ("omp declare simd",
+ get_attribute_name (t)))
+ {
+ tree clauses = TREE_VALUE (val);
+ clauses = tsubst_omp_clauses (clauses, true, false, args,
+ complain, in_decl);
+ c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
+ clauses = finish_omp_clauses (clauses, false, true);
+ tree parms = DECL_ARGUMENTS (*decl_p);
+ clauses
+ = c_omp_declare_simd_clauses_to_numbers (parms, clauses);
+ if (clauses)
+ val = build_tree_list (NULL_TREE, clauses);
+ else
+ val = NULL_TREE;
+ }
+ /* If the first attribute argument is an identifier, don't
+ pass it through tsubst. Attributes like mode, format,
+ cleanup and several target specific attributes expect it
+ unmodified. */
+ else if (attribute_takes_identifier_p (get_attribute_name (t)))
+ {
+ tree chain
+ = tsubst_expr (TREE_CHAIN (val), args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+ if (chain != TREE_CHAIN (val))
+ val = tree_cons (NULL_TREE, TREE_VALUE (val), chain);
+ }
+ else if (PACK_EXPANSION_P (val))
+ {
+ /* An attribute pack expansion. */
+ tree purp = TREE_PURPOSE (t);
+ tree pack = tsubst_pack_expansion (val, args, complain, in_decl);
+ int len = TREE_VEC_LENGTH (pack);
+ tree list = NULL_TREE;
+ tree *q = &list;
+ for (int i = 0; i < len; ++i)
+ {
+ tree elt = TREE_VEC_ELT (pack, i);
+ *q = build_tree_list (purp, elt);
+ q = &TREE_CHAIN (*q);
+ }
+ return list;
+ }
+ else
+ val = tsubst_expr (val, args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+
+ if (val != TREE_VALUE (t))
+ return build_tree_list (TREE_PURPOSE (t), val);
+ return t;
+}
+
+/* Instantiate any dependent attributes in ATTRIBUTES, returning either it
+ unchanged or a new TREE_LIST chain. */
+
+static tree
+tsubst_attributes (tree attributes, tree args,
+ tsubst_flags_t complain, tree in_decl)
+{
+ tree last_dep = NULL_TREE;
+
+ for (tree t = attributes; t; t = TREE_CHAIN (t))
+ if (ATTR_IS_DEPENDENT (t))
+ {
+ last_dep = t;
+ attributes = copy_list (attributes);
+ break;
+ }
+
+ if (last_dep)
+ for (tree *p = &attributes; *p; p = &TREE_CHAIN (*p))
+ {
+ tree t = *p;
+ if (ATTR_IS_DEPENDENT (t))
+ {
+ tree subst = tsubst_attribute (t, NULL, args, complain, in_decl);
+ if (subst == t)
+ continue;
+ *p = subst;
+ do
+ p = &TREE_CHAIN (*p);
+ while (*p);
+ *p = TREE_CHAIN (t);
+ }
+ }
+
+ return attributes;
+}
+
/* Apply any attributes which had to be deferred until instantiation
time. DECL_P, ATTRIBUTES and ATTR_FLAGS are as cplus_decl_attributes;
ARGS, COMPLAIN, IN_DECL are as tsubst. */
@@ -9581,61 +9687,10 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags,
{
*p = TREE_CHAIN (t);
TREE_CHAIN (t) = NULL_TREE;
- if ((flag_openmp || flag_openmp_simd || flag_cilkplus)
- && is_attribute_p ("omp declare simd",
- get_attribute_name (t))
- && TREE_VALUE (t))
- {
- tree clauses = TREE_VALUE (TREE_VALUE (t));
- clauses = tsubst_omp_clauses (clauses, true, false, args,
- complain, in_decl);
- c_omp_declare_simd_clauses_to_decls (*decl_p, clauses);
- clauses = finish_omp_clauses (clauses, false, true);
- tree parms = DECL_ARGUMENTS (*decl_p);
- clauses
- = c_omp_declare_simd_clauses_to_numbers (parms, clauses);
- if (clauses)
- TREE_VALUE (TREE_VALUE (t)) = clauses;
- else
- TREE_VALUE (t) = NULL_TREE;
- }
- /* If the first attribute argument is an identifier, don't
- pass it through tsubst. Attributes like mode, format,
- cleanup and several target specific attributes expect it
- unmodified. */
- else if (attribute_takes_identifier_p (get_attribute_name (t))
- && TREE_VALUE (t))
- {
- tree chain
- = tsubst_expr (TREE_CHAIN (TREE_VALUE (t)), args, complain,
- in_decl,
- /*integral_constant_expression_p=*/false);
- if (chain != TREE_CHAIN (TREE_VALUE (t)))
- TREE_VALUE (t)
- = tree_cons (NULL_TREE, TREE_VALUE (TREE_VALUE (t)),
- chain);
- }
- else if (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t)))
- {
- /* An attribute pack expansion. */
- tree purp = TREE_PURPOSE (t);
- tree pack = (tsubst_pack_expansion
- (TREE_VALUE (t), args, complain, in_decl));
- int len = TREE_VEC_LENGTH (pack);
- for (int i = 0; i < len; ++i)
- {
- tree elt = TREE_VEC_ELT (pack, i);
- *q = build_tree_list (purp, elt);
- q = &TREE_CHAIN (*q);
- }
- continue;
- }
- else
- TREE_VALUE (t)
- = tsubst_expr (TREE_VALUE (t), args, complain, in_decl,
- /*integral_constant_expression_p=*/false);
- *q = t;
- q = &TREE_CHAIN (t);
+ *q = tsubst_attribute (t, decl_p, args, complain, in_decl);
+ do
+ q = &TREE_CHAIN (*q);
+ while (*q);
}
else
p = &TREE_CHAIN (t);
diff --git a/gcc/testsuite/g++.dg/abi/abi-tag15.C b/gcc/testsuite/g++.dg/abi/abi-tag15.C
index bfda3a2..cf9e32f 100644
--- a/gcc/testsuite/g++.dg/abi/abi-tag15.C
+++ b/gcc/testsuite/g++.dg/abi/abi-tag15.C
@@ -1,3 +1,3 @@
// PR c++/66748
-enum __attribute__((abi_tag("foo"))) E {}; // { dg-error "redeclaration of" }
+enum __attribute__((abi_tag("foo"))) E {};
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum31.C b/gcc/testsuite/g++.dg/cpp0x/enum31.C
new file mode 100644
index 0000000..62d65b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum31.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+
+enum class __attribute__((__visibility__("default"))) Foobar
+{
+ fratz,
+ nabble
+};