DR 325 PR c++/51666
DR 325 PR c++/51666 * parser.c (cp_parser_cache_defarg): Split out... (cp_parser_parameter_declaration): ...from here. (cp_parser_save_nsdmi): Use it. (cp_parser_cache_group): Remove CPP_COMMA support. From-SVN: r182809
This commit is contained in:
parent
358b9253c1
commit
d28c2dcd71
|
@ -1,3 +1,12 @@
|
|||
2012-01-02 Jason Merrill <jason@redhat.com>
|
||||
|
||||
DR 325
|
||||
PR c++/51666
|
||||
* parser.c (cp_parser_cache_defarg): Split out...
|
||||
(cp_parser_parameter_declaration): ...from here.
|
||||
(cp_parser_save_nsdmi): Use it.
|
||||
(cp_parser_cache_group): Remove CPP_COMMA support.
|
||||
|
||||
2012-01-02 Dodji Seketeli <dodji@redhat.com>
|
||||
|
||||
PR c++/51462
|
||||
|
|
347
gcc/cp/parser.c
347
gcc/cp/parser.c
|
@ -2249,6 +2249,8 @@ static void cp_parser_pre_parsed_nested_name_specifier
|
|||
(cp_parser *);
|
||||
static bool cp_parser_cache_group
|
||||
(cp_parser *, enum cpp_ttype, unsigned);
|
||||
static tree cp_parser_cache_defarg
|
||||
(cp_parser *parser, bool nsdmi);
|
||||
static void cp_parser_parse_tentatively
|
||||
(cp_parser *);
|
||||
static void cp_parser_commit_to_tentative_parse
|
||||
|
@ -17267,159 +17269,18 @@ cp_parser_parameter_declaration (cp_parser *parser,
|
|||
/* If the next token is `=', then process a default argument. */
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
|
||||
{
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
/* If we are defining a class, then the tokens that make up the
|
||||
default argument must be saved and processed later. */
|
||||
if (!template_parm_p && at_class_scope_p ()
|
||||
&& TYPE_BEING_DEFINED (current_class_type)
|
||||
&& !LAMBDA_TYPE_P (current_class_type))
|
||||
{
|
||||
unsigned depth = 0;
|
||||
int maybe_template_id = 0;
|
||||
cp_token *first_token;
|
||||
cp_token *token;
|
||||
|
||||
/* Add tokens until we have processed the entire default
|
||||
argument. We add the range [first_token, token). */
|
||||
first_token = cp_lexer_peek_token (parser->lexer);
|
||||
while (true)
|
||||
{
|
||||
bool done = false;
|
||||
|
||||
/* Peek at the next token. */
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
/* What we do depends on what token we have. */
|
||||
switch (token->type)
|
||||
{
|
||||
/* In valid code, a default argument must be
|
||||
immediately followed by a `,' `)', or `...'. */
|
||||
case CPP_COMMA:
|
||||
if (depth == 0 && maybe_template_id)
|
||||
{
|
||||
/* If we've seen a '<', we might be in a
|
||||
template-argument-list. Until Core issue 325 is
|
||||
resolved, we don't know how this situation ought
|
||||
to be handled, so try to DTRT. We check whether
|
||||
what comes after the comma is a valid parameter
|
||||
declaration list. If it is, then the comma ends
|
||||
the default argument; otherwise the default
|
||||
argument continues. */
|
||||
bool error = false;
|
||||
tree t;
|
||||
|
||||
/* Set ITALP so cp_parser_parameter_declaration_list
|
||||
doesn't decide to commit to this parse. */
|
||||
bool saved_italp = parser->in_template_argument_list_p;
|
||||
parser->in_template_argument_list_p = true;
|
||||
|
||||
cp_parser_parse_tentatively (parser);
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
begin_scope (sk_function_parms, NULL_TREE);
|
||||
cp_parser_parameter_declaration_list (parser, &error);
|
||||
for (t = current_binding_level->names; t; t = DECL_CHAIN (t))
|
||||
pop_binding (DECL_NAME (t), t);
|
||||
leave_scope ();
|
||||
if (!cp_parser_error_occurred (parser) && !error)
|
||||
done = true;
|
||||
cp_parser_abort_tentative_parse (parser);
|
||||
|
||||
parser->in_template_argument_list_p = saved_italp;
|
||||
break;
|
||||
}
|
||||
case CPP_CLOSE_PAREN:
|
||||
case CPP_ELLIPSIS:
|
||||
/* If we run into a non-nested `;', `}', or `]',
|
||||
then the code is invalid -- but the default
|
||||
argument is certainly over. */
|
||||
case CPP_SEMICOLON:
|
||||
case CPP_CLOSE_BRACE:
|
||||
case CPP_CLOSE_SQUARE:
|
||||
if (depth == 0)
|
||||
done = true;
|
||||
/* Update DEPTH, if necessary. */
|
||||
else if (token->type == CPP_CLOSE_PAREN
|
||||
|| token->type == CPP_CLOSE_BRACE
|
||||
|| token->type == CPP_CLOSE_SQUARE)
|
||||
--depth;
|
||||
break;
|
||||
|
||||
case CPP_OPEN_PAREN:
|
||||
case CPP_OPEN_SQUARE:
|
||||
case CPP_OPEN_BRACE:
|
||||
++depth;
|
||||
break;
|
||||
|
||||
case CPP_LESS:
|
||||
if (depth == 0)
|
||||
/* This might be the comparison operator, or it might
|
||||
start a template argument list. */
|
||||
++maybe_template_id;
|
||||
break;
|
||||
|
||||
case CPP_RSHIFT:
|
||||
if (cxx_dialect == cxx98)
|
||||
break;
|
||||
/* Fall through for C++0x, which treats the `>>'
|
||||
operator like two `>' tokens in certain
|
||||
cases. */
|
||||
|
||||
case CPP_GREATER:
|
||||
if (depth == 0)
|
||||
{
|
||||
/* This might be an operator, or it might close a
|
||||
template argument list. But if a previous '<'
|
||||
started a template argument list, this will have
|
||||
closed it, so we can't be in one anymore. */
|
||||
maybe_template_id -= 1 + (token->type == CPP_RSHIFT);
|
||||
if (maybe_template_id < 0)
|
||||
maybe_template_id = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* If we run out of tokens, issue an error message. */
|
||||
case CPP_EOF:
|
||||
case CPP_PRAGMA_EOL:
|
||||
error_at (token->location, "file ends in default argument");
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case CPP_NAME:
|
||||
case CPP_SCOPE:
|
||||
/* In these cases, we should look for template-ids.
|
||||
For example, if the default argument is
|
||||
`X<int, double>()', we need to do name lookup to
|
||||
figure out whether or not `X' is a template; if
|
||||
so, the `,' does not end the default argument.
|
||||
|
||||
That is not yet done. */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we've reached the end, stop. */
|
||||
if (done)
|
||||
break;
|
||||
|
||||
/* Add the token to the token block. */
|
||||
token = cp_lexer_consume_token (parser->lexer);
|
||||
}
|
||||
|
||||
/* Create a DEFAULT_ARG to represent the unparsed default
|
||||
argument. */
|
||||
default_argument = make_node (DEFAULT_ARG);
|
||||
DEFARG_TOKENS (default_argument)
|
||||
= cp_token_cache_new (first_token, token);
|
||||
DEFARG_INSTANTIATIONS (default_argument) = NULL;
|
||||
}
|
||||
default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
|
||||
/* Outside of a class definition, we can just parse the
|
||||
assignment-expression. */
|
||||
else
|
||||
{
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
default_argument
|
||||
= cp_parser_default_argument (parser, template_parm_p);
|
||||
}
|
||||
default_argument
|
||||
= cp_parser_default_argument (parser, template_parm_p);
|
||||
|
||||
if (!parser->default_arg_ok_p)
|
||||
{
|
||||
|
@ -21630,25 +21491,9 @@ cp_parser_save_member_function_body (cp_parser* parser,
|
|||
static tree
|
||||
cp_parser_save_nsdmi (cp_parser* parser)
|
||||
{
|
||||
/* Save away the tokens that make up the body of the
|
||||
function. */
|
||||
cp_token *first = parser->lexer->next_token;
|
||||
cp_token *last;
|
||||
tree node;
|
||||
|
||||
/* Save tokens until the next comma or semicolon. */
|
||||
cp_parser_cache_group (parser, CPP_COMMA, /*depth=*/0);
|
||||
|
||||
last = parser->lexer->next_token;
|
||||
|
||||
node = make_node (DEFAULT_ARG);
|
||||
DEFARG_TOKENS (node) = cp_token_cache_new (first, last);
|
||||
DEFARG_INSTANTIATIONS (node) = NULL;
|
||||
|
||||
return node;
|
||||
return cp_parser_cache_defarg (parser, /*nsdmi=*/true);
|
||||
}
|
||||
|
||||
|
||||
/* Parse a template-argument-list, as well as the trailing ">" (but
|
||||
not the opening "<"). See cp_parser_template_argument_list for the
|
||||
return value. */
|
||||
|
@ -22758,12 +22603,6 @@ cp_parser_cache_group (cp_parser *parser,
|
|||
kind of syntax error. */
|
||||
return true;
|
||||
|
||||
/* If we're caching something finished by a comma (or semicolon),
|
||||
such as an NSDMI, don't consume the comma. */
|
||||
if (end == CPP_COMMA
|
||||
&& (token->type == CPP_SEMICOLON || token->type == CPP_COMMA))
|
||||
return false;
|
||||
|
||||
/* Consume the token. */
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
/* See if it starts a new group. */
|
||||
|
@ -22789,6 +22628,178 @@ cp_parser_cache_group (cp_parser *parser,
|
|||
}
|
||||
}
|
||||
|
||||
/* Like above, for caching a default argument or NSDMI. Both of these are
|
||||
terminated by a non-nested comma, but it can be unclear whether or not a
|
||||
comma is nested in a template argument list unless we do more parsing.
|
||||
In order to handle this ambiguity, when we encounter a ',' after a '<'
|
||||
we try to parse what follows as a parameter-declaration-list (in the
|
||||
case of a default argument) or a member-declarator (in the case of an
|
||||
NSDMI). If that succeeds, then we stop caching. */
|
||||
|
||||
static tree
|
||||
cp_parser_cache_defarg (cp_parser *parser, bool nsdmi)
|
||||
{
|
||||
unsigned depth = 0;
|
||||
int maybe_template_id = 0;
|
||||
cp_token *first_token;
|
||||
cp_token *token;
|
||||
tree default_argument;
|
||||
|
||||
/* Add tokens until we have processed the entire default
|
||||
argument. We add the range [first_token, token). */
|
||||
first_token = cp_lexer_peek_token (parser->lexer);
|
||||
if (first_token->type == CPP_OPEN_BRACE)
|
||||
{
|
||||
/* For list-initialization, this is straightforward. */
|
||||
cp_parser_cache_group (parser, CPP_CLOSE_BRACE, /*depth=*/0);
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
}
|
||||
else while (true)
|
||||
{
|
||||
bool done = false;
|
||||
|
||||
/* Peek at the next token. */
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
/* What we do depends on what token we have. */
|
||||
switch (token->type)
|
||||
{
|
||||
/* In valid code, a default argument must be
|
||||
immediately followed by a `,' `)', or `...'. */
|
||||
case CPP_COMMA:
|
||||
if (depth == 0 && maybe_template_id)
|
||||
{
|
||||
/* If we've seen a '<', we might be in a
|
||||
template-argument-list. Until Core issue 325 is
|
||||
resolved, we don't know how this situation ought
|
||||
to be handled, so try to DTRT. We check whether
|
||||
what comes after the comma is a valid parameter
|
||||
declaration list. If it is, then the comma ends
|
||||
the default argument; otherwise the default
|
||||
argument continues. */
|
||||
bool error = false;
|
||||
tree t;
|
||||
|
||||
/* Set ITALP so cp_parser_parameter_declaration_list
|
||||
doesn't decide to commit to this parse. */
|
||||
bool saved_italp = parser->in_template_argument_list_p;
|
||||
parser->in_template_argument_list_p = true;
|
||||
|
||||
cp_parser_parse_tentatively (parser);
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
|
||||
if (nsdmi)
|
||||
{
|
||||
int ctor_dtor_or_conv_p;
|
||||
cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
|
||||
&ctor_dtor_or_conv_p,
|
||||
/*parenthesized_p=*/NULL,
|
||||
/*member_p=*/true);
|
||||
}
|
||||
else
|
||||
{
|
||||
begin_scope (sk_function_parms, NULL_TREE);
|
||||
cp_parser_parameter_declaration_list (parser, &error);
|
||||
for (t = current_binding_level->names; t; t = DECL_CHAIN (t))
|
||||
pop_binding (DECL_NAME (t), t);
|
||||
leave_scope ();
|
||||
}
|
||||
if (!cp_parser_error_occurred (parser) && !error)
|
||||
done = true;
|
||||
cp_parser_abort_tentative_parse (parser);
|
||||
|
||||
parser->in_template_argument_list_p = saved_italp;
|
||||
break;
|
||||
}
|
||||
case CPP_CLOSE_PAREN:
|
||||
case CPP_ELLIPSIS:
|
||||
/* If we run into a non-nested `;', `}', or `]',
|
||||
then the code is invalid -- but the default
|
||||
argument is certainly over. */
|
||||
case CPP_SEMICOLON:
|
||||
case CPP_CLOSE_BRACE:
|
||||
case CPP_CLOSE_SQUARE:
|
||||
if (depth == 0)
|
||||
done = true;
|
||||
/* Update DEPTH, if necessary. */
|
||||
else if (token->type == CPP_CLOSE_PAREN
|
||||
|| token->type == CPP_CLOSE_BRACE
|
||||
|| token->type == CPP_CLOSE_SQUARE)
|
||||
--depth;
|
||||
break;
|
||||
|
||||
case CPP_OPEN_PAREN:
|
||||
case CPP_OPEN_SQUARE:
|
||||
case CPP_OPEN_BRACE:
|
||||
++depth;
|
||||
break;
|
||||
|
||||
case CPP_LESS:
|
||||
if (depth == 0)
|
||||
/* This might be the comparison operator, or it might
|
||||
start a template argument list. */
|
||||
++maybe_template_id;
|
||||
break;
|
||||
|
||||
case CPP_RSHIFT:
|
||||
if (cxx_dialect == cxx98)
|
||||
break;
|
||||
/* Fall through for C++0x, which treats the `>>'
|
||||
operator like two `>' tokens in certain
|
||||
cases. */
|
||||
|
||||
case CPP_GREATER:
|
||||
if (depth == 0)
|
||||
{
|
||||
/* This might be an operator, or it might close a
|
||||
template argument list. But if a previous '<'
|
||||
started a template argument list, this will have
|
||||
closed it, so we can't be in one anymore. */
|
||||
maybe_template_id -= 1 + (token->type == CPP_RSHIFT);
|
||||
if (maybe_template_id < 0)
|
||||
maybe_template_id = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* If we run out of tokens, issue an error message. */
|
||||
case CPP_EOF:
|
||||
case CPP_PRAGMA_EOL:
|
||||
error_at (token->location, "file ends in default argument");
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case CPP_NAME:
|
||||
case CPP_SCOPE:
|
||||
/* In these cases, we should look for template-ids.
|
||||
For example, if the default argument is
|
||||
`X<int, double>()', we need to do name lookup to
|
||||
figure out whether or not `X' is a template; if
|
||||
so, the `,' does not end the default argument.
|
||||
|
||||
That is not yet done. */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we've reached the end, stop. */
|
||||
if (done)
|
||||
break;
|
||||
|
||||
/* Add the token to the token block. */
|
||||
token = cp_lexer_consume_token (parser->lexer);
|
||||
}
|
||||
|
||||
/* Create a DEFAULT_ARG to represent the unparsed default
|
||||
argument. */
|
||||
default_argument = make_node (DEFAULT_ARG);
|
||||
DEFARG_TOKENS (default_argument)
|
||||
= cp_token_cache_new (first_token, token);
|
||||
DEFARG_INSTANTIATIONS (default_argument) = NULL;
|
||||
|
||||
return default_argument;
|
||||
}
|
||||
|
||||
/* Begin parsing tentatively. We always save tokens while parsing
|
||||
tentatively so that if the tentative parsing fails we can restore the
|
||||
tokens. */
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2012-01-02 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/51666
|
||||
* g++.dg/cpp0x/nsdmi-defer5.C: New.
|
||||
|
||||
2012-01-02 Dodji Seketeli <dodji@redhat.com>
|
||||
|
||||
PR c++/51462
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// PR c++/51666 (DR 325)
|
||||
// { dg-options -std=c++0x }
|
||||
|
||||
template<typename T, typename U>
|
||||
struct tuple
|
||||
{
|
||||
tuple(T, U) { }
|
||||
};
|
||||
|
||||
struct Y
|
||||
{
|
||||
tuple<int, int> tt = tuple<int, int>{1, 2};
|
||||
};
|
||||
|
||||
struct A
|
||||
{
|
||||
int i = 0;
|
||||
int j = i < 42, k; // OK, declares j and k
|
||||
int l = i < 42, 24; // { dg-error "" }
|
||||
};
|
Loading…
Reference in New Issue