aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c201
1 files changed, 197 insertions, 4 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index b8d2b15..a7190cb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -577,6 +577,8 @@ cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
/* GNU extensions. */
case RID_ATTRIBUTE:
case RID_TYPEOF:
+ /* C++0x extensions. */
+ case RID_DECLTYPE:
return true;
default:
@@ -1582,7 +1584,7 @@ static tree cp_parser_nested_name_specifier
static tree cp_parser_class_or_namespace_name
(cp_parser *, bool, bool, bool, bool, bool);
static tree cp_parser_postfix_expression
- (cp_parser *, bool, bool);
+ (cp_parser *, bool, bool, bool);
static tree cp_parser_postfix_open_square_expression
(cp_parser *, tree, bool);
static tree cp_parser_postfix_dot_deref_expression
@@ -1707,6 +1709,8 @@ static void cp_parser_linkage_specification
(cp_parser *);
static void cp_parser_static_assert
(cp_parser *, bool);
+static tree cp_parser_decltype
+ (cp_parser *);
/* Declarators [gram.dcl.decl] */
@@ -4254,15 +4258,20 @@ cp_parser_class_or_namespace_name (cp_parser *parser,
`&' operator. CAST_P is true if this expression is the target of a
cast.
+ If MEMBER_ACCESS_ONLY_P, we only allow postfix expressions that are
+ class member access expressions [expr.ref].
+
Returns a representation of the expression. */
static tree
-cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
+cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
+ bool member_access_only_p)
{
cp_token *token;
enum rid keyword;
cp_id_kind idk = CP_ID_KIND_NONE;
tree postfix_expression = NULL_TREE;
+ bool is_member_access = false;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
@@ -4513,6 +4522,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
postfix_expression,
false);
idk = CP_ID_KIND_NONE;
+ is_member_access = false;
break;
case CPP_OPEN_PAREN:
@@ -4524,6 +4534,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
bool saved_non_integral_constant_expression_p = false;
tree args;
+ is_member_access = false;
+
is_builtin_constant_p
= DECL_IS_BUILTIN_CONSTANT_P (postfix_expression);
if (is_builtin_constant_p)
@@ -4669,6 +4681,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
= cp_parser_postfix_dot_deref_expression (parser, token->type,
postfix_expression,
false, &idk);
+
+ is_member_access = true;
break;
case CPP_PLUS_PLUS:
@@ -4684,6 +4698,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
"an increment"))
postfix_expression = error_mark_node;
idk = CP_ID_KIND_NONE;
+ is_member_access = false;
break;
case CPP_MINUS_MINUS:
@@ -4699,10 +4714,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
"a decrement"))
postfix_expression = error_mark_node;
idk = CP_ID_KIND_NONE;
+ is_member_access = false;
break;
default:
- return postfix_expression;
+ if (member_access_only_p)
+ return is_member_access? postfix_expression : error_mark_node;
+ else
+ return postfix_expression;
}
}
@@ -5341,7 +5360,8 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p)
return expression;
}
- return cp_parser_postfix_expression (parser, address_p, cast_p);
+ return cp_parser_postfix_expression (parser, address_p, cast_p,
+ /*member_access_only_p=*/false);
}
/* Returns ERROR_MARK if TOKEN is not a unary-operator. If TOKEN is a
@@ -8371,6 +8391,164 @@ cp_parser_static_assert(cp_parser *parser, bool member_p)
finish_static_assert (condition, message, saved_loc, member_p);
}
+/* Parse a `decltype' type. Returns the type.
+
+ simple-type-specifier:
+ decltype ( expression ) */
+
+static tree
+cp_parser_decltype (cp_parser *parser)
+{
+ tree expr;
+ bool id_expression_or_member_access_p = false;
+ const char *saved_message;
+ bool saved_integral_constant_expression_p;
+ bool saved_non_integral_constant_expression_p;
+
+ /* Look for the `decltype' token. */
+ if (!cp_parser_require_keyword (parser, RID_DECLTYPE, "`decltype'"))
+ return error_mark_node;
+
+ /* Types cannot be defined in a `decltype' expression. Save away the
+ old message. */
+ saved_message = parser->type_definition_forbidden_message;
+
+ /* And create the new one. */
+ parser->type_definition_forbidden_message
+ = "types may not be defined in `decltype' expressions";
+
+ /* The restrictions on constant-expressions do not apply inside
+ decltype expressions. */
+ saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
+ parser->integral_constant_expression_p = false;
+
+ /* Do not actually evaluate the expression. */
+ ++skip_evaluation;
+
+ /* Parse the opening `('. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+
+ /* First, try parsing an id-expression. */
+ cp_parser_parse_tentatively (parser);
+ expr = cp_parser_id_expression (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/false,
+ /*optional_p=*/false);
+
+ if (!cp_parser_error_occurred (parser) && expr != error_mark_node)
+ {
+ bool non_integral_constant_expression_p = false;
+ tree id_expression = expr;
+ cp_id_kind idk;
+ const char *error_msg;
+
+ /* Lookup the name we got back from the id-expression. */
+ expr = cp_parser_lookup_name (parser, expr,
+ none_type,
+ /*is_template=*/false,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true,
+ /*ambiguous_decls=*/NULL);
+
+ if (expr
+ && expr != error_mark_node
+ && TREE_CODE (expr) != TEMPLATE_ID_EXPR
+ && TREE_CODE (expr) != TYPE_DECL
+ && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
+ {
+ /* Complete lookup of the id-expression. */
+ expr = (finish_id_expression
+ (id_expression, expr, parser->scope, &idk,
+ /*integral_constant_expression_p=*/false,
+ /*allow_non_integral_constant_expression_p=*/true,
+ &non_integral_constant_expression_p,
+ /*template_p=*/false,
+ /*done=*/true,
+ /*address_p=*/false,
+ /*template_arg_p=*/false,
+ &error_msg));
+
+ if (expr == error_mark_node)
+ /* We found an id-expression, but it was something that we
+ should not have found. This is an error, not something
+ we can recover from, so note that we found an
+ id-expression and we'll recover as gracefully as
+ possible. */
+ id_expression_or_member_access_p = true;
+ }
+
+ if (expr
+ && expr != error_mark_node
+ && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
+ /* We have an id-expression. */
+ id_expression_or_member_access_p = true;
+ }
+
+ if (!id_expression_or_member_access_p)
+ {
+ /* Abort the id-expression parse. */
+ cp_parser_abort_tentative_parse (parser);
+
+ /* Parsing tentatively, again. */
+ cp_parser_parse_tentatively (parser);
+
+ /* Parse a class member access. */
+ expr = cp_parser_postfix_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false,
+ /*member_access_only_p=*/true);
+
+ if (expr
+ && expr != error_mark_node
+ && cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_PAREN)
+ /* We have an id-expression. */
+ id_expression_or_member_access_p = true;
+ }
+
+ if (id_expression_or_member_access_p)
+ /* We have parsed the complete id-expression or member access. */
+ cp_parser_parse_definitely (parser);
+ else
+ {
+ /* Abort our attempt to parse an id-expression or member access
+ expression. */
+ cp_parser_abort_tentative_parse (parser);
+
+ /* Parse a full expression. */
+ expr = cp_parser_expression (parser, /*cast_p=*/false);
+ }
+
+ /* Go back to evaluating expressions. */
+ --skip_evaluation;
+
+ /* Restore the old message and the integral constant expression
+ flags. */
+ parser->type_definition_forbidden_message = saved_message;
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ 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, "`)'"))
+ cp_parser_skip_to_closing_parenthesis (parser, true, false,
+ /*consume_paren=*/true);
+
+ return finish_decltype_type (expr, id_expression_or_member_access_p);
+}
+
/* Special member functions [gram.special] */
/* Parse a conversion-function-id.
@@ -10438,6 +10616,11 @@ cp_parser_type_specifier (cp_parser* parser,
double
void
+ C++0x Extension:
+
+ simple-type-specifier:
+ decltype ( expression )
+
GNU Extension:
simple-type-specifier:
@@ -10507,6 +10690,16 @@ cp_parser_simple_type_specifier (cp_parser* parser,
type = void_type_node;
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,
+ /*user_defined_p=*/true);
+
+ return type;
+
case RID_TYPEOF:
/* Consume the `typeof' token. */
cp_lexer_consume_token (parser->lexer);