This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: C/C++ PATCH to allow deprecating enum values (PR c/47043)
- From: Marek Polacek <polacek at redhat dot com>
- To: Ed Smith-Rowland <3dw4rd at verizon dot net>, Joseph Myers <joseph at codesourcery dot com>, Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>, Sandra Loosemore <sandra at codesourcery dot com>
- Date: Thu, 14 May 2015 10:44:31 +0200
- Subject: Re: C/C++ PATCH to allow deprecating enum values (PR c/47043)
- Authentication-results: sourceware.org; auth=none
- References: <554AD940 dot 3000800 at verizon dot net> <20150507135955 dot GE3384 at redhat dot com> <554B74E8 dot 2060900 at verizon dot net> <20150507162240 dot GF3384 at redhat dot com>
Ping.
Joseph, do you have any further comments on the patch?
Jason, can you review the C++ parts?
Thanks,
On Thu, May 07, 2015 at 06:22:40PM +0200, Marek Polacek wrote:
> This (third) version of the patch entails the change in tsubst_enum Ed
> suggested + new testcase.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2015-05-07 Marek Polacek <polacek@redhat.com>
> Edward Smith-Rowland <3dw4rd@verizon.net>
>
> 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 decl attributes to build_enumerator.
> * semantics.c (finish_id_expression): Don't warn_deprecated_use here.
>
> * doc/extend.texi (Enumerator Attributes): New section.
> Document syntax of enumerator attributes.
>
> * c-c++-common/attributes-enum-1.c: New test.
> * c-c++-common/attributes-enum-2.c: New test.
> * g++.dg/cpp0x/attributes-enum-1.C: New test.
> * g++.dg/cpp1y/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..889e6d7 100644
> --- gcc/c/c-parser.c
> +++ gcc/c/c-parser.c
> @@ -2516,6 +2516,13 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
> enumerator:
> enumeration-constant
> enumeration-constant = constant-expression
> +
> + GNU Extensions:
> +
> + enumerator:
> + enumeration-constant attributes[opt]
> + enumeration-constant attributes[opt] = constant-expression
> +
> */
>
> static struct c_typespec
> @@ -2575,6 +2582,8 @@ c_parser_enum_specifier (c_parser *parser)
> c_parser_set_source_position_from_token (token);
> decl_loc = value_loc = token->location;
> c_parser_consume_token (parser);
> + /* Parse any specified attributes. */
> + tree enum_attrs = c_parser_attributes (parser);
> if (c_parser_next_token_is (parser, CPP_EQ))
> {
> c_parser_consume_token (parser);
> @@ -2584,7 +2593,9 @@ 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);
> + 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..420759e 100644
> --- gcc/cp/parser.c
> +++ gcc/cp/parser.c
> @@ -16056,7 +16056,13 @@ cp_parser_enumerator_list (cp_parser* parser, tree type)
> enumerator = constant-expression
>
> enumerator:
> - identifier */
> + identifier
> +
> + GNU Extensions:
> +
> + enumerator-definition:
> + enumerator attributes [opt]
> + enumerator attributes [opt] = constant-expression */
>
> static void
> cp_parser_enumerator_definition (cp_parser* parser, tree type)
> @@ -16074,6 +16080,9 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type)
> if (identifier == error_mark_node)
> return;
>
> + /* Parse any specified attributes. */
> + tree attrs = cp_parser_attributes_opt (parser);
> +
> /* If the next token is an '=', then there is an explicit value. */
> if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
> {
> @@ -16091,7 +16100,7 @@ cp_parser_enumerator_definition (cp_parser* parser, tree type)
> value = error_mark_node;
>
> /* 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..d5e2b56 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,
> + DECL_ATTRIBUTES (decl), 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/doc/extend.texi gcc/doc/extend.texi
> index c290059..4337a32 100644
> --- gcc/doc/extend.texi
> +++ gcc/doc/extend.texi
> @@ -59,6 +59,7 @@ extensions, accepted by GCC in C90 mode and in C++.
> * Variable Attributes:: Specifying attributes of variables.
> * Type Attributes:: Specifying attributes of types.
> * Label Attributes:: Specifying attributes on labels.
> +* Enumerator Attributes:: Specifying attributes on enumerators.
> * Attribute Syntax:: Formal syntax for attributes.
> * Function Prototypes:: Prototype declarations and old-style definitions.
> * C++ Comments:: C++ comments are recognized.
> @@ -2175,6 +2176,7 @@ attribute syntax and placement.
> GCC also supports attributes on
> variable declarations (@pxref{Variable Attributes}),
> labels (@pxref{Label Attributes}),
> +enumerators (@pxref{Enumerator Attributes}),
> and types (@pxref{Type Attributes}).
>
> There is some overlap between the purposes of attributes and pragmas
> @@ -5041,8 +5043,9 @@ by an attribute specification inside double parentheses. Some
> attributes are currently defined generically for variables.
> Other attributes are defined for variables on particular target
> systems. Other attributes are available for functions
> -(@pxref{Function Attributes}), labels (@pxref{Label Attributes}) and for
> -types (@pxref{Type Attributes}).
> +(@pxref{Function Attributes}), labels (@pxref{Label Attributes}),
> +enumerators (@pxref{Enumerator Attributes}), and for types
> +(@pxref{Type Attributes}).
> Other front ends might define more attributes
> (@pxref{C++ Extensions,,Extensions to the C++ Language}).
>
> @@ -5837,7 +5840,8 @@ attributes of types. Some type attributes apply only to @code{struct}
> and @code{union} types, while others can apply to any type defined
> via a @code{typedef} declaration. Other attributes are defined for
> functions (@pxref{Function Attributes}), labels (@pxref{Label
> -Attributes}) and for variables (@pxref{Variable Attributes}).
> +Attributes}), enumerators (@pxref{Enumerator Attributes}), and for
> +variables (@pxref{Variable Attributes}).
>
> The @code{__attribute__} keyword is followed by an attribute specification
> inside double parentheses.
> @@ -6300,7 +6304,8 @@ compilers to match the native Microsoft compiler.
> GCC allows attributes to be set on C labels. @xref{Attribute Syntax}, for
> details of the exact syntax for using attributes. Other attributes are
> available for functions (@pxref{Function Attributes}), variables
> -(@pxref{Variable Attributes}) and for types (@pxref{Type Attributes}).
> +(@pxref{Variable Attributes}), enumerators (@xref{Enumerator Attributes}),
> +and for types (@pxref{Type Attributes}).
>
> This example uses the @code{cold} label attribute to indicate the
> @code{ErrorHandling} branch is unlikely to be taken and that the
> @@ -6346,6 +6351,45 @@ with computed goto or @code{asm goto}.
>
> @end table
>
> +@node Enumerator Attributes
> +@section Enumerator Attributes
> +@cindex Enumerator Attributes
> +
> +GCC allows attributes to be set on enumerators. @xref{Attribute Syntax}, for
> +details of the exact syntax for using attributes. Other attributes are
> +available for functions (@pxref{Function Attributes}), variables
> +(@pxref{Variable Attributes}), labels (@xref{Label Attributes}),
> +and for types (@pxref{Type Attributes}).
> +
> +This example uses the @code{deprecated} enumerator attribute to indicate the
> +@code{oldval} enumerator is deprecated:
> +
> +@smallexample
> +enum E @{
> + oldval __attribute__((deprecated)),
> + newval
> +@};
> +
> +int
> +fn (void)
> +@{
> + return oldval;
> +@}
> +@end smallexample
> +
> +@table @code
> +@item deprecated
> +@cindex @code{deprecated} enumerator attribute
> +The @code{deprecated} attribute results in a warning if the enumerator
> +is used anywhere in the source file. This is useful when identifying
> +enumerators that are expected to be removed in a future version of a
> +program. The warning also includes the location of the declaration
> +of the deprecated enumerator, to enable users to easily find further
> +information about why the enumerator is deprecated, or what they should
> +do instead. Note that the warnings only occurs for uses.
> +
> +@end table
> +
> @node Attribute Syntax
> @section Attribute Syntax
> @cindex attribute syntax
> @@ -6371,6 +6415,8 @@ for details of the semantics of attributes applying to structure, union
> and enumerated types.
> @xref{Label Attributes}, for details of the semantics of attributes
> applying to labels.
> +@xref{Enumerator Attributes}, for details of the semantics of attributes
> +applying to enumerators.
>
> An @dfn{attribute specifier} is of the form
> @code{__attribute__ ((@var{attribute-list}))}. An @dfn{attribute list}
> @@ -6428,6 +6474,14 @@ ambiguous, as it is permissible for a declaration, which could begin
> with an attribute list, to be labelled in C++. Declarations cannot be
> labelled in C90 or C99, so the ambiguity does not arise there.
>
> +@subsubheading Enumerator Attributes
> +
> +In GNU C, an attribute specifier list may appear as part of an enumerator.
> +The attribute goes after the enumeration constant, before @code{=}, if
> +present. The optional attribute in the enumerator appertains to the
> +enumeration constant. It is not possible to place the attribute after
> +the constant expression, if present.
> +
> @subsubheading Type Attributes
>
> An attribute specifier list may appear as part of a @code{struct},
> diff --git gcc/testsuite/c-c++-common/attributes-enum-1.c gcc/testsuite/c-c++-common/attributes-enum-1.c
> index e69de29..cb5af5b 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 __attribute__((deprecated)) = 10,
> + D __attribute__((deprecated ("foo"))) = 15,
> + 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/c-c++-common/attributes-enum-2.c gcc/testsuite/c-c++-common/attributes-enum-2.c
> index e69de29..f143f15 100644
> --- gcc/testsuite/c-c++-common/attributes-enum-2.c
> +++ gcc/testsuite/c-c++-common/attributes-enum-2.c
> @@ -0,0 +1,14 @@
> +/* Test enumerators with attributes. Test invalid uses. */
> +/* PR c/47043 */
> +/* { dg-do compile } */
> +
> +enum E {
> + A __attribute__((foo)), /* { dg-warning "ignored" } */
> + B __attribute__((cold)), /* { dg-warning "ignored" } */
> + C __attribute__((const)), /* { dg-warning "ignored" } */
> + D __attribute__((unused)), /* { dg-warning "ignored" } */
> + E __attribute__((flatten)), /* { dg-warning "ignored" } */
> + F __attribute__((tm)), /* { dg-warning "ignored" } */
> + G __attribute__((common)), /* { dg-warning "ignored" } */
> + H __attribute__((volatile)), /* { dg-warning "ignored" } */
> +};
> diff --git gcc/testsuite/g++.dg/cpp0x/attributes-enum-1.C gcc/testsuite/g++.dg/cpp0x/attributes-enum-1.C
> index e69de29..fd1b6f0 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/47043
> +// { 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;
> +}
> diff --git gcc/testsuite/g++.dg/cpp1y/attributes-enum-1.C gcc/testsuite/g++.dg/cpp1y/attributes-enum-1.C
> index e69de29..3bd1ba1 100644
> --- gcc/testsuite/g++.dg/cpp1y/attributes-enum-1.C
> +++ gcc/testsuite/g++.dg/cpp1y/attributes-enum-1.C
> @@ -0,0 +1,35 @@
> +// PR c/47043
> +// { dg-do compile { target c++14 } }
> +
> +class C
> +{
> +public:
> + enum Foo
> + {
> + T,
> + U [[deprecated("unused")]],
> + V
> + };
> +};
> +
> +template<typename Tp>
> + class D
> + {
> + public:
> + enum Bar
> + {
> + X,
> + Y [[deprecated("unused")]],
> + Z
> + };
> + };
> +
> +int
> +f (int i)
> +{
> + auto j = C::U; // { dg-warning ".U. is deprecated" }
> +
> + auto k = D<int>::Y; // { dg-warning ".Y. is deprecated" }
> +
> + return i;
> +}
Marek