c-common.c (do_switch_warnings): Look through the CONST_DECLs in the enumerators of an ENUMERAL_TYPE.
2008-08-26 Douglas Gregor <doug.gregor@gmail.com> * c-common.c (do_switch_warnings): Look through the CONST_DECLs in the enumerators of an ENUMERAL_TYPE. * dbxout.c (dbxout_type): Ditto. 2008-08-26 Douglas Gregor <doug.gregor@gmail.com> * typeck.c (type_after_usual_arithmetic_conversions): Don't do the usual arithmetic conversions on scoped enumeration types. (common_type): Ditto. (default_conversion): Don't perform integral promotions on scoped enumeration types. (build_array_ref): Scoped enumeration types can't be used as subscripts. * decl.c (start_enum): If building a C++0x scoped enumeration, enter its scope. If provided with an underlying type, check that underlying type and set up the enumeration type accordingly. (finish_enum): Only compute an underlying type if the underlying type isn't already fixed, and only convert the enumerator values now if we've just computed the underlying type. Finish the scope of C++0x scoped enumerations. (build_enumerator): For enumerations with a fixed underlying type, check the enumerator values when the enumerator is defined. (lookup_enumerator): New. * call.c (standard_conversion): Don't allow assignment from integers to scoped enumeration types, even with -fpermissive. Don't convert from scoped enumerations to bool or any arithmetic types. (build_conditional_expr): Don't per the usual arithmetic conversions for scoped enumeration types. (convert_like_real): Check complain to see if we should produce warnings. * error.c (class_key_or_enum_as_string): Print scoped enums. * cp-tree.h (MAYBE_CLASS_TYPE_P): Check CLASS_TYPE_P, not TYPE_LANG_FLAG_5. (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P): New. (SCOPED_ENUM_P): New. (UNSCOPED_ENUM_P): New. (SET_SCOPED_ENUM_P): New. (ENUM_UNDERLYING_TYPE): New. * pt.c (lookup_template_class): Update the instantiation of enum types to deal with C++0x scoped enumerations and underlying types. * name-lookup.c (begin_scope): Deal with scoped enumeration scopes. (lookup_qualified_name): Deal with lookup into enumeration types. * name-lookup.h (enum scope_kind): Add sk_scoped_enum. * parser.c (cp_parser_class_or_namespace_name): Rename to... (cp_parser_qualifying_entity): ... this. Also, in C++0x mode, parse a type-name that can be an enumeration type. (cp_parser_nested_name_specifier_opt): Update with C++0x grammar. (cp_parser_elaborated_type_specifier): Parse the optional `struct' or `class' following enum (in C++0x). (cp_parser_enum_specifier): Parse C++0x scoped enumerations and enum-base clauses. 2008-08-26 Douglas Gregor <doug.gregor@gmail.com> * g++.dg/cpp0x/scoped_enum_examples.C: New. * g++.dg/cpp0x/scoped_enum.C: New. * g++.dg/cpp0x/scoped_enum_98.C: New. * g++.dg/cpp0x/enum_base_warn.C: New. * g++.dg/cpp0x/enum_base.C: New. From-SVN: r139611
This commit is contained in:
parent
54e2227628
commit
adf2edec3c
17 changed files with 646 additions and 155 deletions
|
@ -4928,6 +4928,8 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,
|
|||
for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain))
|
||||
{
|
||||
tree value = TREE_VALUE (chain);
|
||||
if (TREE_CODE (value) == CONST_DECL)
|
||||
value = DECL_INITIAL (value);
|
||||
node = splay_tree_lookup (cases, (splay_tree_key) value);
|
||||
if (node)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,54 @@
|
|||
2008-08-26 Douglas Gregor <doug.gregor@gmail.com>
|
||||
|
||||
* typeck.c (type_after_usual_arithmetic_conversions): Don't do the
|
||||
usual arithmetic conversions on scoped enumeration types.
|
||||
(common_type): Ditto.
|
||||
(default_conversion): Don't perform integral promotions on scoped
|
||||
enumeration types.
|
||||
(build_array_ref): Scoped enumeration types can't be used as
|
||||
subscripts.
|
||||
* decl.c (start_enum): If building a C++0x scoped enumeration,
|
||||
enter its scope. If provided with an underlying type, check that
|
||||
underlying type and set up the enumeration type accordingly.
|
||||
(finish_enum): Only compute an underlying type if the underlying
|
||||
type isn't already fixed, and only convert the enumerator values
|
||||
now if we've just computed the underlying type. Finish the scope
|
||||
of C++0x scoped enumerations.
|
||||
(build_enumerator): For enumerations with a fixed underlying type,
|
||||
check the enumerator values when the enumerator is defined.
|
||||
(lookup_enumerator): New.
|
||||
* call.c (standard_conversion): Don't allow assignment from
|
||||
integers to scoped enumeration types, even with -fpermissive.
|
||||
Don't convert from scoped enumerations to bool or any arithmetic
|
||||
types.
|
||||
(build_conditional_expr): Don't per the usual arithmetic
|
||||
conversions for scoped enumeration types.
|
||||
(convert_like_real): Check complain to see if we should
|
||||
produce warnings.
|
||||
* error.c (class_key_or_enum_as_string): Print scoped enums.
|
||||
* cp-tree.h (MAYBE_CLASS_TYPE_P): Check CLASS_TYPE_P, not
|
||||
TYPE_LANG_FLAG_5.
|
||||
(INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P): New.
|
||||
(SCOPED_ENUM_P): New.
|
||||
(UNSCOPED_ENUM_P): New.
|
||||
(SET_SCOPED_ENUM_P): New.
|
||||
(ENUM_UNDERLYING_TYPE): New.
|
||||
* pt.c (lookup_template_class): Update the instantiation of enum
|
||||
types to deal with C++0x scoped enumerations and underlying
|
||||
types.
|
||||
* name-lookup.c (begin_scope): Deal with scoped enumeration
|
||||
scopes.
|
||||
(lookup_qualified_name): Deal with lookup into enumeration types.
|
||||
* name-lookup.h (enum scope_kind): Add sk_scoped_enum.
|
||||
* parser.c (cp_parser_class_or_namespace_name): Rename to...
|
||||
(cp_parser_qualifying_entity): ... this. Also, in C++0x mode,
|
||||
parse a type-name that can be an enumeration type.
|
||||
(cp_parser_nested_name_specifier_opt): Update with C++0x grammar.
|
||||
(cp_parser_elaborated_type_specifier): Parse the
|
||||
optional `struct' or `class' following enum (in C++0x).
|
||||
(cp_parser_enum_specifier): Parse C++0x scoped enumerations and
|
||||
enum-base clauses.
|
||||
|
||||
2008-08-21 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
|
||||
|
||||
* typeck.c: Update all calls to pedwarn.
|
||||
|
|
|
@ -771,7 +771,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
conv = build_conv (ck_std, to, conv);
|
||||
conv->bad_p = true;
|
||||
}
|
||||
else if (tcode == ENUMERAL_TYPE && fcode == INTEGER_TYPE)
|
||||
else if (UNSCOPED_ENUM_P (to) && fcode == INTEGER_TYPE)
|
||||
{
|
||||
/* For backwards brain damage compatibility, allow interconversion of
|
||||
enums and integers with a pedwarn. */
|
||||
|
@ -896,10 +896,11 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
{
|
||||
/* [conv.bool]
|
||||
|
||||
An rvalue of arithmetic, enumeration, pointer, or pointer to
|
||||
member type can be converted to an rvalue of type bool. */
|
||||
An rvalue of arithmetic, unscoped enumeration, pointer, or
|
||||
pointer to member type can be converted to an rvalue of type
|
||||
bool. */
|
||||
if (ARITHMETIC_TYPE_P (from)
|
||||
|| fcode == ENUMERAL_TYPE
|
||||
|| UNSCOPED_ENUM_P (from)
|
||||
|| fcode == POINTER_TYPE
|
||||
|| TYPE_PTR_TO_MEMBER_P (from))
|
||||
{
|
||||
|
@ -919,7 +920,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
/* As an extension, allow conversion to complex type. */
|
||||
else if (ARITHMETIC_TYPE_P (to))
|
||||
{
|
||||
if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
|
||||
if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE)
|
||||
|| SCOPED_ENUM_P (from))
|
||||
return NULL;
|
||||
conv = build_conv (ck_std, to, conv);
|
||||
|
||||
|
@ -3702,9 +3704,9 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
|
|||
type; the usual arithmetic conversions are performed to bring
|
||||
them to a common type, and the result is of that type. */
|
||||
else if ((ARITHMETIC_TYPE_P (arg2_type)
|
||||
|| TREE_CODE (arg2_type) == ENUMERAL_TYPE)
|
||||
|| UNSCOPED_ENUM_P (arg2_type))
|
||||
&& (ARITHMETIC_TYPE_P (arg3_type)
|
||||
|| TREE_CODE (arg3_type) == ENUMERAL_TYPE))
|
||||
|| UNSCOPED_ENUM_P (arg3_type)))
|
||||
{
|
||||
/* In this case, there is always a common type. */
|
||||
result_type = type_after_usual_arithmetic_conversions (arg2_type,
|
||||
|
@ -4791,7 +4793,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
|||
if (convs->check_narrowing)
|
||||
check_narrowing (totype, expr);
|
||||
|
||||
if (issue_conversion_warnings)
|
||||
if (issue_conversion_warnings && (complain & tf_warning))
|
||||
expr = convert_and_check (totype, expr);
|
||||
else
|
||||
expr = convert (totype, expr);
|
||||
|
|
|
@ -116,7 +116,8 @@ extern void cp_cpp_error (cpp_reader *, int,
|
|||
2: Unused
|
||||
3: TYPE_FOR_JAVA.
|
||||
4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR
|
||||
5: CLASS_TYPE_P.
|
||||
5: CLASS_TYPE_P (in RECORD_TYPE and UNION_TYPE)
|
||||
SCOPED_ENUM_P (in ENUMERAL_TYPE)
|
||||
6: TYPE_DEPENDENT_P_VALID
|
||||
|
||||
Usage of DECL_LANG_FLAG_?:
|
||||
|
@ -980,7 +981,7 @@ enum languages { lang_c, lang_cplusplus, lang_java };
|
|||
|| TREE_CODE (T) == TYPEOF_TYPE \
|
||||
|| TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \
|
||||
|| TREE_CODE (T) == DECLTYPE_TYPE \
|
||||
|| TYPE_LANG_FLAG_5 (T))
|
||||
|| CLASS_TYPE_P (T))
|
||||
|
||||
/* Set CLASS_TYPE_P for T to VAL. T must be a class, struct, or
|
||||
union type. */
|
||||
|
@ -2688,6 +2689,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|
|||
#define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE) \
|
||||
(TREE_CODE (TYPE) == ENUMERAL_TYPE || CP_INTEGRAL_TYPE_P (TYPE))
|
||||
|
||||
/* Returns true if TYPE is an integral or unscoped enumeration type. */
|
||||
#define INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P(TYPE) \
|
||||
(UNSCOPED_ENUM_P (TYPE) || CP_INTEGRAL_TYPE_P (TYPE))
|
||||
|
||||
/* [basic.fundamental]
|
||||
|
||||
Integral and floating types are collectively called arithmetic
|
||||
|
@ -2714,6 +2719,59 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|
|||
|| TYPE_PTR_P (TYPE) \
|
||||
|| TYPE_PTRMEMFUNC_P (TYPE))
|
||||
|
||||
/* Determines whether this type is a C++0x scoped enumeration
|
||||
type. Scoped enumerations types are introduced via "enum class" or
|
||||
"enum struct", e.g.,
|
||||
|
||||
enum class Color {
|
||||
Red, Green, Blue
|
||||
};
|
||||
|
||||
Scoped enumeration types are different from normal (unscoped)
|
||||
enumeration types in several ways:
|
||||
|
||||
- The enumerators of a scoped enumeration type are only available
|
||||
within the scope of the enumeration type and not in the
|
||||
enclosing scope. For example, the Red color can be referred to
|
||||
with "Color::Red" but not "Red".
|
||||
|
||||
- Scoped enumerators and enumerations do not implicitly convert
|
||||
to integers or 'bool'.
|
||||
|
||||
- The underlying type of the enum is well-defined. */
|
||||
#define SCOPED_ENUM_P(TYPE) \
|
||||
(TREE_CODE (TYPE) == ENUMERAL_TYPE && TYPE_LANG_FLAG_5 (TYPE))
|
||||
|
||||
/* Determine whether this is an unscoped enumeration type. */
|
||||
#define UNSCOPED_ENUM_P(TYPE) \
|
||||
(TREE_CODE (TYPE) == ENUMERAL_TYPE && !TYPE_LANG_FLAG_5 (TYPE))
|
||||
|
||||
/* Set the flag indicating whether an ENUMERAL_TYPE is a C++0x scoped
|
||||
enumeration type (1) or a normal (unscoped) enumeration type
|
||||
(0). */
|
||||
#define SET_SCOPED_ENUM_P(TYPE, VAL) \
|
||||
(TYPE_LANG_FLAG_5 (ENUMERAL_TYPE_CHECK (TYPE)) = (VAL))
|
||||
|
||||
/* Returns the underlying type of the given enumeration type. The
|
||||
underlying type is determined in different ways, depending on the
|
||||
properties of the enum:
|
||||
|
||||
- In C++0x, the underlying type can be explicitly specified, e.g.,
|
||||
|
||||
enum E1 : char { ... } // underlying type is char
|
||||
|
||||
- In a C++0x scoped enumeration, the underlying type is int
|
||||
unless otherwises specified:
|
||||
|
||||
enum class E2 { ... } // underlying type is int
|
||||
|
||||
- Otherwise, the underlying type is determined based on the
|
||||
values of the enumerators. In this case, the
|
||||
ENUM_UNDERLYING_TYPE will not be set until after the definition
|
||||
of the enumeration is completed by finish_enum. */
|
||||
#define ENUM_UNDERLYING_TYPE(TYPE) \
|
||||
TREE_TYPE (ENUMERAL_TYPE_CHECK (TYPE))
|
||||
|
||||
/* [dcl.init.aggr]
|
||||
|
||||
An aggregate is an array or a class with no user-declared
|
||||
|
@ -4272,9 +4330,10 @@ 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);
|
||||
extern tree start_enum (tree, tree, bool);
|
||||
extern void finish_enum (tree);
|
||||
extern void build_enumerator (tree, tree, tree);
|
||||
extern tree lookup_enumerator (tree, tree);
|
||||
extern void start_preparsed_function (tree, tree, int);
|
||||
extern int start_function (cp_decl_specifier_seq *, const cp_declarator *, tree);
|
||||
extern tree begin_function_body (void);
|
||||
|
|
287
gcc/cp/decl.c
287
gcc/cp/decl.c
|
@ -10712,13 +10712,20 @@ xref_basetypes (tree ref, tree base_list)
|
|||
|
||||
|
||||
/* Begin compiling the definition of an enumeration type.
|
||||
NAME is its name.
|
||||
NAME is its name,
|
||||
|
||||
UNDERLYING_TYPE is the type that will be used as the storage for
|
||||
the enumeration type. This should be NULL_TREE if no storage type
|
||||
was specified.
|
||||
|
||||
SCOPED_ENUM_P is true if this is a scoped enumeration type.
|
||||
|
||||
Returns the type object, as yet incomplete.
|
||||
Also records info about it so that build_enumerator
|
||||
may be used to declare the individual values as they are read. */
|
||||
|
||||
tree
|
||||
start_enum (tree name)
|
||||
start_enum (tree name, tree underlying_type, bool scoped_enum_p)
|
||||
{
|
||||
tree enumtype;
|
||||
|
||||
|
@ -10750,6 +10757,39 @@ start_enum (tree name)
|
|||
enumtype = pushtag (name, enumtype, /*tag_scope=*/ts_current);
|
||||
}
|
||||
|
||||
if (scoped_enum_p)
|
||||
{
|
||||
SET_SCOPED_ENUM_P (enumtype, 1);
|
||||
begin_scope (sk_scoped_enum, enumtype);
|
||||
|
||||
/* [C++0x dcl.enum]p5:
|
||||
|
||||
If not explicitly specified, the underlying type of a scoped
|
||||
enumeration type is int. */
|
||||
if (!underlying_type)
|
||||
underlying_type = integer_type_node;
|
||||
}
|
||||
|
||||
if (underlying_type)
|
||||
{
|
||||
if (CP_INTEGRAL_TYPE_P (underlying_type))
|
||||
{
|
||||
TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (underlying_type);
|
||||
TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (underlying_type);
|
||||
TYPE_SIZE (enumtype) = TYPE_SIZE (underlying_type);
|
||||
TYPE_SIZE_UNIT (enumtype) = TYPE_SIZE_UNIT (underlying_type);
|
||||
TYPE_MODE (enumtype) = TYPE_MODE (underlying_type);
|
||||
TYPE_PRECISION (enumtype) = TYPE_PRECISION (underlying_type);
|
||||
TYPE_ALIGN (enumtype) = TYPE_ALIGN (underlying_type);
|
||||
TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type);
|
||||
TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (underlying_type);
|
||||
ENUM_UNDERLYING_TYPE (enumtype) = underlying_type;
|
||||
}
|
||||
else
|
||||
error ("underlying type %<%T%> of %<%T%> must be an integral type",
|
||||
underlying_type, enumtype);
|
||||
}
|
||||
|
||||
return enumtype;
|
||||
}
|
||||
|
||||
|
@ -10762,9 +10802,9 @@ finish_enum (tree enumtype)
|
|||
{
|
||||
tree values;
|
||||
tree decl;
|
||||
tree value;
|
||||
tree minnode;
|
||||
tree maxnode;
|
||||
tree value;
|
||||
tree t;
|
||||
bool unsignedp;
|
||||
bool use_short_enum;
|
||||
|
@ -10773,6 +10813,8 @@ finish_enum (tree enumtype)
|
|||
int precision;
|
||||
integer_type_kind itk;
|
||||
tree underlying_type = NULL_TREE;
|
||||
bool fixed_underlying_type_p
|
||||
= ENUM_UNDERLYING_TYPE (enumtype) != NULL_TREE;
|
||||
|
||||
/* We built up the VALUES in reverse order. */
|
||||
TYPE_VALUES (enumtype) = nreverse (TYPE_VALUES (enumtype));
|
||||
|
@ -10798,34 +10840,34 @@ finish_enum (tree enumtype)
|
|||
minnode = maxnode = NULL_TREE;
|
||||
|
||||
for (values = TYPE_VALUES (enumtype);
|
||||
values;
|
||||
values = TREE_CHAIN (values))
|
||||
{
|
||||
decl = TREE_VALUE (values);
|
||||
values;
|
||||
values = TREE_CHAIN (values))
|
||||
{
|
||||
decl = TREE_VALUE (values);
|
||||
|
||||
/* [dcl.enum]: Following the closing brace of an enum-specifier,
|
||||
each enumerator has the type of its enumeration. Prior to the
|
||||
closing brace, the type of each enumerator is the type of its
|
||||
initializing value. */
|
||||
TREE_TYPE (decl) = enumtype;
|
||||
/* [dcl.enum]: Following the closing brace of an enum-specifier,
|
||||
each enumerator has the type of its enumeration. Prior to the
|
||||
closing brace, the type of each enumerator is the type of its
|
||||
initializing value. */
|
||||
TREE_TYPE (decl) = enumtype;
|
||||
|
||||
/* Update the minimum and maximum values, if appropriate. */
|
||||
value = DECL_INITIAL (decl);
|
||||
if (value == error_mark_node)
|
||||
value = integer_zero_node;
|
||||
/* Figure out what the minimum and maximum values of the
|
||||
enumerators are. */
|
||||
if (!minnode)
|
||||
minnode = maxnode = value;
|
||||
else if (tree_int_cst_lt (maxnode, value))
|
||||
maxnode = value;
|
||||
else if (tree_int_cst_lt (value, minnode))
|
||||
minnode = value;
|
||||
}
|
||||
/* Update the minimum and maximum values, if appropriate. */
|
||||
value = DECL_INITIAL (decl);
|
||||
if (value == error_mark_node)
|
||||
value = integer_zero_node;
|
||||
/* Figure out what the minimum and maximum values of the
|
||||
enumerators are. */
|
||||
if (!minnode)
|
||||
minnode = maxnode = value;
|
||||
else if (tree_int_cst_lt (maxnode, value))
|
||||
maxnode = value;
|
||||
else if (tree_int_cst_lt (value, minnode))
|
||||
minnode = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* [dcl.enum]
|
||||
|
||||
|
||||
If the enumerator-list is empty, the underlying type is as if
|
||||
the enumeration had a single enumerator with value 0. */
|
||||
minnode = maxnode = integer_zero_node;
|
||||
|
@ -10839,46 +10881,70 @@ finish_enum (tree enumtype)
|
|||
highprec = min_precision (maxnode, unsignedp);
|
||||
precision = MAX (lowprec, highprec);
|
||||
|
||||
/* Determine the underlying type of the enumeration.
|
||||
|
||||
[dcl.enum]
|
||||
|
||||
The underlying type of an enumeration is an integral type that
|
||||
can represent all the enumerator values defined in the
|
||||
enumeration. It is implementation-defined which integral type is
|
||||
used as the underlying type for an enumeration except that the
|
||||
underlying type shall not be larger than int unless the value of
|
||||
an enumerator cannot fit in an int or unsigned int.
|
||||
|
||||
We use "int" or an "unsigned int" as the underlying type, even if
|
||||
a smaller integral type would work, unless the user has
|
||||
explicitly requested that we use the smallest possible type. The
|
||||
user can request that for all enumerations with a command line
|
||||
flag, or for just one enumeration with an attribute. */
|
||||
|
||||
use_short_enum = flag_short_enums
|
||||
|| lookup_attribute ("packed", TYPE_ATTRIBUTES (enumtype));
|
||||
|
||||
for (itk = (use_short_enum ? itk_char : itk_int);
|
||||
itk != itk_none;
|
||||
itk++)
|
||||
if (!fixed_underlying_type_p)
|
||||
{
|
||||
underlying_type = integer_types[itk];
|
||||
if (TYPE_PRECISION (underlying_type) >= precision
|
||||
&& TYPE_UNSIGNED (underlying_type) == unsignedp)
|
||||
break;
|
||||
}
|
||||
if (itk == itk_none)
|
||||
{
|
||||
/* DR 377
|
||||
/* Determine the underlying type of the enumeration.
|
||||
|
||||
IF no integral type can represent all the enumerator values, the
|
||||
enumeration is ill-formed. */
|
||||
error ("no integral type can represent all of the enumerator values "
|
||||
"for %qT", enumtype);
|
||||
precision = TYPE_PRECISION (long_long_integer_type_node);
|
||||
underlying_type = integer_types[itk_unsigned_long_long];
|
||||
[dcl.enum]
|
||||
|
||||
The underlying type of an enumeration is an integral type that
|
||||
can represent all the enumerator values defined in the
|
||||
enumeration. It is implementation-defined which integral type is
|
||||
used as the underlying type for an enumeration except that the
|
||||
underlying type shall not be larger than int unless the value of
|
||||
an enumerator cannot fit in an int or unsigned int.
|
||||
|
||||
We use "int" or an "unsigned int" as the underlying type, even if
|
||||
a smaller integral type would work, unless the user has
|
||||
explicitly requested that we use the smallest possible type. The
|
||||
user can request that for all enumerations with a command line
|
||||
flag, or for just one enumeration with an attribute. */
|
||||
|
||||
use_short_enum = flag_short_enums
|
||||
|| lookup_attribute ("packed", TYPE_ATTRIBUTES (enumtype));
|
||||
|
||||
for (itk = (use_short_enum ? itk_char : itk_int);
|
||||
itk != itk_none;
|
||||
itk++)
|
||||
{
|
||||
underlying_type = integer_types[itk];
|
||||
if (TYPE_PRECISION (underlying_type) >= precision
|
||||
&& TYPE_UNSIGNED (underlying_type) == unsignedp)
|
||||
break;
|
||||
}
|
||||
if (itk == itk_none)
|
||||
{
|
||||
/* DR 377
|
||||
|
||||
IF no integral type can represent all the enumerator values, the
|
||||
enumeration is ill-formed. */
|
||||
error ("no integral type can represent all of the enumerator values "
|
||||
"for %qT", enumtype);
|
||||
precision = TYPE_PRECISION (long_long_integer_type_node);
|
||||
underlying_type = integer_types[itk_unsigned_long_long];
|
||||
}
|
||||
|
||||
/* [dcl.enum]
|
||||
|
||||
The value of sizeof() applied to an enumeration type, an object
|
||||
of an enumeration type, or an enumerator, is the value of sizeof()
|
||||
applied to the underlying type. */
|
||||
TYPE_SIZE (enumtype) = TYPE_SIZE (underlying_type);
|
||||
TYPE_SIZE_UNIT (enumtype) = TYPE_SIZE_UNIT (underlying_type);
|
||||
TYPE_MODE (enumtype) = TYPE_MODE (underlying_type);
|
||||
TYPE_ALIGN (enumtype) = TYPE_ALIGN (underlying_type);
|
||||
TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type);
|
||||
TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (underlying_type);
|
||||
|
||||
/* Set the underlying type of the enumeration type to the
|
||||
computed enumeration type, restricted to the enumerator
|
||||
values. */
|
||||
ENUM_UNDERLYING_TYPE (enumtype) = copy_node (underlying_type);
|
||||
set_min_and_max_values_for_integral_type
|
||||
(ENUM_UNDERLYING_TYPE (enumtype), precision, unsignedp);
|
||||
}
|
||||
else
|
||||
underlying_type = ENUM_UNDERLYING_TYPE (enumtype);
|
||||
|
||||
/* Compute the minimum and maximum values for the type.
|
||||
|
||||
|
@ -10889,28 +10955,16 @@ finish_enum (tree enumtype)
|
|||
underlying type in the range bmin to bmax, where bmin and bmax are,
|
||||
respectively, the smallest and largest values of the smallest bit-
|
||||
field that can store emin and emax. */
|
||||
|
||||
|
||||
/* The middle-end currently assumes that types with TYPE_PRECISION
|
||||
narrower than their underlying type are suitably zero or sign
|
||||
extended to fill their mode. g++ doesn't make these guarantees.
|
||||
Until the middle-end can represent such paradoxical types, we
|
||||
set the TYPE_PRECISION to the width of the underlying type. */
|
||||
TYPE_PRECISION (enumtype) = TYPE_PRECISION (underlying_type);
|
||||
|
||||
|
||||
set_min_and_max_values_for_integral_type (enumtype, precision, unsignedp);
|
||||
|
||||
/* [dcl.enum]
|
||||
|
||||
The value of sizeof() applied to an enumeration type, an object
|
||||
of an enumeration type, or an enumerator, is the value of sizeof()
|
||||
applied to the underlying type. */
|
||||
TYPE_SIZE (enumtype) = TYPE_SIZE (underlying_type);
|
||||
TYPE_SIZE_UNIT (enumtype) = TYPE_SIZE_UNIT (underlying_type);
|
||||
TYPE_MODE (enumtype) = TYPE_MODE (underlying_type);
|
||||
TYPE_ALIGN (enumtype) = TYPE_ALIGN (underlying_type);
|
||||
TYPE_USER_ALIGN (enumtype) = TYPE_USER_ALIGN (underlying_type);
|
||||
TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (underlying_type);
|
||||
|
||||
|
||||
/* Convert each of the enumerators to the type of the underlying
|
||||
type of the enumeration. */
|
||||
for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values))
|
||||
|
@ -10920,9 +10974,14 @@ finish_enum (tree enumtype)
|
|||
decl = TREE_VALUE (values);
|
||||
saved_location = input_location;
|
||||
input_location = DECL_SOURCE_LOCATION (decl);
|
||||
value = perform_implicit_conversion (underlying_type,
|
||||
DECL_INITIAL (decl),
|
||||
tf_warning_or_error);
|
||||
if (fixed_underlying_type_p)
|
||||
/* If the enumeration type has a fixed underlying type, we
|
||||
already checked all of the enumerator values. */
|
||||
value = DECL_INITIAL (decl);
|
||||
else
|
||||
value = perform_implicit_conversion (underlying_type,
|
||||
DECL_INITIAL (decl),
|
||||
tf_warning_or_error);
|
||||
input_location = saved_location;
|
||||
|
||||
/* Do not clobber shared ints. */
|
||||
|
@ -10930,7 +10989,6 @@ finish_enum (tree enumtype)
|
|||
|
||||
TREE_TYPE (value) = enumtype;
|
||||
DECL_INITIAL (decl) = value;
|
||||
TREE_VALUE (values) = value;
|
||||
}
|
||||
|
||||
/* Fix up all variant types of this enum type. */
|
||||
|
@ -10946,8 +11004,13 @@ finish_enum (tree enumtype)
|
|||
TYPE_ALIGN (t) = TYPE_ALIGN (enumtype);
|
||||
TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (enumtype);
|
||||
TYPE_UNSIGNED (t) = TYPE_UNSIGNED (enumtype);
|
||||
ENUM_UNDERLYING_TYPE (t) = ENUM_UNDERLYING_TYPE (enumtype);
|
||||
}
|
||||
|
||||
/* Finish up the scope of a scoped enumeration. */
|
||||
if (SCOPED_ENUM_P (enumtype))
|
||||
finish_scope ();
|
||||
|
||||
/* Finish debugging output for this type. */
|
||||
rest_of_type_compilation (enumtype, namespace_bindings_p ());
|
||||
}
|
||||
|
@ -11024,24 +11087,46 @@ build_enumerator (tree name, tree value, tree enumtype)
|
|||
|
||||
/* Remove no-op casts from the value. */
|
||||
STRIP_TYPE_NOPS (value);
|
||||
|
||||
/* If the underlying type of the enum is fixed, check whether
|
||||
the enumerator values fits in the underlying type. If it
|
||||
does not fit, the program is ill-formed [C++0x dcl.enum]. */
|
||||
if (ENUM_UNDERLYING_TYPE (enumtype)
|
||||
&& value
|
||||
&& TREE_CODE (value) == INTEGER_CST
|
||||
&& !int_fits_type_p (value, ENUM_UNDERLYING_TYPE (enumtype)))
|
||||
{
|
||||
error ("enumerator value %E is too large for underlying type %<%T%>",
|
||||
value, ENUM_UNDERLYING_TYPE (enumtype));
|
||||
|
||||
/* Silently convert the value so that we can continue. */
|
||||
value = perform_implicit_conversion (ENUM_UNDERLYING_TYPE (enumtype),
|
||||
value, tf_none);
|
||||
if (value == error_mark_node)
|
||||
value = NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
||||
/* C++ associates enums with global, function, or class declarations. */
|
||||
context = current_scope ();
|
||||
|
||||
/* Build the actual enumeration constant. Note that the enumeration
|
||||
constants have the type of their initializers until the
|
||||
enumeration is complete:
|
||||
constants have the underlying type of the enum (if it is fixed)
|
||||
or the type of their initializer (if the underlying type of the
|
||||
enum is not fixed):
|
||||
|
||||
[ dcl.enum ]
|
||||
[ C++0x dcl.enum ]
|
||||
|
||||
Following the closing brace of an enum-specifier, each enumer-
|
||||
ator has the type of its enumeration. Prior to the closing
|
||||
brace, the type of each enumerator is the type of its
|
||||
initializing value.
|
||||
If the underlying type is fixed, the type of each enumerator
|
||||
prior to the closing brace is the underlying type; if the
|
||||
initializing value of an enumerator cannot be represented by
|
||||
the underlying type, the program is ill-formed. If the
|
||||
underlying type is not fixed, the type of each enumerator is
|
||||
the type of its initializing value.
|
||||
|
||||
In finish_enum we will reset the type. Of course, if we're
|
||||
processing a template, there may be no value. */
|
||||
If the underlying type is not fixed, it will be computed by
|
||||
finish_enum and we will reset the type of this enumerator. Of
|
||||
course, if we're processing a template, there may be no value. */
|
||||
type = value ? TREE_TYPE (value) : NULL_TREE;
|
||||
|
||||
if (context && context == current_class_type)
|
||||
|
@ -11070,6 +11155,26 @@ build_enumerator (tree name, tree value, tree enumtype)
|
|||
TYPE_VALUES (enumtype) = tree_cons (name, decl, TYPE_VALUES (enumtype));
|
||||
}
|
||||
|
||||
/* Look for an enumerator with the given NAME within the enumeration
|
||||
type ENUMTYPE. This routine is used primarily for qualified name
|
||||
lookup into an enumerator in C++0x, e.g.,
|
||||
|
||||
enum class Color { Red, Green, Blue };
|
||||
|
||||
Color color = Color::Red;
|
||||
|
||||
Returns the value corresponding to the enumerator, or
|
||||
NULL_TREE if no such enumerator was found. */
|
||||
tree
|
||||
lookup_enumerator (tree enumtype, tree name)
|
||||
{
|
||||
tree e;
|
||||
gcc_assert (enumtype && TREE_CODE (enumtype) == ENUMERAL_TYPE);
|
||||
|
||||
e = purpose_member (name, TYPE_VALUES (enumtype));
|
||||
return e? TREE_VALUE (e) : NULL_TREE;
|
||||
}
|
||||
|
||||
|
||||
/* We're defining DECL. Make sure that it's type is OK. */
|
||||
|
||||
|
|
|
@ -447,8 +447,13 @@ dump_typename (tree t, int flags)
|
|||
const char *
|
||||
class_key_or_enum_as_string (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) == ENUMERAL_TYPE)
|
||||
return "enum";
|
||||
if (TREE_CODE (t) == ENUMERAL_TYPE)
|
||||
{
|
||||
if (SCOPED_ENUM_P (t))
|
||||
return "enum class";
|
||||
else
|
||||
return "enum";
|
||||
}
|
||||
else if (TREE_CODE (t) == UNION_TYPE)
|
||||
return "union";
|
||||
else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
|
||||
|
|
|
@ -1329,7 +1329,7 @@ push_binding_level (struct cp_binding_level *scope)
|
|||
|
||||
/* Create a new KIND scope and make it the top of the active scopes stack.
|
||||
ENTITY is the scope of the associated C++ entity (namespace, class,
|
||||
function); it is NULL otherwise. */
|
||||
function, C++0x enumeration); it is NULL otherwise. */
|
||||
|
||||
cxx_scope *
|
||||
begin_scope (scope_kind kind, tree entity)
|
||||
|
@ -1364,6 +1364,7 @@ begin_scope (scope_kind kind, tree entity)
|
|||
case sk_catch:
|
||||
case sk_for:
|
||||
case sk_class:
|
||||
case sk_scoped_enum:
|
||||
case sk_function_parms:
|
||||
case sk_omp:
|
||||
scope->keep = keep_next_level_flag;
|
||||
|
@ -3853,6 +3854,8 @@ lookup_qualified_name (tree scope, tree name, bool is_type_p, bool complain)
|
|||
if (qualified_lookup_using_namespace (name, scope, &binding, flags))
|
||||
t = binding.value;
|
||||
}
|
||||
else if (cxx_dialect != cxx98 && TREE_CODE (scope) == ENUMERAL_TYPE)
|
||||
t = lookup_enumerator (scope, name);
|
||||
else if (is_class_type (scope, complain))
|
||||
t = lookup_member (scope, name, 2, is_type_p);
|
||||
|
||||
|
|
|
@ -113,6 +113,8 @@ typedef enum scope_kind {
|
|||
for-init-statement. */
|
||||
sk_function_parms, /* The scope containing function parameters. */
|
||||
sk_class, /* The scope containing the members of a class. */
|
||||
sk_scoped_enum, /* The scope containing the enumertors of a C++0x
|
||||
scoped enumeration. */
|
||||
sk_namespace, /* The scope containing the members of a
|
||||
namespace, including the global scope. */
|
||||
sk_template_parms, /* A scope for template parameters. */
|
||||
|
|
158
gcc/cp/parser.c
158
gcc/cp/parser.c
|
@ -1581,7 +1581,7 @@ static tree cp_parser_nested_name_specifier_opt
|
|||
(cp_parser *, bool, bool, bool, bool);
|
||||
static tree cp_parser_nested_name_specifier
|
||||
(cp_parser *, bool, bool, bool, bool);
|
||||
static tree cp_parser_class_or_namespace_name
|
||||
static tree cp_parser_qualifying_entity
|
||||
(cp_parser *, bool, bool, bool, bool, bool);
|
||||
static tree cp_parser_postfix_expression
|
||||
(cp_parser *, bool, bool, bool);
|
||||
|
@ -3932,10 +3932,16 @@ cp_parser_unqualified_id (cp_parser* parser,
|
|||
|
||||
/* Parse an (optional) nested-name-specifier.
|
||||
|
||||
nested-name-specifier:
|
||||
nested-name-specifier: [C++98]
|
||||
class-or-namespace-name :: nested-name-specifier [opt]
|
||||
class-or-namespace-name :: template nested-name-specifier [opt]
|
||||
|
||||
nested-name-specifier: [C++0x]
|
||||
type-name ::
|
||||
namespace-name ::
|
||||
nested-name-specifier identifier ::
|
||||
nested-name-specifier template [opt] simple-template-id ::
|
||||
|
||||
PARSER->SCOPE should be set appropriately before this function is
|
||||
called. TYPENAME_KEYWORD_P is TRUE if the `typename' keyword is in
|
||||
effect. TYPE_P is TRUE if we non-type bindings should be ignored
|
||||
|
@ -4010,7 +4016,7 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
|
|||
else
|
||||
{
|
||||
/* If the next token is not an identifier, then it is
|
||||
definitely not a class-or-namespace-name. */
|
||||
definitely not a type-name or namespace-name. */
|
||||
if (token->type != CPP_NAME)
|
||||
break;
|
||||
/* If the following token is neither a `<' (to begin a
|
||||
|
@ -4050,12 +4056,12 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
|
|||
/*only_current_p=*/false);
|
||||
/* Parse the qualifying entity. */
|
||||
new_scope
|
||||
= cp_parser_class_or_namespace_name (parser,
|
||||
typename_keyword_p,
|
||||
template_keyword_p,
|
||||
check_dependency_p,
|
||||
type_p,
|
||||
is_declaration);
|
||||
= cp_parser_qualifying_entity (parser,
|
||||
typename_keyword_p,
|
||||
template_keyword_p,
|
||||
check_dependency_p,
|
||||
type_p,
|
||||
is_declaration);
|
||||
/* Look for the `::' token. */
|
||||
cp_parser_require (parser, CPP_SCOPE, "%<::%>");
|
||||
|
||||
|
@ -4107,10 +4113,14 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
|
|||
decl = error_mark_node;
|
||||
}
|
||||
else
|
||||
cp_parser_name_lookup_error
|
||||
(parser, token->u.value, decl,
|
||||
"is not a class or namespace",
|
||||
token->location);
|
||||
{
|
||||
const char* msg = "is not a class or namespace";
|
||||
if (cxx_dialect != cxx98)
|
||||
msg = "is not a class, namespace, or enumeration";
|
||||
cp_parser_name_lookup_error
|
||||
(parser, token->u.value, decl, msg,
|
||||
token->location);
|
||||
}
|
||||
}
|
||||
parser->scope = error_mark_node;
|
||||
error_p = true;
|
||||
|
@ -4229,11 +4239,11 @@ cp_parser_nested_name_specifier (cp_parser *parser,
|
|||
return scope;
|
||||
}
|
||||
|
||||
/* Parse a class-or-namespace-name.
|
||||
|
||||
class-or-namespace-name:
|
||||
class-name
|
||||
namespace-name
|
||||
/* Parse the qualifying entity in a nested-name-specifier. For C++98,
|
||||
this is either a class-name or a namespace-name (which corresponds
|
||||
to the class-or-namespace-name production in the grammar). For
|
||||
C++0x, it can also be a type-name that refers to an enumeration
|
||||
type.
|
||||
|
||||
TYPENAME_KEYWORD_P is TRUE iff the `typename' keyword is in effect.
|
||||
TEMPLATE_KEYWORD_P is TRUE iff the `template' keyword is in effect.
|
||||
|
@ -4247,18 +4257,19 @@ cp_parser_nested_name_specifier (cp_parser *parser,
|
|||
ERROR_MARK_NODE is returned. */
|
||||
|
||||
static tree
|
||||
cp_parser_class_or_namespace_name (cp_parser *parser,
|
||||
bool typename_keyword_p,
|
||||
bool template_keyword_p,
|
||||
bool check_dependency_p,
|
||||
bool type_p,
|
||||
bool is_declaration)
|
||||
cp_parser_qualifying_entity (cp_parser *parser,
|
||||
bool typename_keyword_p,
|
||||
bool template_keyword_p,
|
||||
bool check_dependency_p,
|
||||
bool type_p,
|
||||
bool is_declaration)
|
||||
{
|
||||
tree saved_scope;
|
||||
tree saved_qualifying_scope;
|
||||
tree saved_object_scope;
|
||||
tree scope;
|
||||
bool only_class_p;
|
||||
bool successful_parse_p;
|
||||
|
||||
/* Before we try to parse the class-name, we must save away the
|
||||
current PARSER->SCOPE since cp_parser_class_name will destroy
|
||||
|
@ -4268,7 +4279,8 @@ cp_parser_class_or_namespace_name (cp_parser *parser,
|
|||
saved_object_scope = parser->object_scope;
|
||||
/* Try for a class-name first. If the SAVED_SCOPE is a type, then
|
||||
there is no need to look for a namespace-name. */
|
||||
only_class_p = template_keyword_p || (saved_scope && TYPE_P (saved_scope));
|
||||
only_class_p = template_keyword_p
|
||||
|| (saved_scope && TYPE_P (saved_scope) && cxx_dialect == cxx98);
|
||||
if (!only_class_p)
|
||||
cp_parser_parse_tentatively (parser);
|
||||
scope = cp_parser_class_name (parser,
|
||||
|
@ -4278,8 +4290,26 @@ cp_parser_class_or_namespace_name (cp_parser *parser,
|
|||
check_dependency_p,
|
||||
/*class_head_p=*/false,
|
||||
is_declaration);
|
||||
successful_parse_p = only_class_p || cp_parser_parse_definitely (parser);
|
||||
/* If that didn't work and we're in C++0x mode, try for a type-name. */
|
||||
if (!only_class_p
|
||||
&& cxx_dialect != cxx98
|
||||
&& !successful_parse_p)
|
||||
{
|
||||
/* Restore the saved scope. */
|
||||
parser->scope = saved_scope;
|
||||
parser->qualifying_scope = saved_qualifying_scope;
|
||||
parser->object_scope = saved_object_scope;
|
||||
|
||||
/* Parse tentatively. */
|
||||
cp_parser_parse_tentatively (parser);
|
||||
|
||||
/* Parse a typedef-name or enum-name. */
|
||||
scope = cp_parser_nonclass_name (parser);
|
||||
successful_parse_p = cp_parser_parse_definitely (parser);
|
||||
}
|
||||
/* If that didn't work, try for a namespace-name. */
|
||||
if (!only_class_p && !cp_parser_parse_definitely (parser))
|
||||
if (!only_class_p && !successful_parse_p)
|
||||
{
|
||||
/* Restore the saved scope. */
|
||||
parser->scope = saved_scope;
|
||||
|
@ -11307,7 +11337,7 @@ cp_parser_nonclass_name (cp_parser* parser)
|
|||
elaborated-type-specifier:
|
||||
class-key :: [opt] nested-name-specifier [opt] identifier
|
||||
class-key :: [opt] nested-name-specifier [opt] template [opt] template-id
|
||||
enum :: [opt] nested-name-specifier [opt] identifier
|
||||
enum-key :: [opt] nested-name-specifier [opt] identifier
|
||||
typename :: [opt] nested-name-specifier identifier
|
||||
typename :: [opt] nested-name-specifier template [opt]
|
||||
template-id
|
||||
|
@ -11345,6 +11375,17 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
|
|||
cp_lexer_consume_token (parser->lexer);
|
||||
/* Remember that it's an enumeration type. */
|
||||
tag_type = enum_type;
|
||||
/* Parse the optional `struct' or `class' key (for C++0x scoped
|
||||
enums). */
|
||||
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_CLASS)
|
||||
|| cp_lexer_next_token_is_keyword (parser->lexer, RID_STRUCT))
|
||||
{
|
||||
if (cxx_dialect == cxx98)
|
||||
maybe_warn_cpp0x ("scoped enums");
|
||||
|
||||
/* Consume the `struct' or `class'. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
}
|
||||
/* Parse the attributes. */
|
||||
attributes = cp_parser_attributes_opt (parser);
|
||||
}
|
||||
|
@ -11632,11 +11673,19 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
|
|||
/* Parse an enum-specifier.
|
||||
|
||||
enum-specifier:
|
||||
enum identifier [opt] { enumerator-list [opt] }
|
||||
enum-key identifier [opt] enum-base [opt] { enumerator-list [opt] }
|
||||
|
||||
enum-key:
|
||||
enum
|
||||
enum class [C++0x]
|
||||
enum struct [C++0x]
|
||||
|
||||
enum-base: [C++0x]
|
||||
: type-specifier-seq
|
||||
|
||||
GNU Extensions:
|
||||
enum attributes[opt] identifier [opt] { enumerator-list [opt] }
|
||||
attributes[opt]
|
||||
enum-key attributes[opt] identifier [opt] enum-base [opt]
|
||||
{ enumerator-list [opt] }attributes[opt]
|
||||
|
||||
Returns an ENUM_TYPE representing the enumeration, or NULL_TREE
|
||||
if the token stream isn't an enum-specifier after all. */
|
||||
|
@ -11647,6 +11696,8 @@ cp_parser_enum_specifier (cp_parser* parser)
|
|||
tree identifier;
|
||||
tree type;
|
||||
tree attributes;
|
||||
bool scoped_enum_p = false;
|
||||
tree underlying_type = NULL_TREE;
|
||||
|
||||
/* Parse tentatively so that we can back up if we don't find a
|
||||
enum-specifier. */
|
||||
|
@ -11658,6 +11709,20 @@ cp_parser_enum_specifier (cp_parser* parser)
|
|||
the enumeration being defined. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
||||
/* Parse the "class" or "struct", which indicates a scoped
|
||||
enumeration type in C++0x. */
|
||||
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_CLASS)
|
||||
|| cp_lexer_next_token_is_keyword (parser->lexer, RID_STRUCT))
|
||||
{
|
||||
if (cxx_dialect == cxx98)
|
||||
maybe_warn_cpp0x ("scoped enums");
|
||||
|
||||
/* Consume the `struct' or `class' token. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
||||
scoped_enum_p = true;
|
||||
}
|
||||
|
||||
attributes = cp_parser_attributes_opt (parser);
|
||||
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
|
||||
|
@ -11665,6 +11730,35 @@ cp_parser_enum_specifier (cp_parser* parser)
|
|||
else
|
||||
identifier = make_anon_name ();
|
||||
|
||||
/* Check for the `:' that denotes a specified underlying type in C++0x. */
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
|
||||
{
|
||||
cp_decl_specifier_seq type_specifiers;
|
||||
|
||||
if (cxx_dialect == cxx98)
|
||||
maybe_warn_cpp0x ("scoped enums");
|
||||
|
||||
/* Consume the `:'. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
||||
/* Parse the type-specifier-seq. */
|
||||
cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
|
||||
&type_specifiers);
|
||||
if (type_specifiers.type == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
/* If that didn't work, stop. */
|
||||
if (type_specifiers.type != error_mark_node)
|
||||
{
|
||||
underlying_type = grokdeclarator (NULL, &type_specifiers, TYPENAME,
|
||||
/*initialized=*/0, NULL);
|
||||
if (underlying_type == error_mark_node)
|
||||
underlying_type = NULL_TREE;
|
||||
}
|
||||
else
|
||||
cp_parser_error (parser, "expected underlying type of enumeration");
|
||||
}
|
||||
|
||||
/* Look for the `{' but don't consume it yet. */
|
||||
if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
|
||||
cp_parser_simulate_error (parser);
|
||||
|
@ -11679,7 +11773,7 @@ cp_parser_enum_specifier (cp_parser* parser)
|
|||
/* Create the new type. We do this before consuming the opening
|
||||
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 = start_enum (identifier, underlying_type, scoped_enum_p);
|
||||
|
||||
/* Consume the opening brace. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
@ -11818,7 +11912,7 @@ cp_parser_namespace_name (cp_parser* parser)
|
|||
During the lookup of a name preceding the :: scope resolution
|
||||
operator, object, function, and enumerator names are ignored.
|
||||
|
||||
(Note that cp_parser_class_or_namespace_name only calls this
|
||||
(Note that cp_parser_qualifying_entity only calls this
|
||||
function if the token after the name is the scope resolution
|
||||
operator.) */
|
||||
namespace_decl = cp_parser_lookup_name (parser, identifier,
|
||||
|
|
18
gcc/cp/pt.c
18
gcc/cp/pt.c
|
@ -5836,14 +5836,20 @@ lookup_template_class (tree d1,
|
|||
if (!is_partial_instantiation)
|
||||
{
|
||||
set_current_access_from_decl (TYPE_NAME (template_type));
|
||||
t = start_enum (TYPE_IDENTIFIER (template_type));
|
||||
t = start_enum (TYPE_IDENTIFIER (template_type),
|
||||
tsubst (ENUM_UNDERLYING_TYPE (template_type),
|
||||
arglist, complain, in_decl),
|
||||
SCOPED_ENUM_P (template_type));
|
||||
}
|
||||
else
|
||||
/* We don't want to call start_enum for this type, since
|
||||
the values for the enumeration constants may involve
|
||||
template parameters. And, no one should be interested
|
||||
in the enumeration constants for such a type. */
|
||||
t = make_node (ENUMERAL_TYPE);
|
||||
{
|
||||
/* We don't want to call start_enum for this type, since
|
||||
the values for the enumeration constants may involve
|
||||
template parameters. And, no one should be interested
|
||||
in the enumeration constants for such a type. */
|
||||
t = make_node (ENUMERAL_TYPE);
|
||||
SET_SCOPED_ENUM_P (t, SCOPED_ENUM_P (template_type));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -262,10 +262,10 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
|
|||
/* FIXME: Attributes. */
|
||||
gcc_assert (ARITHMETIC_TYPE_P (t1)
|
||||
|| TREE_CODE (t1) == VECTOR_TYPE
|
||||
|| TREE_CODE (t1) == ENUMERAL_TYPE);
|
||||
|| UNSCOPED_ENUM_P (t1));
|
||||
gcc_assert (ARITHMETIC_TYPE_P (t2)
|
||||
|| TREE_CODE (t2) == VECTOR_TYPE
|
||||
|| TREE_CODE (t2) == ENUMERAL_TYPE);
|
||||
|| UNSCOPED_ENUM_P (t2));
|
||||
|
||||
/* In what follows, we slightly generalize the rules given in [expr] so
|
||||
as to deal with `long long' and `complex'. First, merge the
|
||||
|
@ -764,9 +764,9 @@ common_type (tree t1, tree t2)
|
|||
code1 = TREE_CODE (t1);
|
||||
code2 = TREE_CODE (t2);
|
||||
|
||||
if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE
|
||||
if ((ARITHMETIC_TYPE_P (t1) || UNSCOPED_ENUM_P (t1)
|
||||
|| code1 == VECTOR_TYPE)
|
||||
&& (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE
|
||||
&& (ARITHMETIC_TYPE_P (t2) || UNSCOPED_ENUM_P (t2)
|
||||
|| code2 == VECTOR_TYPE))
|
||||
return type_after_usual_arithmetic_conversions (t1, t2);
|
||||
|
||||
|
@ -1666,7 +1666,7 @@ default_conversion (tree exp)
|
|||
/* Perform the integral promotions first so that bitfield
|
||||
expressions (which may promote to "int", even if the bitfield is
|
||||
declared "unsigned") are promoted correctly. */
|
||||
if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (exp)))
|
||||
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (exp)))
|
||||
exp = perform_integral_promotions (exp);
|
||||
/* Perform the other conversions. */
|
||||
exp = decay_conversion (exp);
|
||||
|
@ -2548,7 +2548,7 @@ build_array_ref (tree array, tree idx)
|
|||
|
||||
warn_array_subscript_with_type_char (idx);
|
||||
|
||||
if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (idx)))
|
||||
if (!INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (idx)))
|
||||
{
|
||||
error ("array subscript is not an integer");
|
||||
return error_mark_node;
|
||||
|
|
17
gcc/dbxout.c
17
gcc/dbxout.c
|
@ -2174,16 +2174,21 @@ dbxout_type (tree type, int full)
|
|||
stabstr_C ('e');
|
||||
for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem))
|
||||
{
|
||||
tree value = TREE_VALUE (tem);
|
||||
|
||||
stabstr_I (TREE_PURPOSE (tem));
|
||||
stabstr_C (':');
|
||||
|
||||
if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == 0)
|
||||
stabstr_D (TREE_INT_CST_LOW (TREE_VALUE (tem)));
|
||||
else if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == -1
|
||||
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (TREE_VALUE (tem)) < 0)
|
||||
stabstr_D (TREE_INT_CST_LOW (TREE_VALUE (tem)));
|
||||
if (TREE_CODE (value) == CONST_DECL)
|
||||
value = DECL_INITIAL (value);
|
||||
|
||||
if (TREE_INT_CST_HIGH (value) == 0)
|
||||
stabstr_D (TREE_INT_CST_LOW (value));
|
||||
else if (TREE_INT_CST_HIGH (value) == -1
|
||||
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (value) < 0)
|
||||
stabstr_D (TREE_INT_CST_LOW (value));
|
||||
else
|
||||
stabstr_O (TREE_VALUE (tem));
|
||||
stabstr_O (value);
|
||||
|
||||
stabstr_C (',');
|
||||
if (TREE_CHAIN (tem) != 0)
|
||||
|
|
25
gcc/testsuite/g++.dg/cpp0x/enum_base.C
Normal file
25
gcc/testsuite/g++.dg/cpp0x/enum_base.C
Normal file
|
@ -0,0 +1,25 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
typedef unsigned volatile long long uvlonglong;
|
||||
|
||||
enum E1 : char { };
|
||||
enum E2 : signed const short { };
|
||||
enum E3 : uvlonglong { };
|
||||
enum E4 : char {
|
||||
val = 500 // { dg-error "too large" }
|
||||
};
|
||||
|
||||
enum class E5 {
|
||||
val = (unsigned long long)-1 // { dg-error "too large" }
|
||||
};
|
||||
|
||||
typedef float Float;
|
||||
|
||||
enum class E6 : Float { }; // { dg-error "must be an integral type" }
|
||||
|
||||
static_assert (sizeof(E1) == sizeof(char), "char-sized enum");
|
||||
static_assert (sizeof(E2) == sizeof(signed short), "short-sized enum");
|
||||
static_assert (sizeof(E3) == sizeof(unsigned long long),
|
||||
"long long-sized enum");
|
||||
static_assert (sizeof(E4) == sizeof(char), "char-sized enum");
|
||||
static_assert (sizeof(E5) == sizeof(int), "scoped enum with int size");
|
25
gcc/testsuite/g++.dg/cpp0x/enum_base_warn.C
Normal file
25
gcc/testsuite/g++.dg/cpp0x/enum_base_warn.C
Normal file
|
@ -0,0 +1,25 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-O2 -Wtype-limits -std=c++0x" }
|
||||
extern void link_error (void);
|
||||
|
||||
enum Alpha : unsigned char {
|
||||
ZERO = 0, ONE, TWO, THREE
|
||||
};
|
||||
|
||||
Alpha a2;
|
||||
|
||||
int m1 = -1;
|
||||
int GetM1() {
|
||||
return m1;
|
||||
}
|
||||
|
||||
int main() {
|
||||
a2 = static_cast<Alpha>(GetM1());
|
||||
if (a2 == -1) { // { dg-warning "always false due" }
|
||||
link_error ();
|
||||
}
|
||||
if (-1 == a2) { // { dg-warning "always false due" }
|
||||
link_error ();
|
||||
}
|
||||
return 0;
|
||||
}
|
76
gcc/testsuite/g++.dg/cpp0x/scoped_enum.C
Normal file
76
gcc/testsuite/g++.dg/cpp0x/scoped_enum.C
Normal file
|
@ -0,0 +1,76 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
enum class Color1 {
|
||||
Red,
|
||||
Green,
|
||||
Blue
|
||||
};
|
||||
|
||||
enum struct Color2 {
|
||||
Red, // { dg-error "previously declared here" }
|
||||
Orange,
|
||||
Yellow,
|
||||
Green,
|
||||
Blue,
|
||||
Indigo = Green + 2,
|
||||
Violet,
|
||||
Red // { dg-error "redefinition" }
|
||||
};
|
||||
|
||||
enum Color {
|
||||
Red, Green, Blue
|
||||
};
|
||||
|
||||
enum class Color3 {
|
||||
Red
|
||||
};
|
||||
|
||||
enum class Color color;
|
||||
enum Color3 color3;
|
||||
|
||||
void f(int);
|
||||
void f2(Color3);
|
||||
|
||||
void g()
|
||||
{
|
||||
int i = 0;
|
||||
f(color); // okay: unscoped enum
|
||||
f(color3); // { dg-error "cannot convert" }
|
||||
f2(color); // { dg-error "cannot convert" }
|
||||
f2(color3);
|
||||
f2(i); // { dg-error "cannot convert" }
|
||||
i = color3; // { dg-error "cannot convert" }
|
||||
color3 = i; // { dg-error "cannot convert" }
|
||||
f(static_cast<int>(color3)); // okay
|
||||
|
||||
int a[5];
|
||||
a[color3]; // { dg-error "array subscript is not an integer" }
|
||||
|
||||
bool b = color3; // { dg-error "cannot convert" }
|
||||
}
|
||||
|
||||
void h()
|
||||
{
|
||||
Color1 c1 = Color1::Red;
|
||||
Color2 c2 = Color1::Red; // { dg-error "cannot convert" }
|
||||
c2 = Color1::Red; // { dg-error "cannot convert" }
|
||||
|
||||
c2 = Color2::Red;
|
||||
int c3 = Color::Red;
|
||||
}
|
||||
|
||||
template<typename T, T value>
|
||||
struct constant { };
|
||||
|
||||
template<typename T>
|
||||
int& sfinae(constant<T, T::Green>*);
|
||||
|
||||
float& sfinae(void*);
|
||||
|
||||
void sfinae_test()
|
||||
{
|
||||
int& test1 = sfinae((constant<Color1, Color1::Green>*)0);
|
||||
int& test2 = sfinae((constant<Color2, Color2::Green>*)0);
|
||||
float& test3 = sfinae((constant<Color1, Color1::Red>*)0);
|
||||
int& test4 = sfinae((constant<Color, Green>*)0);
|
||||
float& test5 = sfinae((constant<Color, Red>*)0);
|
||||
}
|
4
gcc/testsuite/g++.dg/cpp0x/scoped_enum_98.C
Normal file
4
gcc/testsuite/g++.dg/cpp0x/scoped_enum_98.C
Normal file
|
@ -0,0 +1,4 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-std=c++98" }
|
||||
enum class E1 { e1 }; // { dg-warning "scoped enums" }
|
||||
enum E2 : char { e2 }; // { dg-warning "scoped enums" }
|
27
gcc/testsuite/g++.dg/cpp0x/scoped_enum_examples.C
Normal file
27
gcc/testsuite/g++.dg/cpp0x/scoped_enum_examples.C
Normal file
|
@ -0,0 +1,27 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-std=c++0x" }
|
||||
enum class Col { red, yellow, green };
|
||||
|
||||
int x = Col::red; // { dg-error "cannot convert" }
|
||||
Col y = Col::red;
|
||||
|
||||
void f()
|
||||
{
|
||||
if (y) { } // { dg-error "could not convert" }
|
||||
}
|
||||
|
||||
enum direction { left='l', right='r' };
|
||||
void g() {
|
||||
// OK
|
||||
direction d;
|
||||
// OK
|
||||
d = left;
|
||||
// OK
|
||||
d = direction::right;
|
||||
}
|
||||
enum class altitude { high='h', low='l' };
|
||||
void h() {
|
||||
altitude a;
|
||||
a = high; // { dg-error "not declared in this scope" }
|
||||
a = altitude::low;
|
||||
}
|
Loading…
Add table
Reference in a new issue