From patchwork Wed Jul 20 14:29:02 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 105697 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 25C2FB6F7A for ; Thu, 21 Jul 2011 00:29:32 +1000 (EST) Received: (qmail 6090 invoked by alias); 20 Jul 2011 14:29:30 -0000 Received: (qmail 6075 invoked by uid 22791); 20 Jul 2011 14:29:28 -0000 X-SWARE-Spam-Status: No, hits=-7.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 20 Jul 2011 14:29:06 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p6KET54d004317 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 20 Jul 2011 10:29:05 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p6KET587011900 for ; Wed, 20 Jul 2011 10:29:05 -0400 Received: from [0.0.0.0] ([10.3.113.11]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p6KET33U028966 for ; Wed, 20 Jul 2011 10:29:04 -0400 Message-ID: <4E26E62E.1050305@redhat.com> Date: Wed, 20 Jul 2011 10:29:02 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18) Gecko/20110621 Fedora/3.1.11-1.fc14 Lightning/1.0b2 Thunderbird/3.1.11 MIME-Version: 1.0 To: gcc-patches List Subject: C++ PATCH for c++/42603 and c++/6709 (DR 743/950, allow decltype as base-specifier and nested-name-specifier) Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org DRs 743 and 950 allow decltype to be used as the scope in a nested-name-specifier and as a base-specifier. This patch implements that functionality. In order to deal with the ambiguity when we first encounter "decltype" as to whether it will be a nested-name-specifier or its own simple-type-specifier, we now cache the result of parsing in a new CPP_DECLTYPE token type so that we don't need to parse it a second time if it turns out not to be a nested-name-specifier. Tested x86_64-pc-linux-gnu, applying to trunk. commit 5df8e39edd7a6e9e45de4484a0cb0b7f598bdadf Author: Jason Merrill Date: Fri Jan 15 14:20:08 2010 -0500 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. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index ecb0c84..6078d94 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 a80c0ea..13aae0f 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/parser.c b/gcc/cp/parser.c index b928ef7..b8dc48e 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 31ff0d9..33582fb 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/g++.dg/cpp0x/decltype21.C b/gcc/testsuite/g++.dg/cpp0x/decltype21.C new file mode 100644 index 0000000..ee73bfb --- /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" }