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 <pola...@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