aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-07-20 10:21:05 -0400
committerJason Merrill <jason@gcc.gnu.org>2011-07-20 10:21:05 -0400
commit34429675140b34e3d1c9f4ccb1021d15cb92edb5 (patch)
tree9e56cc48852c32e97103a681ceb85db78262ad17 /gcc
parentff3ac0f47166f4ef3c6a22623bfadba6e419dbb1 (diff)
downloadgcc-34429675140b34e3d1c9f4ccb1021d15cb92edb5.zip
gcc-34429675140b34e3d1c9f4ccb1021d15cb92edb5.tar.gz
gcc-34429675140b34e3d1c9f4ccb1021d15cb92edb5.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c-family/ChangeLog9
-rw-r--r--gcc/c-family/c-common.c2
-rw-r--r--gcc/c-family/c-common.h24
-rw-r--r--gcc/cp/ChangeLog14
-rw-r--r--gcc/cp/parser.c142
-rw-r--r--gcc/cp/parser.h19
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/decltype21.C18
8 files changed, 185 insertions, 49 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 9ff311c..c5f2306 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,12 @@
+2011-07-20 Jason Merrill <jason@redhat.com>
+
+ 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 <rguenther@suse.de>
* 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 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 %<decltype%>");
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/ChangeLog b/gcc/cp/ChangeLog
index 2f5be0a..37fa052 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,4 +1,16 @@
-2011-07-19 Jason Merrill <jason@redhat.com>
+2011-07-20 Jason Merrill <jason@redhat.com>
+
+ 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 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/ChangeLog b/gcc/testsuite/ChangeLog
index 1e2bc1c..faa412b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2011-07-19 Jason Merrill <jason@redhat.com>
+
+ PR c++/6709 (DR 743)
+ PR c++/42603 (DR 950)
+ * g++.dg/cpp0x/decltype21.C: New.
+
2011-07-20 Richard Guenther <rguenther@suse.de>
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 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 <class T>
+T make();
+
+struct p { typedef int t; };
+struct c : decltype(make<p>()) {};
+
+decltype(make<p>())::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" }