static cp_declarator *make_pointer_declarator
(cp_cv_quals, cp_declarator *);
static cp_declarator *make_reference_declarator
- (cp_cv_quals, cp_declarator *);
+ (cp_cv_quals, cp_declarator *, bool);
static cp_parameter_declarator *make_parameter_declarator
(cp_decl_specifier_seq *, cp_declarator *, tree);
static cp_declarator *make_ptrmem_declarator
declarator->kind = kind;
declarator->attributes = NULL_TREE;
declarator->declarator = NULL;
+ declarator->parameter_pack_p = false;
return declarator;
}
declarator->u.id.qualifying_scope = qualifying_scope;
declarator->u.id.unqualified_name = unqualified_name;
declarator->u.id.sfk = sfk;
-
+
return declarator;
}
declarator->declarator = target;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = NULL_TREE;
+ if (target)
+ {
+ declarator->parameter_pack_p = target->parameter_pack_p;
+ target->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
/* Like make_pointer_declarator -- but for references. */
cp_declarator *
-make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
+make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target,
+ bool rvalue_ref)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_reference);
declarator->declarator = target;
- declarator->u.pointer.qualifiers = cv_qualifiers;
- declarator->u.pointer.class_type = NULL_TREE;
+ declarator->u.reference.qualifiers = cv_qualifiers;
+ declarator->u.reference.rvalue_ref = rvalue_ref;
+ if (target)
+ {
+ declarator->parameter_pack_p = target->parameter_pack_p;
+ target->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = class_type;
+ if (pointee)
+ {
+ declarator->parameter_pack_p = pointee->parameter_pack_p;
+ pointee->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
+
return declarator;
}
declarator->u.function.parameters = parms;
declarator->u.function.qualifiers = cv_qualifiers;
declarator->u.function.exception_specification = exception_specification;
+ if (target)
+ {
+ declarator->parameter_pack_p = target->parameter_pack_p;
+ target->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
declarator = make_declarator (cdk_array);
declarator->declarator = element;
declarator->u.array.bounds = bounds;
+ if (element)
+ {
+ declarator->parameter_pack_p = element->parameter_pack_p;
+ element->parameter_pack_p = false;
+ }
+ else
+ declarator->parameter_pack_p = false;
return declarator;
}
+/* Determine whether the declarator we've seen so far can be a
+ parameter pack, when followed by an ellipsis. */
+static bool
+declarator_can_be_parameter_pack (cp_declarator *declarator)
+{
+ /* Search for a declarator name, or any other declarator that goes
+ after the point where the ellipsis could appear in a parameter
+ pack. If we find any of these, then this declarator can not be
+ made into a parameter pack. */
+ bool found = false;
+ while (declarator && !found)
+ {
+ switch ((int)declarator->kind)
+ {
+ case cdk_id:
+ case cdk_error:
+ case cdk_array:
+ case cdk_ptrmem:
+ found = true;
+ break;
+
+ default:
+ declarator = declarator->declarator;
+ break;
+ }
+ }
+
+ return !found;
+}
+
cp_parameter_declarator *no_parameters;
/* Create a parameter declarator with the indicated DECL_SPECIFIERS,
/* TRUE if the `>' token should be interpreted as the greater-than
operator. FALSE if it is the end of a template-id or
- template-parameter-list. */
+ template-parameter-list. In C++0x mode, this flag also applies to
+ `>>' tokens, which are viewed as two consecutive `>' tokens when
+ this flag is FALSE. */
bool greater_than_is_operator_p;
/* TRUE if default arguments are allowed within a parameter list
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
static tree cp_parser_parenthesized_expression_list
- (cp_parser *, bool, bool, bool *);
+ (cp_parser *, bool, bool, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
static tree cp_parser_template_parameter_list
(cp_parser *);
static tree cp_parser_template_parameter
- (cp_parser *, bool *);
+ (cp_parser *, bool *, bool *);
static tree cp_parser_type_parameter
- (cp_parser *);
+ (cp_parser *, bool *);
static tree cp_parser_template_id
(cp_parser *, bool, bool, bool);
static tree cp_parser_template_name
static void cp_parser_perform_template_parameter_access_checks
(VEC (deferred_access_check,gc)*);
static tree cp_parser_single_declaration
- (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool *);
+ (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
(cp_parser *, tree);
static tree cp_parser_sizeof_operand
(cp_parser *, enum rid);
+static tree cp_parser_trait_expr
+ (cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p
(cp_parser *);
static void cp_parser_set_storage_class
(cp_parser *);
static void cp_parser_skip_to_end_of_block_or_statement
(cp_parser *);
-static void cp_parser_skip_to_closing_brace
+static bool cp_parser_skip_to_closing_brace
(cp_parser *);
static void cp_parser_skip_to_end_of_template_parameter_list
(cp_parser *);
(cp_token *, enum rid);
static tree cp_parser_make_typename_type
(cp_parser *, tree, tree);
+static cp_declarator * cp_parser_make_indirect_declarator
+ (enum tree_code, tree, cp_cv_quals, cp_declarator *);
/* Returns nonzero if we are parsing tentatively. */
if (decl == error_mark_node)
{
if (parser->scope && parser->scope != global_namespace)
- error ("%<%D::%D%> has not been declared",
+ error ("%<%E::%E%> has not been declared",
parser->scope, name);
else if (parser->scope == global_namespace)
- error ("%<::%D%> has not been declared", name);
+ error ("%<::%E%> has not been declared", name);
else if (parser->object_scope
&& !CLASS_TYPE_P (parser->object_scope))
- error ("request for member %qD in non-class type %qT",
+ error ("request for member %qE in non-class type %qT",
name, parser->object_scope);
else if (parser->object_scope)
- error ("%<%T::%D%> has not been declared",
+ error ("%<%T::%E%> has not been declared",
parser->object_scope, name);
else
- error ("%qD has not been declared", name);
+ error ("%qE has not been declared", name);
}
else if (parser->scope && parser->scope != global_namespace)
- error ("%<%D::%D%> %s", parser->scope, name, desired);
+ error ("%<%E::%E%> %s", parser->scope, name, desired);
else if (parser->scope == global_namespace)
- error ("%<::%D%> %s", name, desired);
+ error ("%<::%E%> %s", name, desired);
else
- error ("%qD %s", name, desired);
+ error ("%qE %s", name, desired);
}
/* If we are parsing tentatively, remember that an error has occurred
the scope is dependent, we cannot do much. */
if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)
|| (parser->scope && TYPE_P (parser->scope)
- && dependent_type_p (parser->scope)))
+ && dependent_type_p (parser->scope))
+ || TREE_CODE (id) == TYPE_DECL)
{
cp_parser_abort_tentative_parse (parser);
return false;
}
- if (!cp_parser_parse_definitely (parser) || TREE_CODE (id) == TYPE_DECL)
+ if (!cp_parser_parse_definitely (parser))
return false;
/* Emit a diagnostic for the invalid type. */
}
/* Skip tokens until a non-nested closing curly brace is the next
- token. */
+ token, or there are no more tokens. Return true in the first case,
+ false otherwise. */
-static void
+static bool
cp_parser_skip_to_closing_brace (cp_parser *parser)
{
unsigned nesting_depth = 0;
case CPP_EOF:
case CPP_PRAGMA_EOL:
/* If we've run out of tokens, stop. */
- return;
+ return false;
case CPP_CLOSE_BRACE:
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
if (nesting_depth-- == 0)
- return;
+ return true;
break;
case CPP_OPEN_BRACE:
return make_typename_type (scope, id, typename_type, tf_error);
}
+/* This is a wrapper around the
+ make_{pointer,ptrmem,reference}_declarator functions that decides
+ which one to call based on the CODE and CLASS_TYPE arguments. The
+ CODE argument should be one of the values returned by
+ cp_parser_ptr_operator. */
+static cp_declarator *
+cp_parser_make_indirect_declarator (enum tree_code code, tree class_type,
+ cp_cv_quals cv_qualifiers,
+ cp_declarator *target)
+{
+ if (code == INDIRECT_REF)
+ if (class_type == NULL_TREE)
+ return make_pointer_declarator (cv_qualifiers, target);
+ else
+ return make_ptrmem_declarator (cv_qualifiers, class_type, target);
+ else if (code == ADDR_EXPR && class_type == NULL_TREE)
+ return make_reference_declarator (cv_qualifiers, target, false);
+ else if (code == NON_LVALUE_EXPR && class_type == NULL_TREE)
+ return make_reference_declarator (cv_qualifiers, target, true);
+ gcc_unreachable ();
+}
/* Create a new C++ parser. */
__builtin_va_arg ( assignment-expression , type-id )
__builtin_offsetof ( type-id , offsetof-expression )
+ C++ Extensions:
+ __has_nothrow_assign ( type-id )
+ __has_nothrow_constructor ( type-id )
+ __has_nothrow_copy ( type-id )
+ __has_trivial_assign ( type-id )
+ __has_trivial_constructor ( type-id )
+ __has_trivial_copy ( type-id )
+ __has_trivial_destructor ( type-id )
+ __has_virtual_destructor ( type-id )
+ __is_abstract ( type-id )
+ __is_base_of ( type-id , type-id )
+ __is_class ( type-id )
+ __is_convertible_to ( type-id , type-id )
+ __is_empty ( type-id )
+ __is_enum ( type-id )
+ __is_pod ( type-id )
+ __is_polymorphic ( type-id )
+ __is_union ( type-id )
+
Objective-C++ Extension:
primary-expression:
&& next_token->type != CPP_CLOSE_SQUARE
/* The closing ">" in a template-argument-list. */
&& (next_token->type != CPP_GREATER
+ || parser->greater_than_is_operator_p)
+ /* C++0x only: A ">>" treated like two ">" tokens,
+ in a template-argument-list. */
+ && (next_token->type != CPP_RSHIFT
+ || (cxx_dialect == cxx98)
|| parser->greater_than_is_operator_p))
cast_p = false;
}
case RID_OFFSETOF:
return cp_parser_builtin_offsetof (parser);
- /* Objective-C++ expressions. */
+ case RID_HAS_NOTHROW_ASSIGN:
+ case RID_HAS_NOTHROW_CONSTRUCTOR:
+ case RID_HAS_NOTHROW_COPY:
+ case RID_HAS_TRIVIAL_ASSIGN:
+ case RID_HAS_TRIVIAL_CONSTRUCTOR:
+ case RID_HAS_TRIVIAL_COPY:
+ case RID_HAS_TRIVIAL_DESTRUCTOR:
+ case RID_HAS_VIRTUAL_DESTRUCTOR:
+ case RID_IS_ABSTRACT:
+ case RID_IS_BASE_OF:
+ case RID_IS_CLASS:
+ case RID_IS_CONVERTIBLE_TO:
+ case RID_IS_EMPTY:
+ case RID_IS_ENUM:
+ case RID_IS_POD:
+ case RID_IS_POLYMORPHIC:
+ case RID_IS_UNION:
+ return cp_parser_trait_expr (parser, token->keyword);
+
+ /* Objective-C++ expressions. */
case RID_AT_ENCODE:
case RID_AT_PROTOCOL:
case RID_AT_SELECTOR:
allowed in standard C++. */
if (pedantic)
pedwarn ("ISO C++ forbids compound-literals");
+ /* For simplicity, we disallow compound literals in
+ constant-expressions. We could
+ allow compound literals of integer type, whose
+ initializer was a constant, in constant
+ expressions. Permitting that usage, as a further
+ extension, would not change the meaning of any
+ currently accepted programs. (Of course, as
+ compound literals are not part of ISO C++, the
+ standard has nothing to say.) */
+ if (cp_parser_non_integral_constant_expression
+ (parser, "non-constant compound literals"))
+ {
+ postfix_expression = error_mark_node;
+ break;
+ }
/* Form the representation of the compound-literal. */
postfix_expression
= finish_compound_literal (type, initializer_list);
}
args = (cp_parser_parenthesized_expression_list
(parser, /*is_attribute_list=*/false,
- /*cast_p=*/false,
+ /*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL));
if (is_builtin_constant_p)
{
CAST_P is true if this expression is the target of a cast.
+ ALLOW_EXPANSION_P is true if this expression allows expansion of an
+ argument pack.
+
Returns a TREE_LIST. The TREE_VALUE of each node is a
representation of an assignment-expression. Note that a TREE_LIST
is returned even if there is only a single expression in the list.
cp_parser_parenthesized_expression_list (cp_parser* parser,
bool is_attribute_list,
bool cast_p,
+ bool allow_expansion_p,
bool *non_constant_p)
{
tree expression_list = NULL_TREE;
if (fold_expr_p)
expr = fold_non_dependent_expr (expr);
+ /* If we have an ellipsis, then this is an expression
+ expansion. */
+ if (allow_expansion_p
+ && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Build the argument pack. */
+ expr = make_pack_expansion (expr);
+ }
+
/* Add it to the list. We add error_mark_node
expressions to the list, so that we can still tell if
the correct form for a parenthesized expression-list
/* Parse the expression-list. */
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*cast_p=*/false,
+ (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL));
return expression_list;
/* Parse another optional declarator. */
declarator = cp_parser_new_declarator_opt (parser);
- /* Create the representation of the declarator. */
- if (type)
- declarator = make_ptrmem_declarator (cv_quals, type, declarator);
- else if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_quals, declarator);
- else
- declarator = make_reference_declarator (cv_quals, declarator);
-
- return declarator;
+ return cp_parser_make_indirect_declarator
+ (code, type, cv_quals, declarator);
}
/* If the next token is a `[', there is a direct-new-declarator. */
tree expression_list;
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*cast_p=*/false,
+ (parser, false, /*cast_p=*/false, /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL));
if (!expression_list)
expression_list = void_zero_node;
The binops_by_token map is used to get the tree codes for each <token> type.
binary-expressions are associated according to a precedence table. */
-#define TOKEN_PRECEDENCE(token) \
- ((token->type == CPP_GREATER && !parser->greater_than_is_operator_p) \
- ? PREC_NOT_OPERATOR \
- : binops_by_token[token->type].prec)
+#define TOKEN_PRECEDENCE(token) \
+(((token->type == CPP_GREATER \
+ || ((cxx_dialect != cxx98) && token->type == CPP_RSHIFT)) \
+ && !parser->greater_than_is_operator_p) \
+ ? PREC_NOT_OPERATOR \
+ : binops_by_token[token->type].prec)
static tree
cp_parser_binary_expression (cp_parser* parser, bool cast_p)
/* Get an operator token. */
token = cp_lexer_peek_token (parser->lexer);
+ if (warn_cxx0x_compat
+ && token->type == CPP_RSHIFT
+ && !parser->greater_than_is_operator_p)
+ {
+ warning (OPT_Wc__0x_compat,
+ "%H%<>>%> operator will be treated as two right angle brackets in C++0x",
+ &token->location);
+ warning (OPT_Wc__0x_compat,
+ "suggest parentheses around %<>>%> expression");
+ }
+
new_prec = TOKEN_PRECEDENCE (token);
/* Popping an entry off the stack means we completed a subexpression:
return expr;
}
+/* Parse a trait expression. */
+
+static tree
+cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
+{
+ cp_trait_kind kind;
+ tree type1, type2 = NULL_TREE;
+ bool binary = false;
+ cp_decl_specifier_seq decl_specs;
+
+ switch (keyword)
+ {
+ case RID_HAS_NOTHROW_ASSIGN:
+ kind = CPTK_HAS_NOTHROW_ASSIGN;
+ break;
+ case RID_HAS_NOTHROW_CONSTRUCTOR:
+ kind = CPTK_HAS_NOTHROW_CONSTRUCTOR;
+ break;
+ case RID_HAS_NOTHROW_COPY:
+ kind = CPTK_HAS_NOTHROW_COPY;
+ break;
+ case RID_HAS_TRIVIAL_ASSIGN:
+ kind = CPTK_HAS_TRIVIAL_ASSIGN;
+ break;
+ case RID_HAS_TRIVIAL_CONSTRUCTOR:
+ kind = CPTK_HAS_TRIVIAL_CONSTRUCTOR;
+ break;
+ case RID_HAS_TRIVIAL_COPY:
+ kind = CPTK_HAS_TRIVIAL_COPY;
+ break;
+ case RID_HAS_TRIVIAL_DESTRUCTOR:
+ kind = CPTK_HAS_TRIVIAL_DESTRUCTOR;
+ break;
+ case RID_HAS_VIRTUAL_DESTRUCTOR:
+ kind = CPTK_HAS_VIRTUAL_DESTRUCTOR;
+ break;
+ case RID_IS_ABSTRACT:
+ kind = CPTK_IS_ABSTRACT;
+ break;
+ case RID_IS_BASE_OF:
+ kind = CPTK_IS_BASE_OF;
+ binary = true;
+ break;
+ case RID_IS_CLASS:
+ kind = CPTK_IS_CLASS;
+ break;
+ case RID_IS_CONVERTIBLE_TO:
+ kind = CPTK_IS_CONVERTIBLE_TO;
+ binary = true;
+ break;
+ case RID_IS_EMPTY:
+ kind = CPTK_IS_EMPTY;
+ break;
+ case RID_IS_ENUM:
+ kind = CPTK_IS_ENUM;
+ break;
+ case RID_IS_POD:
+ kind = CPTK_IS_POD;
+ break;
+ case RID_IS_POLYMORPHIC:
+ kind = CPTK_IS_POLYMORPHIC;
+ break;
+ case RID_IS_UNION:
+ kind = CPTK_IS_UNION;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+
+ type1 = cp_parser_type_id (parser);
+
+ /* Build a trivial decl-specifier-seq. */
+ clear_decl_specs (&decl_specs);
+ decl_specs.type = type1;
+
+ /* Call grokdeclarator to figure out what type this is. */
+ type1 = grokdeclarator (NULL, &decl_specs, TYPENAME,
+ /*initialized=*/0, /*attrlist=*/NULL);
+
+ if (binary)
+ {
+ cp_parser_require (parser, CPP_COMMA, "`,'");
+
+ type2 = cp_parser_type_id (parser);
+
+ /* Build a trivial decl-specifier-seq. */
+ clear_decl_specs (&decl_specs);
+ decl_specs.type = type2;
+
+ /* Call grokdeclarator to figure out what type this is. */
+ type2 = grokdeclarator (NULL, &decl_specs, TYPENAME,
+ /*initialized=*/0, /*attrlist=*/NULL);
+ }
+
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+ /* Complete the trait expr, which may mean either processing the
+ static assert now or saving it for template instantiation. */
+ return finish_trait_expr (kind, type1, type2);
+}
+
/* Statements [gram.stmt.stmt] */
/* Parse a statement.
statement = cp_parser_try_block (parser);
break;
+ case RID_NAMESPACE:
+ /* This must be a namespace alias definition. */
+ cp_parser_declaration_statement (parser);
+ return;
+
default:
/* It might be a keyword like `int' that can start a
declaration-statement. */
return cp_parser_expression (parser, /*cast_p=*/false);
}
+/* We check for a ) immediately followed by ; with no whitespacing
+ between. This is used to issue a warning for:
+
+ while (...);
+
+ and:
+
+ for (...);
+
+ as the semicolon is probably extraneous.
+
+ On parse errors, the next token might not be a ), so do nothing in
+ that case. */
+
+static void
+check_empty_body (cp_parser* parser, const char* type)
+{
+ cp_token *token;
+ cp_token *close_paren;
+ expanded_location close_loc;
+ expanded_location semi_loc;
+
+ close_paren = cp_lexer_peek_token (parser->lexer);
+ if (close_paren->type != CPP_CLOSE_PAREN)
+ return;
+
+ close_loc = expand_location (close_paren->location);
+ token = cp_lexer_peek_nth_token (parser->lexer, 2);
+
+ if (token->type != CPP_SEMICOLON
+ || (token->flags & PREV_WHITE))
+ return;
+
+ semi_loc = expand_location (token->location);
+ if (close_loc.line == semi_loc.line
+#ifdef USE_MAPPED_LOCATION
+ && close_loc.column+1 == semi_loc.column
+#endif
+ )
+ warning (OPT_Wempty_body,
+ "suggest a space before %<;%> or explicit braces around empty "
+ "body in %<%s%> statement",
+ type);
+}
+
/* Parse an iteration-statement.
iteration-statement:
/* Parse the condition. */
condition = cp_parser_condition (parser);
finish_while_stmt_cond (condition, statement);
+ check_empty_body (parser, "while");
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Parse the dependent statement. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
expression = cp_parser_expression (parser, /*cast_p=*/false);
finish_for_expr (expression, statement);
+ check_empty_body (parser, "for");
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Parse another optional declarator. */
declarator = cp_parser_conversion_declarator_opt (parser);
- /* Create the representation of the declarator. */
- if (class_type)
- declarator = make_ptrmem_declarator (cv_quals, class_type,
- declarator);
- else if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_quals, declarator);
- else
- declarator = make_reference_declarator (cv_quals, declarator);
-
- return declarator;
+ return cp_parser_make_indirect_declarator
+ (code, class_type, cv_quals, declarator);
}
return NULL;
/* Parse a mem-initializer-list.
mem-initializer-list:
- mem-initializer
- mem-initializer , mem-initializer-list */
+ mem-initializer ... [opt]
+ mem-initializer ... [opt] , mem-initializer-list */
static void
cp_parser_mem_initializer_list (cp_parser* parser)
/* Parse the mem-initializer. */
mem_initializer = cp_parser_mem_initializer (parser);
+ /* If the next token is a `...', we're expanding member initializers. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* The TREE_PURPOSE must be a _TYPE, because base-specifiers
+ can be expanded but members cannot. */
+ if (mem_initializer != error_mark_node
+ && !TYPE_P (TREE_PURPOSE (mem_initializer)))
+ {
+ error ("cannot expand initializer for member %<%D%>",
+ TREE_PURPOSE (mem_initializer));
+ mem_initializer = error_mark_node;
+ }
+
+ /* Construct the pack expansion type. */
+ if (mem_initializer != error_mark_node)
+ mem_initializer = make_pack_expansion (mem_initializer);
+ }
/* Add it to the list, unless it was erroneous. */
if (mem_initializer != error_mark_node)
{
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/false,
+ /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL);
if (expression_list == error_mark_node)
return error_mark_node;
tree parameter;
cp_token *token;
bool is_non_type;
+ bool is_parameter_pack;
/* Parse the template-parameter. */
- parameter = cp_parser_template_parameter (parser, &is_non_type);
+ parameter = cp_parser_template_parameter (parser,
+ &is_non_type,
+ &is_parameter_pack);
/* Add it to the list. */
if (parameter != error_mark_node)
parameter_list = process_template_parm (parameter_list,
parameter,
- is_non_type);
+ is_non_type,
+ is_parameter_pack);
else
{
tree err_parm = build_tree_list (parameter, parameter);
If all goes well, returns a TREE_LIST. The TREE_VALUE represents
the parameter. The TREE_PURPOSE is the default value, if any.
Returns ERROR_MARK_NODE on failure. *IS_NON_TYPE is set to true
- iff this parameter is a non-type parameter. */
+ iff this parameter is a non-type parameter. *IS_PARAMETER_PACK is
+ set to true iff this parameter is a parameter pack. */
static tree
-cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
+cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
+ bool *is_parameter_pack)
{
cp_token *token;
cp_parameter_declarator *parameter_declarator;
/* Assume it is a type parameter or a template parameter. */
*is_non_type = false;
+ /* Assume it not a parameter pack. */
+ *is_parameter_pack = false;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it is `class' or `template', we have a type-parameter. */
if (token->keyword == RID_TEMPLATE)
- return cp_parser_type_parameter (parser);
+ return cp_parser_type_parameter (parser, is_parameter_pack);
/* If it is `class' or `typename' we do not know yet whether it is a
type parameter or a non-type parameter. Consider:
{
/* Peek at the token after `class' or `typename'. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
+ /* If it's an ellipsis, we have a template type parameter
+ pack. */
+ if (token->type == CPP_ELLIPSIS)
+ return cp_parser_type_parameter (parser, is_parameter_pack);
/* If it's an identifier, skip it. */
if (token->type == CPP_NAME)
token = cp_lexer_peek_nth_token (parser->lexer, 3);
if (token->type == CPP_COMMA
|| token->type == CPP_EQ
|| token->type == CPP_GREATER)
- return cp_parser_type_parameter (parser);
+ return cp_parser_type_parameter (parser, is_parameter_pack);
}
/* Otherwise, it is a non-type parameter.
parameter_declarator
= cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
/*parenthesized_p=*/NULL);
+
+ /* If the parameter declaration is marked as a parameter pack, set
+ *IS_PARAMETER_PACK to notify the caller. Also, unmark the
+ declarator's PACK_EXPANSION_P, otherwise we'll get errors from
+ grokdeclarator. */
+ if (parameter_declarator
+ && parameter_declarator->declarator
+ && parameter_declarator->declarator->parameter_pack_p)
+ {
+ *is_parameter_pack = true;
+ parameter_declarator->declarator->parameter_pack_p = false;
+ }
+
+ /* If the next token is an ellipsis, and we don't already have it
+ marked as a parameter pack, then we have a parameter pack (that
+ has no declarator); */
+ if (!*is_parameter_pack
+ && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
+ && declarator_can_be_parameter_pack (parameter_declarator->declarator))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ *is_parameter_pack = true;
+ }
+
parm = grokdeclarator (parameter_declarator->declarator,
¶meter_declarator->decl_specifiers,
PARM, /*initialized=*/0,
/*attrlist=*/NULL);
if (parm == error_mark_node)
return error_mark_node;
+
return build_tree_list (parameter_declarator->default_argument, parm);
}
template < template-parameter-list > class identifier [opt]
= id-expression
+ GNU Extension (variadic templates):
+
+ type-parameter:
+ class ... identifier [opt]
+ typename ... identifier [opt]
+
Returns a TREE_LIST. The TREE_VALUE is itself a TREE_LIST. The
TREE_PURPOSE is the default-argument, if any. The TREE_VALUE is
- the declaration of the parameter. */
+ the declaration of the parameter.
+
+ Sets *IS_PARAMETER_PACK if this is a template parameter pack. */
static tree
-cp_parser_type_parameter (cp_parser* parser)
+cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
{
cp_token *token;
tree parameter;
tree identifier;
tree default_argument;
+ /* If the next token is an ellipsis, we have a template
+ argument pack. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...' token. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ *is_parameter_pack = true;
+ }
+
/* If the next token is an identifier, then it names the
parameter. */
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
/* Parse the default-argument. */
push_deferring_access_checks (dk_no_deferred);
default_argument = cp_parser_type_id (parser);
+
+ /* Template parameter packs cannot have default
+ arguments. */
+ if (*is_parameter_pack)
+ {
+ if (identifier)
+ error ("template parameter pack %qD cannot have a default argument",
+ identifier);
+ else
+ error ("template parameter packs cannot have default arguments");
+ default_argument = NULL_TREE;
+ }
pop_deferring_access_checks ();
}
else
cp_parser_require (parser, CPP_GREATER, "`>'");
/* Look for the `class' keyword. */
cp_parser_require_keyword (parser, RID_CLASS, "`class'");
+ /* If the next token is an ellipsis, we have a template
+ argument pack. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...' token. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ *is_parameter_pack = true;
+ }
/* If the next token is an `=', then there is a
default-argument. If the next token is a `>', we are at
the end of the parameter-list. If the next token is a `,',
/* See if the default argument is valid. */
default_argument
= check_template_template_default_arg (default_argument);
+
+ /* Template parameter packs cannot have default
+ arguments. */
+ if (*is_parameter_pack)
+ {
+ if (identifier)
+ error ("template parameter pack %qD cannot have a default argument",
+ identifier);
+ else
+ error ("template parameter packs cannot have default arguments");
+ default_argument = NULL_TREE;
+ }
pop_deferring_access_checks ();
}
else
/* Parse a template-argument-list.
template-argument-list:
- template-argument
- template-argument-list , template-argument
+ template-argument ... [opt]
+ template-argument-list , template-argument ... [opt]
Returns a TREE_VEC containing the arguments. */
/* Parse the template-argument. */
argument = cp_parser_template_argument (parser);
+
+ /* If the next token is an ellipsis, we're expanding a template
+ argument pack. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...' token. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Make the argument into a TYPE_PACK_EXPANSION or
+ EXPR_PACK_EXPANSION. */
+ argument = make_pack_expansion (argument);
+ }
+
if (n_args == alloced)
{
alloced *= 2;
cp_parser_single_declaration (parser,
/*checks=*/NULL,
/*member_p=*/false,
+ /*explicit_specialization_p=*/true,
/*friend_p=*/NULL);
/* We're done with the specialization. */
end_specialization ();
if (parser->scope)
{
tree decl;
+ tree ambiguous_decls;
decl = cp_parser_lookup_name (parser, identifier,
tag_type,
/*is_template=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true,
- /*ambiguous_decls=*/NULL);
+ &ambiguous_decls);
+
+ /* If the lookup was ambiguous, an error will already have been
+ issued. */
+ if (ambiguous_decls)
+ return error_mark_node;
/* If we are parsing friend declaration, DECL may be a
TEMPLATE_DECL tree node here. However, we need to check
if (identifier == error_mark_node)
return;
/* Look for the `=' token. */
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser)
+ && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ {
+ error ("%<namespace%> definition is not allowed here");
+ /* Skip the definition. */
+ cp_lexer_consume_token (parser->lexer);
+ if (cp_parser_skip_to_closing_brace (parser))
+ cp_lexer_consume_token (parser->lexer);
+ return;
+ }
cp_parser_require (parser, CPP_EQ, "`='");
/* Look for the qualified-namespace-specifier. */
namespace_specifier
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
}
+ else if ((cxx_dialect != cxx98) && friend_p
+ && decl && TREE_CODE (decl) == FUNCTION_DECL)
+ /* Core issue #226 (C++0x only): A default template-argument
+ shall not be specified in a friend class template
+ declaration. */
+ check_default_tmpl_args (decl, current_template_parms, /*is_primary=*/1,
+ /*is_partial=*/0, /*is_friend_decl=*/1);
+
if (!friend_p && pushed_scope)
pop_scope (pushed_scope);
&& !cp_parser_parse_definitely (parser))
declarator = NULL;
- /* Build the representation of the ptr-operator. */
- if (class_type)
- declarator = make_ptrmem_declarator (cv_quals,
- class_type,
- declarator);
- else if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_quals, declarator);
- else
- declarator = make_reference_declarator (cv_quals, declarator);
+ declarator = cp_parser_make_indirect_declarator
+ (code, class_type, cv_quals, declarator);
}
/* Everything else is a direct-declarator. */
else
tree unqualified_name;
special_function_kind sfk;
bool abstract_ok;
+ bool pack_expansion_p = false;
/* Parse a declarator-id */
abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
if (abstract_ok)
- cp_parser_parse_tentatively (parser);
+ {
+ cp_parser_parse_tentatively (parser);
+
+ /* If we see an ellipsis, we should be looking at a
+ parameter pack. */
+ if (token->type == CPP_ELLIPSIS)
+ {
+ /* Consume the `...' */
+ cp_lexer_consume_token (parser->lexer);
+
+ pack_expansion_p = true;
+ }
+ }
+
unqualified_name
= cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
qualifying_scope = parser->scope;
if (abstract_ok)
{
- if (!cp_parser_parse_definitely (parser))
+ bool okay = false;
+
+ if (!unqualified_name && pack_expansion_p)
+ {
+ /* Check whether an error occurred. */
+ okay = !cp_parser_error_occurred (parser);
+
+ /* We already consumed the ellipsis to mark a
+ parameter pack, but we have no way to report it,
+ so abort the tentative parse. We will be exiting
+ immediately anyway. */
+ cp_parser_abort_tentative_parse (parser);
+ }
+ else
+ okay = cp_parser_parse_definitely (parser);
+
+ if (!okay)
unqualified_name = error_mark_node;
else if (unqualified_name
&& (qualifying_scope
if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
+ pack_expansion_p = false;
+ declarator->parameter_pack_p = false;
break;
}
/*only_current_p=*/false);
/* If that failed, the declarator is invalid. */
if (type == error_mark_node)
- error ("%<%T::%D%> is not a type",
+ error ("%<%T::%E%> is not a type",
TYPE_CONTEXT (qualifying_scope),
TYPE_IDENTIFIER (qualifying_scope));
qualifying_scope = type;
}
sfk = sfk_none;
+
if (unqualified_name)
{
tree class_type;
unqualified_name,
sfk);
declarator->id_loc = token->location;
+ declarator->parameter_pack_p = pack_expansion_p;
+
+ if (pack_expansion_p)
+ maybe_warn_variadic_templates ();
handle_declarator:;
scope = get_scope_of_declarator (declarator);
& cv-qualifier-seq [opt]
Returns INDIRECT_REF if a pointer, or pointer-to-member, was used.
- Returns ADDR_EXPR if a reference was used. In the case of a
- pointer-to-member, *TYPE is filled in with the TYPE containing the
- member. *CV_QUALS is filled in with the cv-qualifier-seq, or
- TYPE_UNQUALIFIED, if there are no cv-qualifiers. Returns
- ERROR_MARK if an error occurred. */
-
+ Returns ADDR_EXPR if a reference was used, or NON_LVALUE_EXPR for
+ an rvalue reference. In the case of a pointer-to-member, *TYPE is
+ filled in with the TYPE containing the member. *CV_QUALS is
+ filled in with the cv-qualifier-seq, or TYPE_UNQUALIFIED, if there
+ are no cv-qualifiers. Returns ERROR_MARK if an error occurred.
+ Note that the tree codes returned by this function have nothing
+ to do with the types of trees that will be eventually be created
+ to represent the pointer or reference type being parsed. They are
+ just constants with suggestive names. */
static enum tree_code
cp_parser_ptr_operator (cp_parser* parser,
tree* type,
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- /* If it's a `*' or `&' we have a pointer or reference. */
- if (token->type == CPP_MULT || token->type == CPP_AND)
- {
- /* Remember which ptr-operator we were processing. */
- code = (token->type == CPP_AND ? ADDR_EXPR : INDIRECT_REF);
- /* Consume the `*' or `&'. */
+ /* If it's a `*', `&' or `&&' we have a pointer or reference. */
+ if (token->type == CPP_MULT)
+ code = INDIRECT_REF;
+ else if (token->type == CPP_AND)
+ code = ADDR_EXPR;
+ else if ((cxx_dialect != cxx98) &&
+ token->type == CPP_AND_AND) /* C++0x only */
+ code = NON_LVALUE_EXPR;
+
+ if (code != ERROR_MARK)
+ {
+ /* Consume the `*', `&' or `&&'. */
cp_lexer_consume_token (parser->lexer);
/* A `*' can be followed by a cv-qualifier-seq, and so can a
/* Parse a parameter declaration.
parameter-declaration:
- decl-specifier-seq declarator
+ decl-specifier-seq ... [opt] declarator
decl-specifier-seq declarator = assignment-expression
- decl-specifier-seq abstract-declarator [opt]
+ decl-specifier-seq ... [opt] abstract-declarator [opt]
decl-specifier-seq abstract-declarator [opt] = assignment-expression
If TEMPLATE_PARM_P is TRUE, then this parameter-declaration
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
+
/* If the next token is a `)', `,', `=', `>', or `...', then there
- is no declarator. */
+ is no declarator. However, when variadic templates are enabled,
+ there may be a declarator following `...'. */
if (token->type == CPP_CLOSE_PAREN
|| token->type == CPP_COMMA
|| token->type == CPP_EQ
- || token->type == CPP_ELLIPSIS
|| token->type == CPP_GREATER)
{
declarator = NULL;
cp_parser_attributes_opt (parser));
}
+ /* If the next token is an ellipsis, and we have not seen a
+ declarator name, and the type of the declarator contains parameter
+ packs but it is not a TYPE_PACK_EXPANSION, then we actually have
+ a parameter pack expansion expression. Otherwise, leave the
+ ellipsis for a C-style variadic function. */
+ token = cp_lexer_peek_token (parser->lexer);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ tree type = decl_specifiers.type;
+
+ if (type && DECL_P (type))
+ type = TREE_TYPE (type);
+
+ if (type
+ && TREE_CODE (type) != TYPE_PACK_EXPANSION
+ && declarator_can_be_parameter_pack (declarator)
+ && (!declarator || !declarator->parameter_pack_p)
+ && uses_parameter_packs (type))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ /* Build a pack expansion type */
+ if (declarator)
+ declarator->parameter_pack_p = true;
+ else
+ decl_specifiers.type = make_pack_expansion (type);
+ }
+ }
+
/* The restriction on defining new types applies only to the type
of the parameter, not to the default argument. */
parser->type_definition_forbidden_message = saved_message;
++depth;
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 we see a non-nested `>', and `>' is not an
operator, then it marks the end of the default
else if (token->type == CPP_OPEN_PAREN)
init = cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/false,
+ /*allow_expansion_p=*/true,
non_constant_p);
else
{
/* Parse an initializer-list.
initializer-list:
- initializer-clause
- initializer-list , initializer-clause
+ initializer-clause ... [opt]
+ initializer-list , initializer-clause ... [opt]
GNU Extension:
if (clause_non_constant_p)
*non_constant_p = true;
+ /* If we have an ellipsis, this is an initializer pack
+ expansion. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Turn the initializer into an initializer expansion. */
+ initializer = make_pack_expansion (initializer);
+ }
+
/* Add it to the vector. */
CONSTRUCTOR_APPEND_ELT(v, identifier, initializer);
entire class body. */
if (!xref_basetypes (type, bases))
{
- cp_parser_skip_to_closing_brace (parser);
-
/* Consuming the closing brace yields better error messages
later on. */
- cp_lexer_consume_token (parser->lexer);
+ if (cp_parser_skip_to_closing_brace (parser))
+ cp_lexer_consume_token (parser->lexer);
pop_deferring_access_checks ();
return error_mark_node;
}
token = cp_lexer_peek_token (parser->lexer);
/* If the next token is a semicolon, consume it. */
if (token->type == CPP_SEMICOLON)
- cp_lexer_consume_token (parser->lexer);
+ {
+ if (pedantic && !in_system_header)
+ pedwarn ("extra %<;%>");
+ cp_lexer_consume_token (parser->lexer);
+ }
return;
}
else
: base-specifier-list
base-specifier-list:
- base-specifier
- base-specifier-list , base-specifier
+ base-specifier ... [opt]
+ base-specifier-list , base-specifier ... [opt]
Returns a TREE_LIST representing the base-classes, in the order in
which they were declared. The representation of each node is as
{
cp_token *token;
tree base;
+ bool pack_expansion_p = false;
/* Look for the base-specifier. */
base = cp_parser_base_specifier (parser);
+ /* Look for the (optional) ellipsis. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ pack_expansion_p = true;
+ }
+
/* Add BASE to the front of the list. */
if (base != error_mark_node)
{
+ if (pack_expansion_p)
+ /* Make this a pack expansion type. */
+ TREE_VALUE (base) = make_pack_expansion (TREE_VALUE (base));
+ else
+ check_for_bare_parameter_packs (TREE_VALUE (base));
+
TREE_CHAIN (base) = bases;
bases = base;
}
/* Parse an (optional) type-id-list.
type-id-list:
- type-id
- type-id-list , type-id
+ type-id ... [opt]
+ type-id-list , type-id ... [opt]
Returns a TREE_LIST. The TREE_VALUE of each node is a TYPE,
in the order that the types were presented. */
/* Get the next type-id. */
type = cp_parser_type_id (parser);
+ /* Parse the optional ellipsis. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Turn the type into a pack expansion expression. */
+ type = make_pack_expansion (type);
+ }
/* Add it to the list. */
types = add_exception_specifier (types, type, /*complain=*/1);
/* Peek at the next token. */
{
arguments = cp_parser_parenthesized_expression_list
(parser, true, /*cast_p=*/false,
+ /*allow_expansion_p=*/false,
/*non_constant_p=*/NULL);
/* Save the arguments away. */
TREE_VALUE (attribute) = arguments;
decl = cp_parser_single_declaration (parser,
checks,
member_p,
+ /*explicit_specialization_p=*/false,
&friend_p);
pop_deferring_access_checks ();
cp_parser_single_declaration (cp_parser* parser,
VEC (deferred_access_check,gc)* checks,
bool member_p,
+ bool explicit_specialization_p,
bool* friend_p)
{
int declares_class_or_enum;
if (!decl
&& (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
|| decl_specifiers.type != error_mark_node))
- decl = cp_parser_init_declarator (parser,
- &decl_specifiers,
- checks,
- /*function_definition_allowed_p=*/true,
- member_p,
- declares_class_or_enum,
- &function_definition_p);
+ {
+ decl = cp_parser_init_declarator (parser,
+ &decl_specifiers,
+ checks,
+ /*function_definition_allowed_p=*/true,
+ member_p,
+ declares_class_or_enum,
+ &function_definition_p);
+
+ /* 7.1.1-1 [dcl.stc]
+
+ A storage-class-specifier shall not be specified in an explicit
+ specialization... */
+ if (decl
+ && explicit_specialization_p
+ && decl_specifiers.storage_class != sc_none)
+ {
+ error ("explicit template specialization cannot have a storage class");
+ decl = error_mark_node;
+ }
+ }
pop_deferring_access_checks ();
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
/*cast_p=*/true,
+ /*allow_expansion_p=*/true,
/*non_constant_p=*/NULL);
cast = build_functional_cast (type, expression_list);
saved_skip_evaluation = skip_evaluation;
skip_evaluation = false;
/* Parse the template-argument-list itself. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
+ if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER)
+ || cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
arguments = NULL_TREE;
else
arguments = cp_parser_template_argument_list (parser);
a '>>' instead, it's probably just a typo. */
if (cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
{
- if (!saved_greater_than_is_operator_p)
+ if (cxx_dialect != cxx98)
+ {
+ /* In C++0x, a `>>' in a template argument list or cast
+ expression is considered to be two separate `>'
+ tokens. So, change the current token to a `>', but don't
+ consume it: it will be consumed later when the outer
+ template argument list (or cast expression) is parsed.
+ Note that this replacement of `>' for `>>' is necessary
+ even if we are parsing tentatively: in the tentative
+ case, after calling
+ cp_parser_enclosed_template_argument_list we will always
+ throw away all of the template arguments and the first
+ closing `>', either because the template argument list
+ was erroneous or because we are replacing those tokens
+ with a CPP_TEMPLATE_ID token. The second `>' (which will
+ not have been thrown away) is needed either to close an
+ outer template argument list or to complete a new-style
+ cast. */
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ token->type = CPP_GREATER;
+ }
+ else if (!saved_greater_than_is_operator_p)
{
/* If we're in a nested template argument list, the '>>' has
to be a typo for '> >'. We emit the error message, but we
"within a nested template argument list",
&token->location);
- /* ??? Proper recovery should terminate two levels of
- template argument list here. */
token->type = CPP_GREATER;
}
else
const char *saved_message;
bool saved_integral_constant_expression_p;
bool saved_non_integral_constant_expression_p;
+ bool pack_expansion_p = false;
/* Initialize FORMAT the first time we get here. */
if (!format)
= parser->non_integral_constant_expression_p;
parser->integral_constant_expression_p = false;
+ /* If it's a `...', then we are computing the length of a parameter
+ pack. */
+ if (keyword == RID_SIZEOF
+ && cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ /* Consume the `...'. */
+ cp_lexer_consume_token (parser->lexer);
+ maybe_warn_variadic_templates ();
+
+ /* Note that this is an expansion. */
+ pack_expansion_p = true;
+ }
+
/* Do not actually evaluate the expression. */
++skip_evaluation;
/* If it's a `(', then we might be looking at the type-id
if (!expr)
expr = cp_parser_unary_expression (parser, /*address_p=*/false,
/*cast_p=*/false);
+
+ if (pack_expansion_p)
+ /* Build a pack expansion. */
+ expr = make_pack_expansion (expr);
+
/* Go back to evaluating expressions. */
--skip_evaluation;
++level;
break;
+ case CPP_RSHIFT:
+ if (cxx_dialect == cxx98)
+ /* C++0x views the `>>' operator as two `>' tokens, but
+ C++98 does not. */
+ break;
+ else if (!nesting_depth && level-- == 0)
+ {
+ /* We've hit a `>>' where the first `>' closes the
+ template argument list, and the second `>' is
+ spurious. Just consume the `>>' and stop; we've
+ already produced at least one error. */
+ cp_lexer_consume_token (parser->lexer);
+ return;
+ }
+ /* Fall through for C++0x, so we handle the second `>' in
+ the `>>'. */
+
case CPP_GREATER:
if (!nesting_depth && level-- == 0)
{
return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON);
}
-/* Returns TRUE iff the next token is the "," or ">" ending a
- template-argument. */
+/* Returns TRUE iff the next token is the "," or ">" (or `>>', in
+ C++0x) ending a template-argument. */
static bool
cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
- return (token->type == CPP_COMMA || token->type == CPP_GREATER);
+ return (token->type == CPP_COMMA
+ || token->type == CPP_GREATER
+ || token->type == CPP_ELLIPSIS
+ || ((cxx_dialect != cxx98) && token->type == CPP_RSHIFT));
}
/* Returns TRUE iff the n-th token is a "<", or the n-th is a "[" and the