From 34429675140b34e3d1c9f4ccb1021d15cb92edb5 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 20 Jul 2011 10:21:05 -0400 Subject: [PATCH] PR c++/6709 (DR 743) PR c++/6709 (DR 743) PR c++/42603 (DR 950) gcc/cp/ * parser.c (token_is_decltype, cp_lexer_next_token_is_decltype): New. (cp_parser_nested_name_specifier_opt): Allow decltype. (cp_parser_qualifying_entity): Likewise. (cp_parser_decltype): Replace source tokens with CPP_DECLTYPE. (cp_parser_simple_type_specifier): Handle decltype as scope. (cp_parser_base_specifier): Allow decltype. (cp_parser_base_clause): Don't crash on null base. * parser.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move to c-common.h. (CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise. gcc/c-family/ * c-common.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move from cp/parser.h. (CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise. (CPP_DECLTYPE): New. * c-common.c (c_parse_error): Handle CPP_DECLTYPE. From-SVN: r176513 --- gcc/c-family/ChangeLog | 9 ++ gcc/c-family/c-common.c | 2 + gcc/c-family/c-common.h | 24 ++++ gcc/cp/ChangeLog | 14 ++- gcc/cp/parser.c | 142 +++++++++++++++++++----- gcc/cp/parser.h | 19 ---- gcc/testsuite/ChangeLog | 6 + gcc/testsuite/g++.dg/cpp0x/decltype21.C | 18 +++ 8 files changed, 185 insertions(+), 49 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype21.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 9ff311c90bb..c5f2306ca62 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,12 @@ +2011-07-20 Jason Merrill + + PR c++/6709 (DR 743) + PR c++/42603 (DR 950) + * c-common.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move from cp/parser.h. + (CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise. + (CPP_DECLTYPE): New. + * c-common.c (c_parse_error): Handle CPP_DECLTYPE. + 2011-07-19 Richard Guenther * c-common.c (pointer_int_sum): Use fold_build_pointer_plus. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index ecb0c8463e7..6078d948ae4 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -8329,6 +8329,8 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type, message = catenate_messages (gmsgid, " before %<#pragma%>"); else if (token_type == CPP_PRAGMA_EOL) message = catenate_messages (gmsgid, " before end of line"); + else if (token_type == CPP_DECLTYPE) + message = catenate_messages (gmsgid, " before %"); else if (token_type < N_TTYPES) { message = catenate_messages (gmsgid, " before %qs token"); diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index a80c0eaec40..13aae0f3ecc 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -320,6 +320,30 @@ struct c_common_resword const unsigned int disable : 16; }; +/* Extra cpp_ttype values for C++. */ + +/* A token type for keywords, as opposed to ordinary identifiers. */ +#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1)) + +/* A token type for template-ids. If a template-id is processed while + parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token; + the value of the CPP_TEMPLATE_ID is whatever was returned by + cp_parser_template_id. */ +#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1)) + +/* A token type for nested-name-specifiers. If a + nested-name-specifier is processed while parsing tentatively, it is + replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the + CPP_NESTED_NAME_SPECIFIER is whatever was returned by + cp_parser_nested_name_specifier_opt. */ +#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1)) + +/* A token type for pre-parsed C++0x decltype. */ +#define CPP_DECLTYPE ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1)) + +/* The number of token types, including C++-specific ones. */ +#define N_CP_TTYPES ((int) (CPP_DECLTYPE + 1)) + /* Disable mask. Keywords are disabled if (reswords[i].disable & mask) is _true_. Thus for keywords which are present in all languages the disable field is zero. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2f5be0ac1e5..37fa0522fc7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,4 +1,16 @@ -2011-07-19 Jason Merrill +2011-07-20 Jason Merrill + + PR c++/6709 (DR 743) + PR c++/42603 (DR 950) + * parser.c (token_is_decltype, cp_lexer_next_token_is_decltype): New. + (cp_parser_nested_name_specifier_opt): Allow decltype. + (cp_parser_qualifying_entity): Likewise. + (cp_parser_decltype): Replace source tokens with CPP_DECLTYPE. + (cp_parser_simple_type_specifier): Handle decltype as scope. + (cp_parser_base_specifier): Allow decltype. + (cp_parser_base_clause): Don't crash on null base. + * parser.h (CPP_KEYWORD, CPP_TEMPLATE_ID): Move to c-common.h. + (CPP_NESTED_NAME_SPECIFIER, N_CP_TTYPES): Likewise. PR c++/49785 * pt.c (coerce_template_parms): Handle non-pack after pack. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b928ef73497..b8dc48e04ca 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -663,6 +663,24 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer) } } +/* Returns TRUE iff the token T begins a decltype type. */ + +static bool +token_is_decltype (cp_token *t) +{ + return (t->keyword == RID_DECLTYPE + || t->type == CPP_DECLTYPE); +} + +/* Returns TRUE iff the next token begins a decltype type. */ + +static bool +cp_lexer_next_token_is_decltype (cp_lexer *lexer) +{ + cp_token *t = cp_lexer_peek_token (lexer); + return token_is_decltype (t); +} + /* Return a pointer to the Nth token in the token stream. If N is 1, then this is precisely equivalent to cp_lexer_peek_token (except that it is not inline). One would like to disallow that case, but @@ -4313,6 +4331,9 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, /* A template-id can start a nested-name-specifier. */ else if (token->type == CPP_TEMPLATE_ID) ; + /* DR 743: decltype can be used in a nested-name-specifier. */ + else if (token_is_decltype (token)) + ; else { /* If the next token is not an identifier, then it is @@ -4386,6 +4407,28 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser, class-or-namespace-name. */ parser->scope = old_scope; parser->qualifying_scope = saved_qualifying_scope; + + /* If the next token is a decltype, and the one after that is a + `::', then the decltype has failed to resolve to a class or + enumeration type. Give this error even when parsing + tentatively since it can't possibly be valid--and we're going + to replace it with a CPP_NESTED_NAME_SPECIFIER below, so we + won't get another chance.*/ + if (cp_lexer_next_token_is (parser->lexer, CPP_DECLTYPE) + && (cp_lexer_peek_nth_token (parser->lexer, 2)->type + == CPP_SCOPE)) + { + token = cp_lexer_consume_token (parser->lexer); + error_at (token->location, "decltype evaluates to %qT, " + "which is not a class or enumeration type", + token->u.value); + parser->scope = error_mark_node; + error_p = true; + /* As below. */ + success = true; + cp_lexer_consume_token (parser->lexer); + } + if (cp_parser_uncommitted_to_tentative_parse_p (parser)) break; /* If the next token is an identifier, and the one after @@ -4585,6 +4628,19 @@ cp_parser_qualifying_entity (cp_parser *parser, bool only_class_p; bool successful_parse_p; + /* DR 743: decltype can appear in a nested-name-specifier. */ + if (cp_lexer_next_token_is_decltype (parser->lexer)) + { + scope = cp_parser_decltype (parser); + if (TREE_CODE (scope) != ENUMERAL_TYPE + && !MAYBE_CLASS_TYPE_P (scope)) + { + cp_parser_simulate_error (parser); + return error_mark_node; + } + return TYPE_NAME (scope); + } + /* Before we try to parse the class-name, we must save away the current PARSER->SCOPE since cp_parser_class_name will destroy it. */ @@ -10197,6 +10253,14 @@ cp_parser_decltype (cp_parser *parser) bool saved_integral_constant_expression_p; bool saved_non_integral_constant_expression_p; cp_token *id_expr_start_token; + cp_token *start_token = cp_lexer_peek_token (parser->lexer); + + if (start_token->type == CPP_DECLTYPE) + { + /* Already parsed. */ + cp_lexer_consume_token (parser->lexer); + return start_token->u.value; + } /* Look for the `decltype' token. */ if (!cp_parser_require_keyword (parser, RID_DECLTYPE, RT_DECLTYPE)) @@ -10350,14 +10414,6 @@ cp_parser_decltype (cp_parser *parser) parser->non_integral_constant_expression_p = saved_non_integral_constant_expression_p; - if (expr == error_mark_node) - { - /* Skip everything up to the closing `)'. */ - cp_parser_skip_to_closing_parenthesis (parser, true, false, - /*consume_paren=*/true); - return error_mark_node; - } - /* Parse to the closing `)'. */ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) { @@ -10366,8 +10422,17 @@ cp_parser_decltype (cp_parser *parser) return error_mark_node; } - return finish_decltype_type (expr, id_expression_or_member_access_p, + expr = finish_decltype_type (expr, id_expression_or_member_access_p, tf_warning_or_error); + + /* Replace the decltype with a CPP_DECLTYPE so we don't need to parse + it again. */ + start_token->type = CPP_DECLTYPE; + start_token->u.value = expr; + start_token->keyword = RID_MAX; + cp_lexer_purge_tokens_after (parser->lexer, start_token); + + return expr; } /* Special member functions [gram.special] */ @@ -12679,15 +12744,13 @@ cp_parser_simple_type_specifier (cp_parser* parser, break; case RID_DECLTYPE: - /* Parse the `decltype' type. */ - type = cp_parser_decltype (parser); - - if (decl_specs) - cp_parser_set_decl_spec_type (decl_specs, type, - token->location, - /*user_defined_p=*/true); - - return type; + /* Since DR 743, decltype can either be a simple-type-specifier by + itself or begin a nested-name-specifier. Parsing it will replace + it with a CPP_DECLTYPE, so just rewind and let the CPP_DECLTYPE + handling below decide what to do. */ + cp_parser_decltype (parser); + cp_lexer_set_token_position (parser->lexer, token); + break; case RID_TYPEOF: /* Consume the `typeof' token. */ @@ -12719,6 +12782,20 @@ cp_parser_simple_type_specifier (cp_parser* parser, break; } + /* If token is an already-parsed decltype not followed by ::, + it's a simple-type-specifier. */ + if (token->type == CPP_DECLTYPE + && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE) + { + type = token->u.value; + if (decl_specs) + cp_parser_set_decl_spec_type (decl_specs, type, + token->location, + /*user_defined_p=*/true); + cp_lexer_consume_token (parser->lexer); + return type; + } + /* If the type-specifier was for a built-in type, we're done. */ if (type) { @@ -18232,12 +18309,11 @@ cp_parser_base_clause (cp_parser* parser) } /* Add BASE to the front of the list. */ - if (base != error_mark_node) + if (base && base != error_mark_node) { if (pack_expansion_p) /* Make this a pack expansion type. */ TREE_VALUE (base) = make_pack_expansion (TREE_VALUE (base)); - if (!check_for_bare_parameter_packs (TREE_VALUE (base))) { @@ -18379,19 +18455,27 @@ cp_parser_base_specifier (cp_parser* parser) class_scope_p = (parser->scope && TYPE_P (parser->scope)); template_p = class_scope_p && cp_parser_optional_template_keyword (parser); - /* Finally, look for the class-name. */ - type = cp_parser_class_name (parser, - class_scope_p, - template_p, - typename_type, - /*check_dependency_p=*/true, - /*class_head_p=*/false, - /*is_declaration=*/true); + if (!parser->scope + && cp_lexer_next_token_is_decltype (parser->lexer)) + /* DR 950 allows decltype as a base-specifier. */ + type = cp_parser_decltype (parser); + else + { + /* Otherwise, look for the class-name. */ + type = cp_parser_class_name (parser, + class_scope_p, + template_p, + typename_type, + /*check_dependency_p=*/true, + /*class_head_p=*/false, + /*is_declaration=*/true); + type = TREE_TYPE (type); + } if (type == error_mark_node) return error_mark_node; - return finish_base_specifier (TREE_TYPE (type), access, virtual_p); + return finish_base_specifier (type, access, virtual_p); } /* Exception handling [gram.exception] */ diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 31ff0d9f2b9..33582fbc0f1 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -23,25 +23,6 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "c-family/c-pragma.h" -/* A token type for keywords, as opposed to ordinary identifiers. */ -#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1)) - -/* A token type for template-ids. If a template-id is processed while - parsing tentatively, it is replaced with a CPP_TEMPLATE_ID token; - the value of the CPP_TEMPLATE_ID is whatever was returned by - cp_parser_template_id. */ -#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1)) - -/* A token type for nested-name-specifiers. If a - nested-name-specifier is processed while parsing tentatively, it is - replaced with a CPP_NESTED_NAME_SPECIFIER token; the value of the - CPP_NESTED_NAME_SPECIFIER is whatever was returned by - cp_parser_nested_name_specifier_opt. */ -#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1)) - -/* The number of token types, including C++-specific ones. */ -#define N_CP_TTYPES ((int) (CPP_NESTED_NAME_SPECIFIER + 1)) - /* A token's value and its associated deferred access checks and qualifying scope. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1e2bc1c07cd..faa412beca0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-07-19 Jason Merrill + + PR c++/6709 (DR 743) + PR c++/42603 (DR 950) + * g++.dg/cpp0x/decltype21.C: New. + 2011-07-20 Richard Guenther PR middle-end/18908 diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype21.C b/gcc/testsuite/g++.dg/cpp0x/decltype21.C new file mode 100644 index 00000000000..ee73bfbc36c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype21.C @@ -0,0 +1,18 @@ +// PR c++/6709 (DR 743) +// PR c++/42603 (DR 950) +// { dg-options -std=c++0x } + +template +T make(); + +struct p { typedef int t; }; +struct c : decltype(make

()) {}; + +decltype(make

())::t t; + +int f(); +decltype(f())::t t2; // { dg-error "not a class" } + +struct D: decltype(f()) { }; // { dg-error "not a class" } + +// { dg-prune-output "expected initializer" } -- 2.30.2