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,
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)
{
......
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);
......
......@@ -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. */
......
......@@ -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;
......
......@@ -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)
......
// { 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