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

Reply via email to