===================================================================
@@ -11331,27 +11331,48 @@ xref_basetypes (tree ref, tree base_list)
may be used to declare the individual values as they are read. */
tree
-start_enum (tree name, tree underlying_type, bool scoped_enum_p)
+start_enum (tree name, tree enumtype, tree underlying_type, bool scoped_enum_p)
{
- tree enumtype;
-
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
+ /* [C++0x dcl.enum]p5:
+
+ If not explicitly specified, the underlying type of a scoped
+ enumeration type is int. */
+ if (!underlying_type && scoped_enum_p)
+ underlying_type = integer_type_node;
+
/* If this is the real definition for a previous forward reference,
fill in the contents in the same object that used to be the
forward reference. */
-
- enumtype = lookup_and_check_tag (enum_type, name,
- /*tag_scope=*/ts_current,
- /*template_header_p=*/false);
-
+ if (!enumtype)
+ enumtype = lookup_and_check_tag (enum_type, name,
+ /*tag_scope=*/ts_current,
+ /*template_header_p=*/false);
if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
{
- error_at (input_location, "multiple definition of %q#T", enumtype);
- error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)),
- "previous definition here");
- /* Clear out TYPE_VALUES, and start again. */
- TYPE_VALUES (enumtype) = NULL_TREE;
+ if (scoped_enum_p != SCOPED_ENUM_P (enumtype))
+ {
+ error_at (input_location, "scoped/unscoped mismatch in enum %q#T", enumtype);
+ error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)),
+ "previous definition here");
+ }
+ if (!underlying_type
+ || !same_type_p (underlying_type, ENUM_UNDERLYING_TYPE (enumtype)))
+ {
+ error_at (input_location, "different underlying type in enum %q#T", enumtype);
+ error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)),
+ "previous definition here");
+ }
+
+ if (cxx_dialect == cxx98)
+ {
+ error_at (input_location, "multiple definition of %q#T", enumtype);
+ error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)),
+ "previous definition here");
+ /* Clear out TYPE_VALUES, and start again. */
+ TYPE_VALUES (enumtype) = NULL_TREE;
+ }
}
else
{
@@ -11367,19 +11388,8 @@ tree
if (enumtype == error_mark_node)
return enumtype;
- if (scoped_enum_p)
- {
- SET_SCOPED_ENUM_P (enumtype, 1);
- begin_scope (sk_scoped_enum, enumtype);
+ SET_SCOPED_ENUM_P (enumtype, scoped_enum_p);
- /* [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))
@@ -11435,8 +11445,6 @@ finish_enum (tree enumtype)
TREE_TYPE (TREE_VALUE (values)) = enumtype;
if (at_function_scope_p ())
add_stmt (build_min (TAG_DEFN, enumtype));
- if (SCOPED_ENUM_P (enumtype))
- finish_scope ();
return;
}
@@ -11625,10 +11633,6 @@ finish_enum (tree 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 ());
}
===================================================================
@@ -6654,7 +6654,7 @@ lookup_template_class (tree d1,
if (!is_dependent_type)
{
set_current_access_from_decl (TYPE_NAME (template_type));
- t = start_enum (TYPE_IDENTIFIER (template_type),
+ t = start_enum (TYPE_IDENTIFIER (template_type), NULL_TREE,
tsubst (ENUM_UNDERLYING_TYPE (template_type),
arglist, complain, in_decl),
SCOPED_ENUM_P (template_type));
@@ -17292,6 +17292,9 @@ static void
tsubst_enum (tree tag, tree newtag, tree args)
{
tree e;
+
+ if (SCOPED_ENUM_P (newtag))
+ begin_scope (sk_scoped_enum, newtag);
for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e))
{
@@ -17313,6 +17316,9 @@ tsubst_enum (tree tag, tree newtag, tree args)
(DECL_NAME (decl), value, newtag, DECL_SOURCE_LOCATION (decl));
}
+ if (SCOPED_ENUM_P (newtag))
+ finish_scope ();
+
finish_enum (newtag);
DECL_SOURCE_LOCATION (TYPE_NAME (newtag))
= DECL_SOURCE_LOCATION (TYPE_NAME (tag));
===================================================================
@@ -13212,10 +13204,13 @@ static tree
cp_parser_enum_specifier (cp_parser* parser)
{
tree identifier;
- tree type;
+ tree type = NULL_TREE;
+ tree nested_name_specifier;
tree attributes;
bool scoped_enum_p = false;
bool has_underlying_type = false;
+ bool nested_being_defined = false;
+ bool must_finish = true;
tree underlying_type = NULL_TREE;
/* Parse tentatively so that we can back up if we don't find a
@@ -13244,10 +13239,36 @@ cp_parser_enum_specifier (cp_parser* parser)
attributes = cp_parser_attributes_opt (parser);
- if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
- identifier = cp_parser_identifier (parser);
+ push_deferring_access_checks (dk_no_check);
+ nested_name_specifier
+ = cp_parser_nested_name_specifier_opt (parser,
+ /*typename_keyword_p=*/false,
+ /*check_dependency_p=*/false,
+ /*type_p=*/false,
+ /*is_declaration=*/false);
+
+ if (nested_name_specifier)
+ {
+ tree name;
+ identifier = cp_parser_identifier (parser);
+ name = cp_parser_lookup_name (parser, identifier,
+ enum_type,
+ /*is_template=*/false,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true,
+ /*ambiguous_decls=*/NULL,
+ input_location);
+ if (name)
+ type = TREE_TYPE (name);
+ }
else
- identifier = make_anon_name ();
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ identifier = cp_parser_identifier (parser);
+ else
+ identifier = make_anon_name ();
+ }
+ pop_deferring_access_checks ();
/* Check for the `:' that denotes a specified underlying type in C++0x.
Note that a ':' could also indicate a bitfield width, however. */
@@ -13285,14 +13306,31 @@ cp_parser_enum_specifier (cp_parser* parser)
/* Look for the `{' but don't consume it yet. */
if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
- cp_parser_error (parser, "expected %<{%>");
- if (has_underlying_type)
- return NULL_TREE;
+ if (cxx_dialect == cxx98 || (!scoped_enum_p && !underlying_type))
+ {
+ cp_parser_error (parser, "expected %<{%>");
+ if (has_underlying_type)
+ return NULL_TREE;
+ }
}
if (!has_underlying_type && !cp_parser_parse_definitely (parser))
return NULL_TREE;
+ if (nested_name_specifier && !scoped_enum_p)
+ {
+ if (CLASS_TYPE_P (nested_name_specifier))
+ {
+ nested_being_defined = TYPE_BEING_DEFINED (nested_name_specifier);
+ TYPE_BEING_DEFINED (nested_name_specifier) = 1;
+ push_scope (nested_name_specifier);
+ }
+ else if ( TREE_CODE(nested_name_specifier) == NAMESPACE_DECL)
+ {
+ push_nested_namespace (nested_name_specifier);
+ }
+ }
+
/* Issue an error message if type-definitions are forbidden here. */
if (!cp_parser_check_type_definition (parser))
type = error_mark_node;
@@ -13300,24 +13338,49 @@ 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, underlying_type, scoped_enum_p);
-
- /* Consume the opening brace. */
- cp_lexer_consume_token (parser->lexer);
+ type = start_enum (identifier, type, underlying_type, scoped_enum_p);
- if (type == error_mark_node)
+ /* If the next token is not '{' it is an opaque enum. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
- cp_parser_skip_to_end_of_block_or_statement (parser);
- return error_mark_node;
- }
+ if (scoped_enum_p)
+ begin_scope (sk_scoped_enum, type);
- /* If the next token is not '}', then there are some enumerators. */
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
- cp_parser_enumerator_list (parser, type);
+ /* Consume the opening brace. */
+ cp_lexer_consume_token (parser->lexer);
- /* Consume the final '}'. */
- cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+ if (ENUM_HAS_VALUE_LIST_P (type))
+ {
+ error_at (input_location, "multiple definition of %q#T", type);
+ error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
+ "previous definition here");
+ type = error_mark_node;
+ }
+ else
+ ENUM_HAS_VALUE_LIST_P (type) = true;
+ if (type == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ must_finish = false;
+ }
+ /* If the next token is not '}', then there are some enumerators. */
+ else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
+ cp_parser_enumerator_list (parser, type);
+
+ /* Consume the final '}'. */
+ cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+
+ if (scoped_enum_p)
+ finish_scope ();
+ }
+ else
+ {
+ /* If this enum has value list from a previous declaration, then it has already
+ been finished. Do not do it again. */
+ must_finish = !ENUM_HAS_VALUE_LIST_P (type);
+ }
+
/* Look for trailing attributes to apply to this enumeration, and
apply them if appropriate. */
if (cp_parser_allow_gnu_extensions_p (parser))
@@ -13330,8 +13393,21 @@ cp_parser_enum_specifier (cp_parser* parser)
}
/* Finish up the enumeration. */
- finish_enum (type);
+ if (must_finish)
+ finish_enum (type);
+ if (nested_name_specifier && !scoped_enum_p)
+ {
+ if (CLASS_TYPE_P (nested_name_specifier))
+ {
+ TYPE_BEING_DEFINED (nested_name_specifier) = nested_being_defined;
+ pop_scope (nested_name_specifier);
+ }
+ else if ( TREE_CODE(nested_name_specifier) == NAMESPACE_DECL)
+ {
+ pop_nested_namespace (nested_name_specifier);
+ }
+ }
return type;
}
===================================================================
@@ -3102,6 +3102,8 @@ more_aggr_init_expr_args_p (const aggr_init_expr_a
#define SET_SCOPED_ENUM_P(TYPE, VAL) \
(ENUM_IS_SCOPED (TYPE) = (VAL))
+#define ENUM_HAS_VALUE_LIST_P(NODE) (TYPE_LANG_FLAG_2 (NODE))
+
/* Returns the underlying type of the given enumeration type. The
underlying type is determined in different ways, depending on the
properties of the enum:
@@ -4778,7 +4780,7 @@ 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, tree, bool);
+extern tree start_enum (tree, tree, tree, bool);
extern void finish_enum (tree);
extern void build_enumerator (tree, tree, tree, location_t);
extern tree lookup_enumerator (tree, tree);