Commit adf2edec by Douglas Gregor Committed by Doug Gregor

c-common.c (do_switch_warnings): Look through the CONST_DECLs in the enumerators…

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
parent 54e22276
...@@ -4928,6 +4928,8 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location, ...@@ -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)) for (chain = TYPE_VALUES (type); chain; chain = TREE_CHAIN (chain))
{ {
tree value = TREE_VALUE (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); node = splay_tree_lookup (cases, (splay_tree_key) value);
if (node) if (node)
{ {
......
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> 2008-08-21 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
* typeck.c: Update all calls to pedwarn. * typeck.c: Update all calls to pedwarn.
......
...@@ -771,7 +771,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, ...@@ -771,7 +771,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
conv = build_conv (ck_std, to, conv); conv = build_conv (ck_std, to, conv);
conv->bad_p = true; 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 /* For backwards brain damage compatibility, allow interconversion of
enums and integers with a pedwarn. */ enums and integers with a pedwarn. */
...@@ -896,10 +896,11 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, ...@@ -896,10 +896,11 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
{ {
/* [conv.bool] /* [conv.bool]
An rvalue of arithmetic, enumeration, pointer, or pointer to An rvalue of arithmetic, unscoped enumeration, pointer, or
member type can be converted to an rvalue of type bool. */ pointer to member type can be converted to an rvalue of type
bool. */
if (ARITHMETIC_TYPE_P (from) if (ARITHMETIC_TYPE_P (from)
|| fcode == ENUMERAL_TYPE || UNSCOPED_ENUM_P (from)
|| fcode == POINTER_TYPE || fcode == POINTER_TYPE
|| TYPE_PTR_TO_MEMBER_P (from)) || TYPE_PTR_TO_MEMBER_P (from))
{ {
...@@ -919,7 +920,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, ...@@ -919,7 +920,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
/* As an extension, allow conversion to complex type. */ /* As an extension, allow conversion to complex type. */
else if (ARITHMETIC_TYPE_P (to)) 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; return NULL;
conv = build_conv (ck_std, to, conv); conv = build_conv (ck_std, to, conv);
...@@ -3702,9 +3704,9 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3, ...@@ -3702,9 +3704,9 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
type; the usual arithmetic conversions are performed to bring type; the usual arithmetic conversions are performed to bring
them to a common type, and the result is of that type. */ them to a common type, and the result is of that type. */
else if ((ARITHMETIC_TYPE_P (arg2_type) else if ((ARITHMETIC_TYPE_P (arg2_type)
|| TREE_CODE (arg2_type) == ENUMERAL_TYPE) || UNSCOPED_ENUM_P (arg2_type))
&& (ARITHMETIC_TYPE_P (arg3_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. */ /* In this case, there is always a common type. */
result_type = type_after_usual_arithmetic_conversions (arg2_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, ...@@ -4791,7 +4793,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
if (convs->check_narrowing) if (convs->check_narrowing)
check_narrowing (totype, expr); check_narrowing (totype, expr);
if (issue_conversion_warnings) if (issue_conversion_warnings && (complain & tf_warning))
expr = convert_and_check (totype, expr); expr = convert_and_check (totype, expr);
else else
expr = convert (totype, expr); expr = convert (totype, expr);
......
...@@ -116,7 +116,8 @@ extern void cp_cpp_error (cpp_reader *, int, ...@@ -116,7 +116,8 @@ extern void cp_cpp_error (cpp_reader *, int,
2: Unused 2: Unused
3: TYPE_FOR_JAVA. 3: TYPE_FOR_JAVA.
4: TYPE_HAS_NONTRIVIAL_DESTRUCTOR 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 6: TYPE_DEPENDENT_P_VALID
Usage of DECL_LANG_FLAG_?: Usage of DECL_LANG_FLAG_?:
...@@ -980,7 +981,7 @@ enum languages { lang_c, lang_cplusplus, lang_java }; ...@@ -980,7 +981,7 @@ enum languages { lang_c, lang_cplusplus, lang_java };
|| TREE_CODE (T) == TYPEOF_TYPE \ || TREE_CODE (T) == TYPEOF_TYPE \
|| TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \ || TREE_CODE (T) == BOUND_TEMPLATE_TEMPLATE_PARM \
|| TREE_CODE (T) == DECLTYPE_TYPE \ || 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 /* Set CLASS_TYPE_P for T to VAL. T must be a class, struct, or
union type. */ union type. */
...@@ -2688,6 +2689,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) ...@@ -2688,6 +2689,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE) \ #define INTEGRAL_OR_ENUMERATION_TYPE_P(TYPE) \
(TREE_CODE (TYPE) == ENUMERAL_TYPE || CP_INTEGRAL_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] /* [basic.fundamental]
Integral and floating types are collectively called arithmetic 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) ...@@ -2714,6 +2719,59 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|| TYPE_PTR_P (TYPE) \ || TYPE_PTR_P (TYPE) \
|| TYPE_PTRMEMFUNC_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] /* [dcl.init.aggr]
An aggregate is an array or a class with no user-declared An aggregate is an array or a class with no user-declared
...@@ -4272,9 +4330,10 @@ extern bool grok_op_properties (tree, bool); ...@@ -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 (enum tag_types, tree, tag_scope, bool);
extern tree xref_tag_from_type (tree, tree, tag_scope); extern tree xref_tag_from_type (tree, tree, tag_scope);
extern bool xref_basetypes (tree, tree); 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 finish_enum (tree);
extern void build_enumerator (tree, tree, tree); extern void build_enumerator (tree, tree, tree);
extern tree lookup_enumerator (tree, tree);
extern void start_preparsed_function (tree, tree, int); extern void start_preparsed_function (tree, tree, int);
extern int start_function (cp_decl_specifier_seq *, const cp_declarator *, tree); extern int start_function (cp_decl_specifier_seq *, const cp_declarator *, tree);
extern tree begin_function_body (void); extern tree begin_function_body (void);
......
...@@ -447,8 +447,13 @@ dump_typename (tree t, int flags) ...@@ -447,8 +447,13 @@ dump_typename (tree t, int flags)
const char * const char *
class_key_or_enum_as_string (tree t) class_key_or_enum_as_string (tree t)
{ {
if (TREE_CODE (t) == ENUMERAL_TYPE) if (TREE_CODE (t) == ENUMERAL_TYPE)
return "enum"; {
if (SCOPED_ENUM_P (t))
return "enum class";
else
return "enum";
}
else if (TREE_CODE (t) == UNION_TYPE) else if (TREE_CODE (t) == UNION_TYPE)
return "union"; return "union";
else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t)) else if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
......
...@@ -1329,7 +1329,7 @@ push_binding_level (struct cp_binding_level *scope) ...@@ -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. /* 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, 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 * cxx_scope *
begin_scope (scope_kind kind, tree entity) begin_scope (scope_kind kind, tree entity)
...@@ -1364,6 +1364,7 @@ begin_scope (scope_kind kind, tree entity) ...@@ -1364,6 +1364,7 @@ begin_scope (scope_kind kind, tree entity)
case sk_catch: case sk_catch:
case sk_for: case sk_for:
case sk_class: case sk_class:
case sk_scoped_enum:
case sk_function_parms: case sk_function_parms:
case sk_omp: case sk_omp:
scope->keep = keep_next_level_flag; scope->keep = keep_next_level_flag;
...@@ -3853,6 +3854,8 @@ lookup_qualified_name (tree scope, tree name, bool is_type_p, bool complain) ...@@ -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)) if (qualified_lookup_using_namespace (name, scope, &binding, flags))
t = binding.value; 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)) else if (is_class_type (scope, complain))
t = lookup_member (scope, name, 2, is_type_p); t = lookup_member (scope, name, 2, is_type_p);
......
...@@ -113,6 +113,8 @@ typedef enum scope_kind { ...@@ -113,6 +113,8 @@ typedef enum scope_kind {
for-init-statement. */ for-init-statement. */
sk_function_parms, /* The scope containing function parameters. */ sk_function_parms, /* The scope containing function parameters. */
sk_class, /* The scope containing the members of a class. */ 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 sk_namespace, /* The scope containing the members of a
namespace, including the global scope. */ namespace, including the global scope. */
sk_template_parms, /* A scope for template parameters. */ sk_template_parms, /* A scope for template parameters. */
......
...@@ -5836,14 +5836,20 @@ lookup_template_class (tree d1, ...@@ -5836,14 +5836,20 @@ lookup_template_class (tree d1,
if (!is_partial_instantiation) if (!is_partial_instantiation)
{ {
set_current_access_from_decl (TYPE_NAME (template_type)); 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 else
/* We don't want to call start_enum for this type, since {
the values for the enumeration constants may involve /* We don't want to call start_enum for this type, since
template parameters. And, no one should be interested the values for the enumeration constants may involve
in the enumeration constants for such a type. */ template parameters. And, no one should be interested
t = make_node (ENUMERAL_TYPE); in the enumeration constants for such a type. */
t = make_node (ENUMERAL_TYPE);
SET_SCOPED_ENUM_P (t, SCOPED_ENUM_P (template_type));
}
} }
else else
{ {
......
...@@ -262,10 +262,10 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2) ...@@ -262,10 +262,10 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
/* FIXME: Attributes. */ /* FIXME: Attributes. */
gcc_assert (ARITHMETIC_TYPE_P (t1) gcc_assert (ARITHMETIC_TYPE_P (t1)
|| TREE_CODE (t1) == VECTOR_TYPE || TREE_CODE (t1) == VECTOR_TYPE
|| TREE_CODE (t1) == ENUMERAL_TYPE); || UNSCOPED_ENUM_P (t1));
gcc_assert (ARITHMETIC_TYPE_P (t2) gcc_assert (ARITHMETIC_TYPE_P (t2)
|| TREE_CODE (t2) == VECTOR_TYPE || 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 /* In what follows, we slightly generalize the rules given in [expr] so
as to deal with `long long' and `complex'. First, merge the as to deal with `long long' and `complex'. First, merge the
...@@ -764,9 +764,9 @@ common_type (tree t1, tree t2) ...@@ -764,9 +764,9 @@ common_type (tree t1, tree t2)
code1 = TREE_CODE (t1); code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2); code2 = TREE_CODE (t2);
if ((ARITHMETIC_TYPE_P (t1) || code1 == ENUMERAL_TYPE if ((ARITHMETIC_TYPE_P (t1) || UNSCOPED_ENUM_P (t1)
|| code1 == VECTOR_TYPE) || code1 == VECTOR_TYPE)
&& (ARITHMETIC_TYPE_P (t2) || code2 == ENUMERAL_TYPE && (ARITHMETIC_TYPE_P (t2) || UNSCOPED_ENUM_P (t2)
|| code2 == VECTOR_TYPE)) || code2 == VECTOR_TYPE))
return type_after_usual_arithmetic_conversions (t1, t2); return type_after_usual_arithmetic_conversions (t1, t2);
...@@ -1666,7 +1666,7 @@ default_conversion (tree exp) ...@@ -1666,7 +1666,7 @@ default_conversion (tree exp)
/* Perform the integral promotions first so that bitfield /* Perform the integral promotions first so that bitfield
expressions (which may promote to "int", even if the bitfield is expressions (which may promote to "int", even if the bitfield is
declared "unsigned") are promoted correctly. */ 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); exp = perform_integral_promotions (exp);
/* Perform the other conversions. */ /* Perform the other conversions. */
exp = decay_conversion (exp); exp = decay_conversion (exp);
...@@ -2548,7 +2548,7 @@ build_array_ref (tree array, tree idx) ...@@ -2548,7 +2548,7 @@ build_array_ref (tree array, tree idx)
warn_array_subscript_with_type_char (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"); error ("array subscript is not an integer");
return error_mark_node; return error_mark_node;
......
...@@ -2174,16 +2174,21 @@ dbxout_type (tree type, int full) ...@@ -2174,16 +2174,21 @@ dbxout_type (tree type, int full)
stabstr_C ('e'); stabstr_C ('e');
for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem))
{ {
tree value = TREE_VALUE (tem);
stabstr_I (TREE_PURPOSE (tem)); stabstr_I (TREE_PURPOSE (tem));
stabstr_C (':'); stabstr_C (':');
if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == 0) if (TREE_CODE (value) == CONST_DECL)
stabstr_D (TREE_INT_CST_LOW (TREE_VALUE (tem))); value = DECL_INITIAL (value);
else if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == -1
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (TREE_VALUE (tem)) < 0) if (TREE_INT_CST_HIGH (value) == 0)
stabstr_D (TREE_INT_CST_LOW (TREE_VALUE (tem))); 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 else
stabstr_O (TREE_VALUE (tem)); stabstr_O (value);
stabstr_C (','); stabstr_C (',');
if (TREE_CHAIN (tem) != 0) if (TREE_CHAIN (tem) != 0)
......
// { 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");
// { 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;
}
// { 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);
}
// { dg-do compile }
// { dg-options "-std=c++98" }
enum class E1 { e1 }; // { dg-warning "scoped enums" }
enum E2 : char { e2 }; // { dg-warning "scoped enums" }
// { 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment