This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C/C++ PATCH to allow deprecating enum values (PR c/47043)
- From: Marek Polacek <polacek at redhat dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Joseph Myers <joseph at codesourcery dot com>, Jason Merrill <jason at redhat dot com>
- Date: Wed, 6 May 2015 17:48:37 +0200
- Subject: C/C++ PATCH to allow deprecating enum values (PR c/47043)
- Authentication-results: sourceware.org; auth=none
This patch implements a feature quite a lot of people wanted: allow using
__attribute__ ((deprecated)) on an enumerator. Implementing it was quite
straightforward: parse the attributes and apply them to the CONST_DECL.
I hit an issue in the C++ FE though: since r217677 we produce the deprecated
diagnostic twice. In finish_id_expression I've just removed the code that
isn't needed anymore (since we've already warned via mark_used), and in
constant_value_1 I'm passing 0 to mark_used to mollify the warning.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2015-05-06 Marek Polacek <polacek@redhat.com>
PR c/47043
* c-common.c (handle_deprecated_attribute): Allow CONST_DECL.
* c-parser.c (c_parser_enum_specifier): Parse and apply enumerator
attributes.
* cp-tree.h (build_enumerator): Update declaration.
* decl.c (build_enumerator): Add attributes parameter. Call
cplus_decl_attributes.
* init.c (constant_value_1): Pass 0 to mark_used.
* parser.c (cp_parser_enumerator_definition): Parse attributes and
pass them down to build_enumerator.
* pt.c (tsubst_enum): Pass NULL_TREE to build_enumerator.
* semantics.c (finish_id_expression): Don't warn_deprecated_use here.
* c-c++-common/attributes-enum-1.c: New test.
* g++.dg/cpp0x/attributes-enum-1.C: New test.
diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index ada8e8a..36968e5 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -8810,6 +8810,7 @@ handle_deprecated_attribute (tree *node, tree name,
|| TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == FIELD_DECL
+ || TREE_CODE (decl) == CONST_DECL
|| objc_method_decl (TREE_CODE (decl)))
TREE_DEPRECATED (decl) = 1;
else
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index bf0e4c57..f06a6b3 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -2584,7 +2584,11 @@ c_parser_enum_specifier (c_parser *parser)
else
enum_value = NULL_TREE;
enum_decl = build_enumerator (decl_loc, value_loc,
- &the_enum, enum_id, enum_value);
+ &the_enum, enum_id, enum_value);
+ /* Parse any specified attributes. */
+ tree enum_attrs = c_parser_attributes (parser);
+ if (enum_attrs)
+ decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs, 0);
TREE_CHAIN (enum_decl) = values;
values = enum_decl;
seen_comma = false;
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index e0fbf5e..6b26cb1 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -5400,7 +5400,7 @@ extern bool xref_basetypes (tree, tree);
extern tree start_enum (tree, tree, tree, bool, bool *);
extern void finish_enum_value_list (tree);
extern void finish_enum (tree);
-extern void build_enumerator (tree, tree, tree, location_t);
+extern void build_enumerator (tree, tree, tree, tree, location_t);
extern tree lookup_enumerator (tree, tree);
extern bool start_preparsed_function (tree, tree, int);
extern bool start_function (cp_decl_specifier_seq *,
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 261a12d..ebbd585 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -13067,11 +13067,12 @@ finish_enum (tree enumtype)
/* Build and install a CONST_DECL for an enumeration constant of the
enumeration type ENUMTYPE whose NAME and VALUE (if any) are provided.
- LOC is the location of NAME.
+ Apply ATTRIBUTES if available. LOC is the location of NAME.
Assignment of sequential values by default is handled here. */
void
-build_enumerator (tree name, tree value, tree enumtype, location_t loc)
+build_enumerator (tree name, tree value, tree enumtype, tree attributes,
+ location_t loc)
{
tree decl;
tree context;
@@ -13234,6 +13235,9 @@ incremented enumerator value is too large for %<long%>");
TREE_READONLY (decl) = 1;
DECL_INITIAL (decl) = value;
+ if (attributes)
+ cplus_decl_attributes (&decl, attributes, 0);
+
if (context && context == current_class_type && !SCOPED_ENUM_P (enumtype))
/* In something like `struct S { enum E { i = 7 }; };' we put `i'
on the TYPE_FIELDS list for `S'. (That's so that you can say
diff --git gcc/cp/init.c gcc/cp/init.c
index c41e30c..9298f2d 100644
--- gcc/cp/init.c
+++ gcc/cp/init.c
@@ -2035,7 +2035,7 @@ constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p)
specialization, we must instantiate it here. The
initializer for the static data member is not processed
until needed; we need it now. */
- mark_used (decl);
+ mark_used (decl, 0);
mark_rvalue_use (decl);
init = DECL_INITIAL (decl);
if (init == error_mark_node)
diff --git gcc/cp/parser.c gcc/cp/parser.c
index 30a3fab..b083c02 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -16090,8 +16090,11 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type)
if (check_for_bare_parameter_packs (value))
value = error_mark_node;
+ /* Parse any specified attributes. */
+ tree attrs = cp_parser_attributes_opt (parser);
+
/* Create the enumerator. */
- build_enumerator (identifier, value, type, loc);
+ build_enumerator (identifier, value, type, attrs, loc);
}
/* Parse a namespace-name.
diff --git gcc/cp/pt.c gcc/cp/pt.c
index 8e0e789..c3a452d 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -20686,8 +20686,8 @@ tsubst_enum (tree tag, tree newtag, tree args)
set_current_access_from_decl (decl);
/* Actually build the enumerator itself. */
- build_enumerator
- (DECL_NAME (decl), value, newtag, DECL_SOURCE_LOCATION (decl));
+ build_enumerator (DECL_NAME (decl), value, newtag, NULL_TREE,
+ DECL_SOURCE_LOCATION (decl));
}
if (SCOPED_ENUM_P (newtag))
diff --git gcc/cp/semantics.c gcc/cp/semantics.c
index 701a8eb..b46c6fc 100644
--- gcc/cp/semantics.c
+++ gcc/cp/semantics.c
@@ -3651,11 +3651,6 @@ finish_id_expression (tree id_expression,
}
}
- /* Handle references (c++/56130). */
- tree t = REFERENCE_REF_P (decl) ? TREE_OPERAND (decl, 0) : decl;
- if (TREE_DEPRECATED (t))
- warn_deprecated_use (t, NULL_TREE);
-
return decl;
}
diff --git gcc/testsuite/c-c++-common/attributes-enum-1.c gcc/testsuite/c-c++-common/attributes-enum-1.c
index e69de29..a02d91d 100644
--- gcc/testsuite/c-c++-common/attributes-enum-1.c
+++ gcc/testsuite/c-c++-common/attributes-enum-1.c
@@ -0,0 +1,22 @@
+/* Test enumerators with attributes. */
+/* PR c/47043 */
+/* { dg-do compile } */
+
+enum E {
+ A __attribute__((deprecated)),
+ B __attribute__((deprecated ("foo"))),
+ C = 10 __attribute__((deprecated)),
+ D = 15 __attribute__((deprecated ("foo"))),
+ E
+};
+
+int
+f (int i)
+{
+ i += A; /* { dg-warning ".A. is deprecated" } */
+ i += B; /* { dg-warning ".B. is deprecated" } */
+ i += C; /* { dg-warning ".C. is deprecated" } */
+ i += D; /* { dg-warning ".D. is deprecated" } */
+ i += E;
+ return i;
+}
diff --git gcc/testsuite/g++.dg/cpp0x/attributes-enum-1.C gcc/testsuite/g++.dg/cpp0x/attributes-enum-1.C
index e69de29..4146116 100644
--- gcc/testsuite/g++.dg/cpp0x/attributes-enum-1.C
+++ gcc/testsuite/g++.dg/cpp0x/attributes-enum-1.C
@@ -0,0 +1,20 @@
+// PR c/47046
+// { dg-do compile { target c++11 } }
+
+enum E {
+ A [[gnu::deprecated]]
+};
+
+enum class F {
+ B [[gnu::deprecated]],
+ C __attribute__ ((deprecated))
+};
+
+int
+f (int i)
+{
+ F f1 = F::B; // { dg-warning ".B. is deprecated" }
+ F f2 = F::C; // { dg-warning ".C. is deprecated" }
+ i += A; // { dg-warning ".A. is deprecated" }
+ return i;
+}
Marek