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;
}
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;
}
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;
}
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
}
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;
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;
/* 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))
+ {
+
+ /* 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;
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;
}
}
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);
/* 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 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 (DECL_P (type))
+ type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) != TYPE_PACK_EXPANSION
+ && (!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;
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);
: 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;
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);
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;
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);
}
/* Returns TRUE iff the n-th token is a "<", or the n-th is a "[" and the
tsubst_flags_t, int, tree);
static int for_each_template_parm (tree, tree_fn_t, void*,
struct pointer_set_t*);
+static tree expand_template_argument_pack (tree);
static tree build_template_parm_index (int, int, int, tree, tree);
static int inline_needs_template_parms (tree);
static void push_inline_template_parms_recursive (tree, int);
static tree get_bindings (tree, tree, tree, bool);
static int template_decl_level (tree);
static int check_cv_quals_for_unify (int, tree, tree);
+static void template_parm_level_and_index (tree, int*, int*);
+static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool);
static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
static void copy_default_args_to_explicit_spec (tree);
static int invalid_nontype_parm_type_p (tree, tsubst_flags_t);
static int eq_local_specializations (const void *, const void *);
+static bool dependent_template_arg_p (tree);
static bool any_template_arguments_need_structural_equality_p (tree);
static bool dependent_type_p_r (tree);
static tree tsubst (tree, tree, tsubst_flags_t, tree);
static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
+static tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
if (TREE_CODE (parm1) != TREE_CODE (parm2))
return 0;
- if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM)
+ if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM
+ && (TEMPLATE_TYPE_PARAMETER_PACK (parm1)
+ == TEMPLATE_TYPE_PARAMETER_PACK (parm2)))
continue;
else if (!same_type_p (TREE_TYPE (parm1), TREE_TYPE (parm2)))
return 0;
return 1;
}
+/* Determine whether PARM is a parameter pack. */
+bool
+template_parameter_pack_p (tree parm)
+{
+ /* Determine if we have a non-type template parameter pack. */
+ if (TREE_CODE (parm) == PARM_DECL)
+ return (DECL_TEMPLATE_PARM_P (parm)
+ && TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)));
+
+ /* If this is a list of template parameters, we could get a
+ TYPE_DECL or a TEMPLATE_DECL. */
+ if (TREE_CODE (parm) == TYPE_DECL || TREE_CODE (parm) == TEMPLATE_DECL)
+ parm = TREE_TYPE (parm);
+
+ return ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
+ && TEMPLATE_TYPE_PARAMETER_PACK (parm));
+}
+
+/* Determine whether PARMS describes a variadic template parameter
+ list, i.e., one that is terminated by a template parameter pack. */
+bool
+template_parms_variadic_p (tree parms)
+{
+ int nparms = TREE_VEC_LENGTH (parms);
+ tree last_parm = TREE_VALUE (TREE_VEC_ELT (parms, nparms - 1));
+
+ return template_parameter_pack_p (last_parm);
+}
+
+/* Determine whether ARGS describes a variadic template args list,
+ i.e., one that is terminated by a template argument pack. */
+static bool
+template_args_variadic_p (tree args)
+{
+ int nargs;
+ tree last_parm;
+
+ if (args == NULL_TREE)
+ return false;
+
+ args = INNERMOST_TEMPLATE_ARGS (args);
+ nargs = TREE_VEC_LENGTH (args);
+
+ if (nargs == 0)
+ return false;
+
+ last_parm = TREE_VEC_ELT (args, nargs - 1);
+
+ return ARGUMENT_PACK_P (last_parm);
+}
+
+/* Generate a new name for the parameter pack name NAME (an
+ IDENTIFIER_NODE) that incorporates its */
+static tree
+make_ith_pack_parameter_name (tree name, int i)
+{
+ /* Munge the name to include the parameter index. */
+ char numbuf[128];
+ char* newname;
+
+ sprintf(numbuf, "%i", i);
+ newname = (char*)alloca (IDENTIFIER_LENGTH (name) + strlen(numbuf) + 2);
+ sprintf(newname, "%s#%i", IDENTIFIER_POINTER (name), i);
+ return get_identifier (newname);
+}
+
+/* Structure used to track the progress of find_parameter_pack_r. */
+struct find_parameter_pack_data
+{
+ tree* parameter_packs;
+ struct pointer_set_t *visited;
+};
+
+/* Identifiers all of the argument packs that occur in a template
+ argument and appends them to the TREE_LIST inside DATA, which is a
+ find_parameter_pack_Data structure. This is a subroutine of
+ make_pack_expansion and uses_parameter_packs. */
+static tree
+find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
+{
+ tree t = *tp;
+ struct find_parameter_pack_data* ppd =
+ (struct find_parameter_pack_data*)data;
+
+ if (TYPE_P (t))
+ {
+ tree context = TYPE_CONTEXT (t);
+ walk_tree (&context, &find_parameter_packs_r, ppd, ppd->visited);
+ }
+
+ /* This switch statement will return immediately if we don't find a
+ parameter pack. */
+ switch (TREE_CODE (t))
+ {
+ case TEMPLATE_PARM_INDEX:
+ if (TEMPLATE_PARM_PARAMETER_PACK (t))
+ break;
+ return NULL_TREE;
+
+ case BOUND_TEMPLATE_TEMPLATE_PARM:
+ /* Check the template arguments. */
+ walk_tree (&TYPE_TI_ARGS (t), &find_parameter_packs_r, ppd,
+ ppd->visited);
+
+ /* Dig out the underlying TEMPLATE_TEMPLATE_PARM. */
+ t = TYPE_TI_TEMPLATE (t);
+ if (DECL_P (t) && TREE_TYPE (t))
+ t = TREE_TYPE (t);
+ *walk_subtrees = 0;
+
+ /* Fall through. */
+
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ if (TEMPLATE_TYPE_PARAMETER_PACK (t))
+ break;
+ return NULL_TREE;
+
+ case PARM_DECL:
+ if (FUNCTION_PARAMETER_PACK_P (t))
+ {
+ /* We don't want to walk into the type of a PARM_DECL,
+ because we don't want to see the type parameter pack.*/
+ *walk_subtrees = 0;
+ break;
+ }
+ return NULL_TREE;
+
+ case RECORD_TYPE:
+ if (TYPE_PTRMEMFUNC_P (t))
+ return NULL_TREE;
+ /* Fall through. */
+
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ if (TYPE_TEMPLATE_INFO (t))
+ {
+ tree args = TREE_VALUE (TYPE_TEMPLATE_INFO (t));
+ walk_tree (&args, &find_parameter_packs_r, ppd, ppd->visited);
+ }
+
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ case TEMPLATE_DECL:
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t)
+ && TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (t)))
+ break;
+
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ case TYPE_PACK_EXPANSION:
+ case EXPR_PACK_EXPANSION:
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ default:
+ return NULL_TREE;
+ }
+
+ /* Add this parameter pack to the list. */
+ *ppd->parameter_packs = tree_cons (NULL_TREE, t, *ppd->parameter_packs);
+
+ return NULL_TREE;
+}
+
+/* Determines if the expression or type T uses any parameter packs. */
+bool
+uses_parameter_packs (tree t)
+{
+ tree parameter_packs = NULL_TREE;
+ struct find_parameter_pack_data ppd;
+ ppd.parameter_packs = ¶meter_packs;
+ ppd.visited = pointer_set_create ();
+ walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
+ return parameter_packs != NULL_TREE;
+}
+
+/* Turn ARG, which may be an expression, type, or a TREE_LIST
+ representation a base-class initializer into a parameter pack
+ expansion. If all goes well, the resulting node will be an
+ EXPR_PACK_EXPANSION, TYPE_PACK_EXPANSION, or TREE_LIST,
+ respectively. */
+tree
+make_pack_expansion (tree arg)
+{
+ tree result;
+ tree parameter_packs = NULL_TREE;
+ bool for_types = false;
+ struct find_parameter_pack_data ppd;
+
+ if (!arg || arg == error_mark_node)
+ return arg;
+
+ if (TREE_CODE (arg) == TREE_LIST)
+ {
+ /* The only time we will see a TREE_LIST here is for a base
+ class initializer. In this case, the TREE_PURPOSE will be a
+ _TYPE node (representing the base class expansion we're
+ initializing) and the TREE_VALUE will be a TREE_LIST
+ containing the initialization arguments.
+
+ The resulting expansion looks somewhat different from most
+ expansions. Rather than returning just one _EXPANSION, we
+ return a TREE_LIST whose TREE_PURPOSE is a
+ TYPE_PACK_EXPANSION containing the bases that will be
+ initialized. The TREE_VALUE will be identical to the
+ original TREE_VALUE, which is a list of arguments that will
+ be passed to each base. We do not introduce any new pack
+ expansion nodes into the TREE_VALUE (although it is possible
+ that some already exist), because the TREE_PURPOSE and
+ TREE_VALUE all need to be expanded together with the same
+ _EXPANSION node. Note that the TYPE_PACK_EXPANSION in the
+ resulting TREE_PURPOSE will mention the parameter packs in
+ both the bases and the arguments to the bases. */
+ tree purpose;
+ tree value;
+ tree parameter_packs = NULL_TREE;
+
+ /* Determine which parameter packs will be used by the base
+ class expansion. */
+ ppd.visited = pointer_set_create ();
+ ppd.parameter_packs = ¶meter_packs;
+ walk_tree (&TREE_PURPOSE (arg), &find_parameter_packs_r,
+ &ppd, ppd.visited);
+
+ if (parameter_packs == NULL_TREE)
+ {
+ error ("base initializer expansion %<%T%> contains no parameter packs", arg);
+ return error_mark_node;
+ }
+
+ if (TREE_VALUE (arg) != void_type_node)
+ {
+ /* Collect the sets of parameter packs used in each of the
+ initialization arguments. */
+ for (value = TREE_VALUE (arg); value; value = TREE_CHAIN (value))
+ {
+ /* Determine which parameter packs will be expanded in this
+ argument. */
+ walk_tree (&TREE_VALUE (value), &find_parameter_packs_r,
+ &ppd, ppd.visited);
+ }
+ }
+
+ /* Create the pack expansion type for the base type. */
+ purpose = make_node (TYPE_PACK_EXPANSION);
+ SET_PACK_EXPANSION_PATTERN (purpose, TREE_PURPOSE (arg));
+ PACK_EXPANSION_PARAMETER_PACKS (purpose) = parameter_packs;
+
+ /* Just use structural equality for these TYPE_PACK_EXPANSIONS;
+ they will rarely be compared to anything. */
+ SET_TYPE_STRUCTURAL_EQUALITY (purpose);
+
+ return tree_cons (purpose, TREE_VALUE (arg), NULL_TREE);
+ }
+
+ if (TYPE_P (arg) || TREE_CODE (arg) == TEMPLATE_DECL)
+ for_types = true;
+
+ /* Build the PACK_EXPANSION_* node. */
+ result = make_node (for_types ? TYPE_PACK_EXPANSION : EXPR_PACK_EXPANSION);
+ SET_PACK_EXPANSION_PATTERN (result, arg);
+ if (TREE_CODE (result) == EXPR_PACK_EXPANSION)
+ {
+ /* Propagate type and const-expression information. */
+ TREE_TYPE (result) = TREE_TYPE (arg);
+ TREE_CONSTANT (result) = TREE_CONSTANT (arg);
+ }
+ else
+ /* Just use structural equality for these TYPE_PACK_EXPANSIONS;
+ they will rarely be compared to anything. */
+ SET_TYPE_STRUCTURAL_EQUALITY (result);
+
+ /* Determine which parameter packs will be expanded. */
+ ppd.parameter_packs = ¶meter_packs;
+ ppd.visited = pointer_set_create ();
+ walk_tree (&arg, &find_parameter_packs_r, &ppd, ppd.visited);
+
+ /* Make sure we found some parameter packs. */
+ if (parameter_packs == NULL_TREE)
+ {
+ if (TYPE_P (arg))
+ error ("expansion pattern %<%T%> contains no argument packs", arg);
+ else
+ error ("expansion pattern %<%E%> contains no argument packs", arg);
+ return error_mark_node;
+ }
+ PACK_EXPANSION_PARAMETER_PACKS (result) = parameter_packs;
+
+ return result;
+}
+
+/* Checks T for any "bare" parameter packs, which have not yet been
+ expanded, and issues an error if any are found. This operation can
+ only be done on full expressions or types (e.g., an expression
+ statement, "if" condition, etc.), because we could have expressions like:
+
+ foo(f(g(h(args)))...)
+
+ where "args" is a parameter pack. check_for_bare_parameter_packs
+ should not be called for the subexpressions args, h(args),
+ g(h(args)), or f(g(h(args))), because we would produce erroneous
+ error messages. */
+void
+check_for_bare_parameter_packs (tree t)
+{
+ tree parameter_packs = NULL_TREE;
+ struct find_parameter_pack_data ppd;
+
+ if (!processing_template_decl || !t || t == error_mark_node)
+ return;
+
+ if (TREE_CODE (t) == TYPE_DECL)
+ t = TREE_TYPE (t);
+
+ ppd.parameter_packs = ¶meter_packs;
+ ppd.visited = pointer_set_create ();
+ walk_tree (&t, &find_parameter_packs_r, &ppd, ppd.visited);
+
+ if (parameter_packs) {
+ error ("parameter packs not expanded with `...':");
+ while (parameter_packs)
+ {
+ tree pack = TREE_VALUE (parameter_packs);
+ tree name = NULL_TREE;
+
+ if (TREE_CODE (pack) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (pack) == TEMPLATE_TEMPLATE_PARM)
+ name = TYPE_NAME (pack);
+ else
+ name = DECL_NAME (pack);
+ inform (" %qD", name);
+
+ parameter_packs = TREE_CHAIN (parameter_packs);
+ }
+ }
+}
+
+/* Expand any parameter packs that occur in the template arguments in
+ ARGS. */
+tree
+expand_template_argument_pack (tree args)
+{
+ tree result_args = NULL_TREE;
+ int in_arg, out_arg = 0, nargs = args ? TREE_VEC_LENGTH (args) : 0;
+ int num_result_args = -1;
+
+ /* First, determine if we need to expand anything, and the number of
+ slots we'll need. */
+ for (in_arg = 0; in_arg < nargs; ++in_arg)
+ {
+ tree arg = TREE_VEC_ELT (args, in_arg);
+ if (ARGUMENT_PACK_P (arg))
+ {
+ int num_packed = TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg));
+ if (num_result_args < 0)
+ num_result_args = in_arg + num_packed;
+ else
+ num_result_args += num_packed;
+ }
+ else
+ {
+ if (num_result_args >= 0)
+ num_result_args++;
+ }
+ }
+
+ /* If no expansion is necessary, we're done. */
+ if (num_result_args < 0)
+ return args;
+
+ /* Expand arguments. */
+ result_args = make_tree_vec (num_result_args);
+ for (in_arg = 0; in_arg < nargs; ++in_arg)
+ {
+ tree arg = TREE_VEC_ELT (args, in_arg);
+ if (ARGUMENT_PACK_P (arg))
+ {
+ tree packed = ARGUMENT_PACK_ARGS (arg);
+ int i, num_packed = TREE_VEC_LENGTH (packed);
+ for (i = 0; i < num_packed; ++i, ++out_arg)
+ TREE_VEC_ELT (result_args, out_arg) = TREE_VEC_ELT(packed, i);
+ }
+ else
+ {
+ TREE_VEC_ELT (result_args, out_arg) = arg;
+ ++out_arg;
+ }
+ }
+
+ return result_args;
+}
+
/* Complain if DECL shadows a template parameter.
[temp.local]: A template-parameter shall not be redeclared within its
TEMPLATE_PARM_ORIG_LEVEL (index),
decl, type);
TEMPLATE_PARM_DESCENDANTS (index) = t;
+ TEMPLATE_PARM_PARAMETER_PACK (t)
+ = TEMPLATE_PARM_PARAMETER_PACK (index);
/* Template template parameters need this. */
if (TREE_CODE (decl) != CONST_DECL)
/* Process information from new template parameter PARM and append it to the
LIST being built. This new parameter is a non-type parameter iff
- IS_NON_TYPE is true. */
+ IS_NON_TYPE is true. This new parameter is a parameter
+ pack iff IS_PARAMETER_PACK is true. */
tree
-process_template_parm (tree list, tree parm, bool is_non_type)
+process_template_parm (tree list, tree parm, bool is_non_type,
+ bool is_parameter_pack)
{
tree decl = 0;
tree defval;
TREE_VALUE (err_parm_list) = error_mark_node;
return chainon (list, err_parm_list);
}
+
+ if (uses_parameter_packs (TREE_TYPE (parm)) && !is_parameter_pack)
+ {
+ /* This template parameter is not a parameter pack, but it
+ should be. Complain about "bare" parameter packs. */
+ check_for_bare_parameter_packs (TREE_TYPE (parm));
+
+ /* Recover by calling this a parameter pack. */
+ is_parameter_pack = true;
+ }
}
/* A template parameter is not modifiable. */
= build_template_parm_index (idx, processing_template_decl,
processing_template_decl,
decl, TREE_TYPE (parm));
+
+ TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
+ = is_parameter_pack;
}
else
{
= build_template_parm_index (idx, processing_template_decl,
processing_template_decl,
decl, TREE_TYPE (parm));
+ TEMPLATE_TYPE_PARAMETER_PACK (t) = is_parameter_pack;
TYPE_CANONICAL (t) = canonical_type_parameter (t);
}
DECL_ARTIFICIAL (decl) = 1;
{
if (TREE_CODE (t) == TYPE_DECL
|| TREE_CODE (t) == TEMPLATE_DECL)
- t = TREE_TYPE (t);
- else
- t = DECL_INITIAL (t);
- }
-
+ {
+ t = TREE_TYPE (t);
+
+ if (TEMPLATE_TYPE_PARAMETER_PACK (t))
+ {
+ /* Turn this argument into a TYPE_ARGUMENT_PACK
+ with a single element, which expands T. */
+ tree vec = make_tree_vec (1);
+ TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+
+ t = make_node (TYPE_ARGUMENT_PACK);
+ SET_ARGUMENT_PACK_ARGS (t, vec);
+ }
+ }
+ else
+ {
+ t = DECL_INITIAL (t);
+
+ if (TEMPLATE_PARM_PARAMETER_PACK (t))
+ {
+ /* Turn this argument into a NONTYPE_ARGUMENT_PACK
+ with a single element, which expands T. */
+ tree vec = make_tree_vec (1);
+ tree type = TREE_TYPE (TEMPLATE_PARM_DECL (t));
+ TREE_VEC_ELT (vec, 0) = make_pack_expansion (t);
+
+ t = make_node (NONTYPE_ARGUMENT_PACK);
+ SET_ARGUMENT_PACK_ARGS (t, vec);
+ TREE_TYPE (t) = type;
+ }
+ }
+ }
TREE_VEC_ELT (a, i) = t;
}
}
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
- specialization. */
+ specialization.
+
+ Also, we verify that pack expansions only occur at the
+ end of the argument list. */
gcc_assert (nargs == DECL_NTPARMS (maintmpl));
tpd2.parms = 0;
for (i = 0; i < nargs; ++i)
{
+ tree parm = TREE_VALUE (TREE_VEC_ELT (main_inner_parms, i));
tree arg = TREE_VEC_ELT (inner_args, i);
- if (/* These first two lines are the `non-type' bit. */
- !TYPE_P (arg)
- && TREE_CODE (arg) != TEMPLATE_DECL
- /* This next line is the `argument expression is not just a
- simple identifier' condition and also the `specialized
- non-type argument' bit. */
- && TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
- {
- if (tpd.arg_uses_template_parms[i])
- error ("template argument %qE involves template parameter(s)", arg);
- else
- {
- /* Look at the corresponding template parameter,
- marking which template parameters its type depends
- upon. */
- tree type =
- TREE_TYPE (TREE_VALUE (TREE_VEC_ELT (main_inner_parms,
- i)));
-
- if (!tpd2.parms)
- {
- /* We haven't yet initialized TPD2. Do so now. */
- tpd2.arg_uses_template_parms
- = (int *) alloca (sizeof (int) * nargs);
- /* The number of parameters here is the number in the
- main template, which, as checked in the assertion
- above, is NARGS. */
- tpd2.parms = (int *) alloca (sizeof (int) * nargs);
- tpd2.level =
- TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
- }
+ tree packed_args = NULL_TREE;
+ int j, len = 1;
- /* Mark the template parameters. But this time, we're
- looking for the template parameters of the main
- template, not in the specialization. */
- tpd2.current_arg = i;
- tpd2.arg_uses_template_parms[i] = 0;
- memset (tpd2.parms, 0, sizeof (int) * nargs);
- for_each_template_parm (type,
- &mark_template_parm,
- &tpd2,
- NULL);
-
- if (tpd2.arg_uses_template_parms [i])
- {
- /* The type depended on some template parameters.
- If they are fully specialized in the
- specialization, that's OK. */
- int j;
- for (j = 0; j < nargs; ++j)
- if (tpd2.parms[j] != 0
- && tpd.arg_uses_template_parms [j])
- {
- error ("type %qT of template argument %qE depends "
- "on template parameter(s)",
- type,
- arg);
- break;
- }
- }
- }
- }
+ if (ARGUMENT_PACK_P (arg))
+ {
+ /* Extract the arguments from the argument pack. We'll be
+ iterating over these in the following loop. */
+ packed_args = ARGUMENT_PACK_ARGS (arg);
+ len = TREE_VEC_LENGTH (packed_args);
+ }
+
+ for (j = 0; j < len; j++)
+ {
+ if (packed_args)
+ /* Get the Jth argument in the parameter pack. */
+ arg = TREE_VEC_ELT (packed_args, j);
+
+ if (PACK_EXPANSION_P (arg))
+ {
+ /* Pack expansions must come at the end of the
+ argument list. */
+ if ((packed_args && j < len - 1)
+ || (!packed_args && i < nargs - 1))
+ {
+ if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+ error ("parameter pack argument %qE must be at the end of the template argument list", arg);
+ else
+ error ("parameter pack argument %qT must be at the end of the template argument list", arg);
+ }
+ }
+
+ if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+ /* We only care about the pattern. */
+ arg = PACK_EXPANSION_PATTERN (arg);
+
+ if (/* These first two lines are the `non-type' bit. */
+ !TYPE_P (arg)
+ && TREE_CODE (arg) != TEMPLATE_DECL
+ /* This next line is the `argument expression is not just a
+ simple identifier' condition and also the `specialized
+ non-type argument' bit. */
+ && TREE_CODE (arg) != TEMPLATE_PARM_INDEX)
+ {
+ if ((!packed_args && tpd.arg_uses_template_parms[i])
+ || (packed_args && uses_template_parms (arg)))
+ error ("template argument %qE involves template parameter(s)",
+ arg);
+ else
+ {
+ /* Look at the corresponding template parameter,
+ marking which template parameters its type depends
+ upon. */
+ tree type = TREE_TYPE (parm);
+
+ if (!tpd2.parms)
+ {
+ /* We haven't yet initialized TPD2. Do so now. */
+ tpd2.arg_uses_template_parms
+ = (int *) alloca (sizeof (int) * nargs);
+ /* The number of parameters here is the number in the
+ main template, which, as checked in the assertion
+ above, is NARGS. */
+ tpd2.parms = (int *) alloca (sizeof (int) * nargs);
+ tpd2.level =
+ TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl));
+ }
+
+ /* Mark the template parameters. But this time, we're
+ looking for the template parameters of the main
+ template, not in the specialization. */
+ tpd2.current_arg = i;
+ tpd2.arg_uses_template_parms[i] = 0;
+ memset (tpd2.parms, 0, sizeof (int) * nargs);
+ for_each_template_parm (type,
+ &mark_template_parm,
+ &tpd2,
+ NULL);
+
+ if (tpd2.arg_uses_template_parms [i])
+ {
+ /* The type depended on some template parameters.
+ If they are fully specialized in the
+ specialization, that's OK. */
+ int j;
+ for (j = 0; j < nargs; ++j)
+ if (tpd2.parms[j] != 0
+ && tpd.arg_uses_template_parms [j])
+ {
+ error ("type %qT of template argument %qE depends "
+ "on template parameter(s)",
+ type,
+ arg);
+ break;
+ }
+ }
+ }
+ }
+ }
}
if (retrieve_specialization (maintmpl, specargs,
check_default_tmpl_args (decl, current_template_parms,
primary, is_partial);
+ /* Ensure that there are no parameter packs in the type of this
+ declaration that have not been expanded. */
+ check_for_bare_parameter_packs (TREE_TYPE (decl));
+
if (is_partial)
return process_partial_specialization (decl);
+ /* A primary class template can only have one parameter pack, at the
+ end of the template parameter list. */
+ if (primary && TREE_CODE (decl) == TYPE_DECL)
+ {
+ tree inner_parms
+ = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+ int i, len = TREE_VEC_LENGTH (inner_parms);
+ for (i = 0; i < len - 1; i++)
+ {
+ tree parm = TREE_VALUE (TREE_VEC_ELT (inner_parms, i));
+
+ if (template_parameter_pack_p (parm))
+ {
+ if (TREE_CODE (parm) == PARM_DECL)
+ error ("parameter pack %qE must be at the end of the"
+ " template parameter list", parm);
+ else
+ error ("parameter pack %qT must be at the end of the"
+ " template parameter list", TREE_TYPE (parm));
+ }
+ }
+ }
+
args = current_template_args ();
if (!ctx
switch (TREE_CODE (parm))
{
- case TYPE_DECL:
- break;
-
case TEMPLATE_DECL:
/* We encounter instantiations of templates like
template <template <template <class> class> class TT>
(parmparm, argparm, complain, in_decl, outer_args))
return 0;
}
+ /* Fall through. */
+
+ case TYPE_DECL:
+ if (TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))
+ != TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (arg)))
+ /* One is a parameter pack, the other is not. */
+ return 0;
break;
case PARM_DECL:
(tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),
TREE_TYPE (arg)))
return 0;
+
+ if (TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))
+ != TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (arg)))
+ /* One is a parameter pack, the other is not. */
+ return 0;
break;
default:
{
tree val;
int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
+ tree check_arg = arg;
if (TREE_CODE (arg) == TREE_LIST
&& TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
requires_type = (TREE_CODE (parm) == TYPE_DECL
|| requires_tmpl_type);
- is_tmpl_type = ((TREE_CODE (arg) == TEMPLATE_DECL
- && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
- || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
- || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);
+ /* When determining whether a argument pack expansion is a template,
+ look at the pattern. */
+ if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
+ check_arg = PACK_EXPANSION_PATTERN (check_arg);
+
+ is_tmpl_type =
+ ((TREE_CODE (check_arg) == TEMPLATE_DECL
+ && TREE_CODE (DECL_TEMPLATE_RESULT (check_arg)) == TYPE_DECL)
+ || TREE_CODE (check_arg) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (check_arg) == UNBOUND_CLASS_TEMPLATE);
if (is_tmpl_type
&& (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
else
{
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
- tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+ tree argparm;
+
+ check_arg = arg;
+ /* When determining whether a pack expansion is a template,
+ look at the pattern. */
+ if (TREE_CODE (check_arg) == TYPE_PACK_EXPANSION)
+ check_arg = PACK_EXPANSION_PATTERN (check_arg);
+
+ argparm = DECL_INNERMOST_TEMPLATE_PARMS (check_arg);
if (coerce_template_template_parms (parmparm, argparm,
complain, in_decl,
/* TEMPLATE_TEMPLATE_PARM node is preferred over
TEMPLATE_DECL. */
- if (val != error_mark_node
- && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
- val = TREE_TYPE (val);
+ if (val != error_mark_node)
+ {
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (val))
+ val = TREE_TYPE (val);
+ else if (TREE_CODE (val) == TYPE_PACK_EXPANSION
+ && DECL_TEMPLATE_TEMPLATE_PARM_P (check_arg))
+ {
+ val = TREE_TYPE (check_arg);
+ val = make_pack_expansion (val);
+ }
+ }
}
else
{
tree new_inner_args;
bool saved_skip_evaluation;
- inner_args = INNERMOST_TEMPLATE_ARGS (args);
+ /* When used as a boolean value, indicates whether this is a
+ variadic template parameter list. Since it's an int, we can also
+ subtract it from nparms to get the number of non-variadic
+ parameters. */
+ int variadic_p = template_parms_variadic_p (parms) ? 1 : 0;
+
+ inner_args
+ = expand_template_argument_pack (INNERMOST_TEMPLATE_ARGS (args));
+
nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
nparms = TREE_VEC_LENGTH (parms);
- if (nargs > nparms
- || (nargs < nparms
+ if ((nargs > nparms - variadic_p && !variadic_p)
+ || (nargs < nparms - variadic_p
&& require_all_args
&& (!use_default_args
|| (TREE_VEC_ELT (parms, nargs) != error_mark_node
{
if (complain & tf_error)
{
- error ("wrong number of template arguments (%d, should be %d)",
- nargs, nparms);
+ const char *or_more = "";
+ if (variadic_p)
+ {
+ or_more = " or more";
+ --nparms;
+ }
+
+ error ("wrong number of template arguments (%d, should be %d%s)",
+ nargs, nparms, or_more);
if (in_decl)
error ("provided for %q+D", in_decl);
skip_evaluation = false;
new_inner_args = make_tree_vec (nparms);
new_args = add_outermost_template_args (args, new_inner_args);
- for (i = 0; i < nparms; i++)
+ for (i = 0; i < nparms - variadic_p; i++)
{
tree arg;
tree parm;
/* Calculate the Ith argument. */
if (i < nargs)
- arg = TREE_VEC_ELT (inner_args, i);
+ {
+ arg = TREE_VEC_ELT (inner_args, i);
+
+ if (PACK_EXPANSION_P (arg))
+ {
+ /* If ARG is a pack expansion, then PARM must be
+ a template parameter pack. We can't expand into a
+ fixed-length argument list. */
+ tree actual_parm = TREE_VALUE (parm);
+ bool parm_is_parameter_pack
+ = template_parameter_pack_p (actual_parm);
+
+ if (!parm_is_parameter_pack)
+ {
+ if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
+ error ("cannot expand %<%E%> into a fixed-length "
+ "argument list", arg);
+ else
+ error ("cannot expand %<%T%> into a fixed-length "
+ "argument list", arg);
+ }
+ }
+ }
else if (require_all_args)
/* There must be a default arg in this case. */
arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
}
skip_evaluation = saved_skip_evaluation;
+ if (variadic_p)
+ {
+ int expected_len = nargs - nparms + 1;
+ tree parm = TREE_VEC_ELT (parms, nparms - 1);
+ tree packed_args;
+ tree argument_pack;
+ tree packed_types = NULL_TREE;
+
+ packed_args = make_tree_vec (expected_len >= 0 ? expected_len : 0);
+
+ if (TREE_CODE (TREE_VALUE (parm)) == PARM_DECL
+ && uses_parameter_packs (TREE_TYPE (TREE_VALUE (parm))))
+ {
+ /* When the template parameter is a non-type template
+ parameter pack whose type uses parameter packs, we need
+ to look at each of the template arguments
+ separately. Build a vector of the types for these
+ non-type template parameters in PACKED_TYPES. */
+ tree expansion
+ = make_pack_expansion (TREE_TYPE (TREE_VALUE (parm)));
+ packed_types = tsubst_pack_expansion (expansion, args,
+ complain, in_decl);
+
+ if (packed_types == error_mark_node)
+ return error_mark_node;
+
+ /* Check that we have the right number of arguments. */
+ if (i < nargs
+ && !PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i))
+ && nargs - i != TREE_VEC_LENGTH (packed_types))
+ {
+ error ("wrong number of template arguments (%d, should be %d)",
+ nargs, nparms - 1 + TREE_VEC_LENGTH (packed_types));
+ return error_mark_node;
+ }
+
+ /* If we aren't able to check the actual arguments now
+ (because they haven't been expanded yet), we can at least
+ verify that all of the types used for the non-type
+ template parameter pack are, in fact, valid for non-type
+ template parameters. */
+ if (i < nargs && PACK_EXPANSION_P (TREE_VEC_ELT (inner_args, i)))
+ {
+ int j, len = TREE_VEC_LENGTH (packed_types);
+ for (j = 0; j < len; ++j)
+ {
+ tree t = TREE_VEC_ELT (packed_types, j);
+ if (invalid_nontype_parm_type_p (t, complain))
+ return error_mark_node;
+ }
+ }
+ }
+
+ /* Convert the remaining arguments, which will be a part of the
+ parameter pack "parm". */
+ for (; i < nargs; ++i)
+ {
+ tree arg = TREE_VEC_ELT (inner_args, i);
+ tree actual_parm = TREE_VALUE (parm);
+
+ if (packed_types && !PACK_EXPANSION_P (arg))
+ {
+ /* When we have a vector of types (corresponding to the
+ non-type template parameter pack that uses parameter
+ packs in its type, as mention above), and the
+ argument is not an expansion (which expands to a
+ currently unknown number of arguments), clone the
+ parm and give it the next type in PACKED_TYPES. */
+ actual_parm = copy_node (actual_parm);
+ TREE_TYPE (actual_parm) =
+ TREE_VEC_ELT (packed_types, i - nparms + 1);
+ }
+
+ arg = convert_template_argument (actual_parm,
+ arg, new_args, complain, i,
+ in_decl);
+ if (arg == error_mark_node)
+ lost++;
+ TREE_VEC_ELT (packed_args, i - nparms + 1) = arg;
+ }
+
+ if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL
+ || TREE_CODE (TREE_VALUE (parm)) == TEMPLATE_DECL)
+ argument_pack = make_node (TYPE_ARGUMENT_PACK);
+ else
+ {
+ argument_pack = make_node (NONTYPE_ARGUMENT_PACK);
+ TREE_TYPE (argument_pack) = TREE_TYPE (TREE_VALUE (parm));
+ TREE_CONSTANT (argument_pack) = 1;
+ }
+
+ SET_ARGUMENT_PACK_ARGS (argument_pack, packed_args);
+ TREE_VEC_ELT (new_inner_args, nparms - 1) = argument_pack;
+ }
+
if (lost)
return error_mark_node;
if (TREE_CODE (nt) == TREE_VEC)
/* For member templates */
return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);
+ else if (PACK_EXPANSION_P (ot))
+ return PACK_EXPANSION_P (nt)
+ && template_args_equal (PACK_EXPANSION_PATTERN (ot),
+ PACK_EXPANSION_PATTERN (nt));
else if (TYPE_P (nt))
return TYPE_P (ot) && same_type_p (ot, nt);
else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))
{
int i;
+ oldargs = expand_template_argument_pack (oldargs);
+ newargs = expand_template_argument_pack (newargs);
+
if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))
return 0;
return error_mark_node;
break;
- case BASELINK:
- /* If we do not handle this case specially, we end up walking
- the BINFO hierarchy, which is circular, and therefore
- confuses walk_tree. */
- *walk_subtrees = 0;
- if (for_each_template_parm (BASELINK_FUNCTIONS (*tp), fn, data,
- pfd->visited))
- return error_mark_node;
- break;
-
default:
break;
}
{
tree base;
tree access = BINFO_BASE_ACCESS (pbinfo, i);
-
- /* Substitute to figure out the base class. */
- base = tsubst (BINFO_TYPE (pbase_binfo), args, tf_error, NULL_TREE);
- if (base == error_mark_node)
- continue;
-
- base_list = tree_cons (access, base, base_list);
- if (BINFO_VIRTUAL_P (pbase_binfo))
- TREE_TYPE (base_list) = integer_type_node;
+ tree expanded_bases = NULL_TREE;
+ int idx, len = 1;
+
+ if (PACK_EXPANSION_P (BINFO_TYPE (pbase_binfo)))
+ {
+ expanded_bases =
+ tsubst_pack_expansion (BINFO_TYPE (pbase_binfo),
+ args, tf_error, NULL_TREE);
+ if (expanded_bases == error_mark_node)
+ continue;
+
+ len = TREE_VEC_LENGTH (expanded_bases);
+ }
+
+ for (idx = 0; idx < len; idx++)
+ {
+ if (expanded_bases)
+ /* Extract the already-expanded base class. */
+ base = TREE_VEC_ELT (expanded_bases, idx);
+ else
+ /* Substitute to figure out the base class. */
+ base = tsubst (BINFO_TYPE (pbase_binfo), args, tf_error,
+ NULL_TREE);
+
+ if (base == error_mark_node)
+ continue;
+
+ base_list = tree_cons (access, base, base_list);
+ if (BINFO_VIRTUAL_P (pbase_binfo))
+ TREE_TYPE (base_list) = integer_type_node;
+ }
}
/* The list is now in reverse order; correct that. */
/*integral_constant_expression_p=*/true);
r = fold_non_dependent_expr (r);
}
- return r;
+ return r;
+}
+
+/* Substitute ARGS into T, which is an pack expansion
+ (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
+ TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node
+ (if only a partial substitution could be performed) or
+ ERROR_MARK_NODE if there was an error. */
+tree
+tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ tree pattern;
+ tree pack, packs = NULL_TREE, unsubstituted_packs = NULL_TREE;
+ tree first_arg_pack; int i, len = -1;
+ tree result;
+ int incomplete = 0;
+
+ gcc_assert (PACK_EXPANSION_P (t));
+ pattern = PACK_EXPANSION_PATTERN (t);
+
+ /* Determine the argument packs that will instantiate the parameter
+ packs used in the expansion expression. While we're at it,
+ compute the number of arguments to be expanded and make sure it
+ is consistent. */
+ for (pack = PACK_EXPANSION_PARAMETER_PACKS (t); pack;
+ pack = TREE_CHAIN (pack))
+ {
+ tree parm_pack = TREE_VALUE (pack);
+ tree arg_pack = NULL_TREE;
+ tree orig_arg = NULL_TREE;
+
+ if (TREE_CODE (parm_pack) == PARM_DECL)
+ {
+ if (local_specializations)
+ arg_pack = retrieve_local_specialization (parm_pack);
+ }
+ else
+ {
+ int level, idx, levels;
+ template_parm_level_and_index (parm_pack, &level, &idx);
+
+ levels = TMPL_ARGS_DEPTH (args);
+ if (level <= levels)
+ arg_pack = TMPL_ARG (args, level, idx);
+ }
+
+ orig_arg = arg_pack;
+ if (arg_pack && TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT)
+ arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack);
+
+ if (arg_pack)
+ {
+ int my_len =
+ TREE_VEC_LENGTH (ARGUMENT_PACK_ARGS (arg_pack));
+
+ /* It's all-or-nothing with incomplete argument packs. */
+ if (incomplete && !ARGUMENT_PACK_INCOMPLETE_P (arg_pack))
+ return error_mark_node;
+
+ if (ARGUMENT_PACK_INCOMPLETE_P (arg_pack))
+ incomplete = 1;
+
+ if (len < 0)
+ {
+ len = my_len;
+ first_arg_pack = arg_pack;
+ }
+ else if (len != my_len)
+ {
+ if (TREE_CODE (t) == TYPE_PACK_EXPANSION)
+ error ("mismatched argument pack lengths while expanding "
+ "%<%T%>",
+ pattern);
+ else
+ error ("mismatched argument pack lengths while expanding "
+ "%<%E%>",
+ pattern);
+ return error_mark_node;
+ }
+
+ /* Keep track of the parameter packs and their corresponding
+ argument packs. */
+ packs = tree_cons (parm_pack, arg_pack, packs);
+ TREE_TYPE (packs) = orig_arg;
+ }
+ else
+ /* We can't substitute for this parameter pack. */
+ unsubstituted_packs = tree_cons (TREE_PURPOSE (pack),
+ TREE_VALUE (pack),
+ unsubstituted_packs);
+ }
+
+ /* We cannot expand this expansion expression, because we don't have
+ all of the argument packs we need. Substitute into the pattern
+ and return a PACK_EXPANSION_*. The caller will need to deal with
+ that. */
+ if (unsubstituted_packs)
+ return make_pack_expansion (tsubst (pattern, args, complain,
+ in_decl));
+
+ /* We could not find any argument packs that work. */
+ if (len < 0)
+ return error_mark_node;
+
+ /* For each argument in each argument pack, substitute into the
+ pattern. */
+ result = make_tree_vec (len + incomplete);
+ for (i = 0; i < len + incomplete; ++i)
+ {
+ /* For parameter pack, change the substitution of the parameter
+ pack to the ith argument in its argument pack, then expand
+ the pattern. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ tree parm = TREE_PURPOSE (pack);
+
+ if (TREE_CODE (parm) == PARM_DECL)
+ {
+ /* Select the Ith argument from the pack. */
+ tree arg = make_node (ARGUMENT_PACK_SELECT);
+ ARGUMENT_PACK_SELECT_FROM_PACK (arg) = TREE_VALUE (pack);
+ ARGUMENT_PACK_SELECT_INDEX (arg) = i;
+ mark_used (parm);
+ register_local_specialization (arg, parm);
+ }
+ else
+ {
+ tree value = parm;
+ int idx, level;
+ template_parm_level_and_index (parm, &level, &idx);
+
+ if (i < len)
+ {
+ /* Select the Ith argument from the pack. */
+ value = make_node (ARGUMENT_PACK_SELECT);
+ ARGUMENT_PACK_SELECT_FROM_PACK (value) = TREE_VALUE (pack);
+ ARGUMENT_PACK_SELECT_INDEX (value) = i;
+ }
+
+ /* Update the corresponding argument. */
+ TMPL_ARG (args, level, idx) = value;
+ }
+ }
+
+ /* Substitute into the PATTERN with the altered arguments. */
+ if (TREE_CODE (t) == EXPR_PACK_EXPANSION)
+ TREE_VEC_ELT (result, i) =
+ tsubst_expr (pattern, args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+ else
+ TREE_VEC_ELT (result, i) = tsubst (pattern, args, complain, in_decl);
+
+ if (i == len)
+ /* When we have incomplete argument packs, the last "expanded"
+ result is itself a pack expansion, which allows us
+ to deduce more arguments. */
+ TREE_VEC_ELT (result, i) =
+ make_pack_expansion (TREE_VEC_ELT (result, i));
+
+ if (TREE_VEC_ELT (result, i) == error_mark_node)
+ {
+ result = error_mark_node;
+ break;
+ }
+ }
+
+ /* Update ARGS to restore the substitution from parameter packs to
+ their argument packs. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ tree parm = TREE_PURPOSE (pack);
+
+ if (TREE_CODE (parm) == PARM_DECL)
+ register_local_specialization (TREE_TYPE (pack), parm);
+ else
+ {
+ int idx, level;
+ template_parm_level_and_index (parm, &level, &idx);
+
+ /* Update the corresponding argument. */
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
+ TREE_VEC_ELT (TREE_VEC_ELT (args, level -1 ), idx) =
+ TREE_TYPE (pack);
+ else
+ TREE_VEC_ELT (args, idx) = TREE_TYPE (pack);
+ }
+ }
+
+ return result;
}
/* Substitute ARGS into the vector or list of template arguments T. */
static tree
tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{
+ tree orig_t = t;
int len = TREE_VEC_LENGTH (t);
- int need_new = 0, i;
+ int need_new = 0, i, expanded_len_adjust = 0, out;
tree *elts = (tree *) alloca (len * sizeof (tree));
for (i = 0; i < len; i++)
if (TREE_CODE (orig_arg) == TREE_VEC)
new_arg = tsubst_template_args (orig_arg, args, complain, in_decl);
+ else if (PACK_EXPANSION_P (orig_arg))
+ {
+ /* Substitute into an expansion expression. */
+ new_arg = tsubst_pack_expansion (orig_arg, args, complain, in_decl);
+
+ if (TREE_CODE (new_arg) == TREE_VEC)
+ /* Add to the expanded length adjustment the number of
+ expanded arguments. We subtract one from this
+ measurement, because the argument pack expression
+ itself is already counted as 1 in
+ LEN. EXPANDED_LEN_ADJUST can actually be negative, if
+ the argument pack is empty. */
+ expanded_len_adjust += TREE_VEC_LENGTH (new_arg) - 1;
+ }
+ else if (ARGUMENT_PACK_P (orig_arg))
+ {
+ /* Substitute into each of the arguments. */
+ new_arg = make_node (TREE_CODE (orig_arg));
+
+ SET_ARGUMENT_PACK_ARGS (
+ new_arg,
+ tsubst_template_args (ARGUMENT_PACK_ARGS (orig_arg),
+ args, complain, in_decl));
+
+ if (ARGUMENT_PACK_ARGS (new_arg) == error_mark_node)
+ new_arg = error_mark_node;
+
+ if (TREE_CODE (new_arg) == NONTYPE_ARGUMENT_PACK) {
+ TREE_TYPE (new_arg) = tsubst (TREE_TYPE (orig_arg), args,
+ complain, in_decl);
+ TREE_CONSTANT (new_arg) = TREE_CONSTANT (orig_arg);
+
+ if (TREE_TYPE (new_arg) == error_mark_node)
+ new_arg = error_mark_node;
+ }
+ }
else
new_arg = tsubst_template_arg (orig_arg, args, complain, in_decl);
if (!need_new)
return t;
- t = make_tree_vec (len);
- for (i = 0; i < len; i++)
- TREE_VEC_ELT (t, i) = elts[i];
+ /* Make space for the expanded arguments coming from template
+ argument packs. */
+ t = make_tree_vec (len + expanded_len_adjust);
+ for (i = 0, out = 0; i < len; i++)
+ {
+ if ((PACK_EXPANSION_P (TREE_VEC_ELT (orig_t, i))
+ || ARGUMENT_PACK_P (TREE_VEC_ELT (orig_t, i)))
+ && TREE_CODE (elts[i]) == TREE_VEC)
+ {
+ int idx;
+
+ /* Now expand the template argument pack "in place". */
+ for (idx = 0; idx < TREE_VEC_LENGTH (elts[i]); idx++, out++)
+ TREE_VEC_ELT (t, out) = TREE_VEC_ELT (elts[i], idx);
+ }
+ else
+ {
+ TREE_VEC_ELT (t, out) = elts[i];
+ out++;
+ }
+ }
return t;
}
case PARM_DECL:
{
- tree type;
-
- r = copy_node (t);
- if (DECL_TEMPLATE_PARM_P (t))
- SET_DECL_TEMPLATE_PARM_P (r);
-
- type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- type = type_decays_to (type);
- TREE_TYPE (r) = type;
- cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+ tree type = NULL_TREE;
+ int i, len = 1;
+ tree expanded_types = NULL_TREE;
+ tree prev_r = NULL_TREE;
+ tree first_r = NULL_TREE;
- if (DECL_INITIAL (r))
- {
- if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
- DECL_INITIAL (r) = TREE_TYPE (r);
- else
- DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args,
- complain, in_decl);
- }
+ if (FUNCTION_PARAMETER_PACK_P (t))
+ {
+ /* If there is a local specialization that isn't a
+ parameter pack, it means that we're doing a "simple"
+ substitution from inside tsubst_pack_expansion. Just
+ return the local specialiation (which will be a single
+ parm). */
+ tree spec = NULL_TREE;
+ if (local_specializations)
+ spec = retrieve_local_specialization (t);
+ if (spec
+ && TREE_CODE (spec) == PARM_DECL
+ && TREE_CODE (TREE_TYPE (spec)) != TYPE_PACK_EXPANSION)
+ return spec;
+
+ /* Expand the TYPE_PACK_EXPANSION that provides the types for
+ the parameters in this function parameter pack. */
+ expanded_types = tsubst_pack_expansion (TREE_TYPE (t), args,
+ complain, in_decl);
+ if (TREE_CODE (expanded_types) == TREE_VEC)
+ {
+ len = TREE_VEC_LENGTH (expanded_types);
+
+ /* Zero-length parameter packs are boring. Just substitute
+ into the chain. */
+ if (len == 0)
+ return tsubst (TREE_CHAIN (t), args, complain,
+ TREE_CHAIN (t));
+ }
+ else
+ {
+ /* All we did was update the type. Make a note of that. */
+ type = expanded_types;
+ expanded_types = NULL_TREE;
+ }
+ }
- DECL_CONTEXT (r) = NULL_TREE;
+ /* Loop through all of the parameter's we'll build. When T is
+ a function parameter pack, LEN is the number of expanded
+ types in EXPANDED_TYPES; otherwise, LEN is 1. */
+ r = NULL_TREE;
+ for (i = 0; i < len; ++i)
+ {
+ prev_r = r;
+ r = copy_node (t);
+ if (DECL_TEMPLATE_PARM_P (t))
+ SET_DECL_TEMPLATE_PARM_P (r);
+
+ if (expanded_types)
+ /* We're on the Ith parameter of the function parameter
+ pack. */
+ {
+ /* Get the Ith type. */
+ type = TREE_VEC_ELT (expanded_types, i);
+
+ if (DECL_NAME (r))
+ /* Rename the parameter to include the index. */
+ DECL_NAME (r) =
+ make_ith_pack_parameter_name (DECL_NAME (r), i);
+ }
+ else if (!type)
+ /* We're dealing with a normal parameter. */
+ type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+ type = type_decays_to (type);
+ TREE_TYPE (r) = type;
+ cp_apply_type_quals_to_decl (cp_type_quals (type), r);
+
+ if (DECL_INITIAL (r))
+ {
+ if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
+ DECL_INITIAL (r) = TREE_TYPE (r);
+ else
+ DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args,
+ complain, in_decl);
+ }
+
+ DECL_CONTEXT (r) = NULL_TREE;
+
+ if (!DECL_TEMPLATE_PARM_P (r))
+ DECL_ARG_TYPE (r) = type_passed_as (type);
+
+ /* Keep track of the first new parameter we
+ generate. That's what will be returned to the
+ caller. */
+ if (!first_r)
+ first_r = r;
+
+ /* Build a proper chain of parameters when substituting
+ into a function parameter pack. */
+ if (prev_r)
+ TREE_CHAIN (prev_r) = r;
+ }
- if (!DECL_TEMPLATE_PARM_P (r))
- DECL_ARG_TYPE (r) = type_passed_as (type);
if (TREE_CHAIN (t))
TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args,
complain, TREE_CHAIN (t));
+
+ /* FIRST_R contains the start of the chain we've built. */
+ r = first_r;
}
break;
tree in_decl)
{
tree remaining_arg_types;
- tree type;
+ tree type = NULL_TREE;
+ int i = 1;
+ tree expanded_args = NULL_TREE;
tree default_arg;
- tree result = NULL_TREE;
if (!arg_types || arg_types == void_list_node)
return arg_types;
if (remaining_arg_types == error_mark_node)
return error_mark_node;
- type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
- if (type == error_mark_node)
- return error_mark_node;
- if (VOID_TYPE_P (type))
+ if (PACK_EXPANSION_P (TREE_VALUE (arg_types)))
{
- if (complain & tf_error)
- {
- error ("invalid parameter type %qT", type);
- if (in_decl)
- error ("in declaration %q+D", in_decl);
- }
- return error_mark_node;
- }
+ /* For a pack expansion, perform substitution on the
+ entire expression. Later on, we'll handle the arguments
+ one-by-one. */
+ expanded_args = tsubst_pack_expansion (TREE_VALUE (arg_types),
+ args, complain, in_decl);
- /* Do array-to-pointer, function-to-pointer conversion, and ignore
- top-level qualifiers as required. */
- type = TYPE_MAIN_VARIANT (type_decays_to (type));
+ if (TREE_CODE (expanded_args) == TREE_VEC)
+ /* So that we'll spin through the parameters, one by one. */
+ i = TREE_VEC_LENGTH (expanded_args);
+ else
+ {
+ /* We only partially substituted into the parameter
+ pack. Our type is TYPE_PACK_EXPANSION. */
+ type = expanded_args;
+ expanded_args = NULL_TREE;
+ }
+ }
- /* We do not substitute into default arguments here. The standard
- mandates that they be instantiated only when needed, which is
- done in build_over_call. */
- default_arg = TREE_PURPOSE (arg_types);
+ while (i > 0) {
+ --i;
+
+ if (expanded_args)
+ type = TREE_VEC_ELT (expanded_args, i);
+ else if (!type)
+ type = tsubst (TREE_VALUE (arg_types), args, complain, in_decl);
- if (default_arg && TREE_CODE (default_arg) == DEFAULT_ARG)
- {
- /* We've instantiated a template before its default arguments
- have been parsed. This can happen for a nested template
- class, and is not an error unless we require the default
- argument in a call of this function. */
- result = tree_cons (default_arg, type, remaining_arg_types);
- VEC_safe_push (tree, gc, DEFARG_INSTANTIATIONS (default_arg), result);
+ if (type == error_mark_node)
+ return error_mark_node;
+ if (VOID_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ {
+ error ("invalid parameter type %qT", type);
+ if (in_decl)
+ error ("in declaration %q+D", in_decl);
+ }
+ return error_mark_node;
}
- else
- result = hash_tree_cons (default_arg, type, remaining_arg_types);
+
+ /* Do array-to-pointer, function-to-pointer conversion, and ignore
+ top-level qualifiers as required. */
+ type = TYPE_MAIN_VARIANT (type_decays_to (type));
- return result;
+ /* We do not substitute into default arguments here. The standard
+ mandates that they be instantiated only when needed, which is
+ done in build_over_call. */
+ default_arg = TREE_PURPOSE (arg_types);
+
+ if (default_arg && TREE_CODE (default_arg) == DEFAULT_ARG)
+ {
+ /* We've instantiated a template before its default arguments
+ have been parsed. This can happen for a nested template
+ class, and is not an error unless we require the default
+ argument in a call of this function. */
+ remaining_arg_types =
+ tree_cons (default_arg, type, remaining_arg_types);
+ VEC_safe_push (tree, gc, DEFARG_INSTANTIATIONS (default_arg),
+ remaining_arg_types);
+ }
+ else
+ remaining_arg_types =
+ hash_tree_cons (default_arg, type, remaining_arg_types);
+ }
+
+ return remaining_arg_types;
}
/* Substitute into a FUNCTION_TYPE or METHOD_TYPE. This routine does
while (specs)
{
tree spec;
- spec = tsubst (TREE_VALUE (specs), args, complain, in_decl);
- if (spec == error_mark_node)
- return spec;
- new_specs = add_exception_specifier (new_specs, spec, complain);
- specs = TREE_CHAIN (specs);
+ int i, len = 1;
+ tree expanded_specs = NULL_TREE;
+
+ if (PACK_EXPANSION_P (TREE_VALUE (specs)))
+ {
+ /* Expand the pack expansion type. */
+ expanded_specs = tsubst_pack_expansion (TREE_VALUE (specs),
+ args, complain,
+ in_decl);
+ len = TREE_VEC_LENGTH (expanded_specs);
+ }
+
+ for (i = 0; i < len; ++i)
+ {
+ if (expanded_specs)
+ spec = TREE_VEC_ELT (expanded_specs, i);
+ else
+ spec = tsubst (TREE_VALUE (specs), args, complain, in_decl);
+ if (spec == error_mark_node)
+ return spec;
+ new_specs = add_exception_specifier (new_specs, spec,
+ complain);
+ }
+
+ specs = TREE_CHAIN (specs);
}
}
return new_specs;
levels = TMPL_ARGS_DEPTH (args);
if (level <= levels)
- arg = TMPL_ARG (args, level, idx);
+ {
+ arg = TMPL_ARG (args, level, idx);
+
+ if (arg && TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
+ /* See through ARGUMENT_PACK_SELECT arguments. */
+ arg = ARGUMENT_PACK_SELECT_ARG (arg);
+ }
if (arg == error_mark_node)
return error_mark_node;
else if (arg != NULL_TREE)
{
+ if (ARGUMENT_PACK_P (arg))
+ /* If ARG is an argument pack, we don't actually want to
+ perform a substitution here, because substitutions
+ for argument packs are only done
+ element-by-element. We can get to this point when
+ substituting the type of a non-type template
+ parameter pack, when that type actually contains
+ template parameter packs from an outer template, e.g.,
+
+ template<typename... Types> struct A {
+ template<Types... Values> struct B { };
+ }; */
+ return t;
+
if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
{
int quals;
complain);
}
+ case TYPE_ARGUMENT_PACK:
+ case NONTYPE_ARGUMENT_PACK:
+ {
+ tree r = make_node (TREE_CODE (t));
+ tree packed_out =
+ tsubst_template_args (ARGUMENT_PACK_ARGS (t),
+ args,
+ complain,
+ in_decl);
+ SET_ARGUMENT_PACK_ARGS (r, packed_out);
+
+ /* For template nontype argument packs, also substitute into
+ the type. */
+ if (TREE_CODE (t) == NONTYPE_ARGUMENT_PACK)
+ TREE_TYPE (r) = tsubst (TREE_TYPE (t), args, complain, in_decl);
+
+ return r;
+ }
+ break;
+
default:
sorry ("use of %qs in template",
tree_code_name [(int) TREE_CODE (t)]);
case PARM_DECL:
r = retrieve_local_specialization (t);
gcc_assert (r != NULL);
+ if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
+ r = ARGUMENT_PACK_SELECT_ARG (r);
mark_used (r);
return r;
(code, tsubst (TREE_TYPE (t), args, complain, in_decl),
tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl));
+ case SIZEOF_EXPR:
+ if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+ {
+ /* We only want to compute the number of arguments. */
+ tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
+ complain, in_decl);
+ return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
+ }
+ /* Fall through */
+
case INDIRECT_REF:
case NEGATE_EXPR:
case TRUTH_NOT_EXPR:
case BIT_NOT_EXPR:
case ADDR_EXPR:
case UNARY_PLUS_EXPR: /* Unary + */
- case SIZEOF_EXPR:
case ALIGNOF_EXPR:
case ARROW_EXPR:
case THROW_EXPR:
mark_used (TREE_OPERAND (t, 1));
return t;
+ case EXPR_PACK_EXPANSION:
+ error ("invalid use of pack expansion expression");
+ return error_mark_node;
+
+ case NONTYPE_ARGUMENT_PACK:
+ error ("use %<...%> to expand argument pack");
+ return error_mark_node;
+
default:
return t;
}
}
break;
+ case EXPR_PACK_EXPANSION:
+ error ("invalid use of pack expansion expression");
+ return error_mark_node;
+
+ case NONTYPE_ARGUMENT_PACK:
+ error ("use %<...%> to expand argument pack");
+ return error_mark_node;
+
default:
gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
/*overloaded_p=*/NULL);
case SIZEOF_EXPR:
+ if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
+ {
+ /* We only want to compute the number of arguments. */
+ tree expanded = tsubst_pack_expansion (TREE_OPERAND (t, 0), args,
+ complain, in_decl);
+ return build_int_cst (size_type_node, TREE_VEC_LENGTH (expanded));
+ }
+ /* Fall through */
+
case ALIGNOF_EXPR:
op1 = TREE_OPERAND (t, 0);
if (!args)
if (t == void_list_node)
return t;
+ if ((TREE_PURPOSE (t) && PACK_EXPANSION_P (TREE_PURPOSE (t)))
+ || (TREE_VALUE (t) && PACK_EXPANSION_P (TREE_VALUE (t))))
+ {
+ /* We have pack expansions, so expand those and
+ create a new list out of it. */
+ tree purposevec = NULL_TREE;
+ tree valuevec = NULL_TREE;
+ tree chain;
+ int i, len = -1;
+
+ /* Expand the argument expressions. */
+ if (TREE_PURPOSE (t))
+ purposevec = tsubst_pack_expansion (TREE_PURPOSE (t), args,
+ complain, in_decl);
+ if (TREE_VALUE (t))
+ valuevec = tsubst_pack_expansion (TREE_VALUE (t), args,
+ complain, in_decl);
+
+ /* Build the rest of the list. */
+ chain = TREE_CHAIN (t);
+ if (chain && chain != void_type_node)
+ chain = RECUR (chain);
+
+ /* Determine the number of arguments. */
+ if (purposevec && TREE_CODE (purposevec) == TREE_VEC)
+ {
+ len = TREE_VEC_LENGTH (purposevec);
+ gcc_assert (!valuevec || len == TREE_VEC_LENGTH (valuevec));
+ }
+ else if (TREE_CODE (valuevec) == TREE_VEC)
+ len = TREE_VEC_LENGTH (valuevec);
+ else
+ {
+ /* Since we only performed a partial substitution into
+ the argument pack, we only return a single list
+ node. */
+ if (purposevec == TREE_PURPOSE (t)
+ && valuevec == TREE_VALUE (t)
+ && chain == TREE_CHAIN (t))
+ return t;
+
+ return tree_cons (purposevec, valuevec, chain);
+ }
+
+ /* Convert the argument vectors into a TREE_LIST */
+ i = len;
+ while (i > 0)
+ {
+ /* Grab the Ith values. */
+ i--;
+ purpose = purposevec ? TREE_VEC_ELT (purposevec, i)
+ : NULL_TREE;
+ value
+ = valuevec ? convert_from_reference (TREE_VEC_ELT (valuevec, i))
+ : NULL_TREE;
+
+ /* Build the list (backwards). */
+ chain = tree_cons (purpose, value, chain);
+ }
+
+ return chain;
+ }
+
purpose = TREE_PURPOSE (t);
if (purpose)
purpose = RECUR (purpose);
unsigned HOST_WIDE_INT idx;
tree type = tsubst (TREE_TYPE (t), args, complain, in_decl);
bool process_index_p;
+ int newlen;
+ bool need_copy_p = false;
if (type == error_mark_node)
return error_mark_node;
process_index_p = !(type && IS_AGGR_TYPE (type));
n = VEC_copy (constructor_elt, gc, CONSTRUCTOR_ELTS (t));
+ newlen = VEC_length (constructor_elt, n);
for (idx = 0; VEC_iterate (constructor_elt, n, idx, ce); idx++)
{
if (ce->index && process_index_p)
ce->index = RECUR (ce->index);
- ce->value = RECUR (ce->value);
+
+ if (PACK_EXPANSION_P (ce->value))
+ {
+ /* Substitute into the pack expansion. */
+ ce->value = tsubst_pack_expansion (ce->value, args, complain,
+ in_decl);
+
+ if (TREE_VEC_LENGTH (ce->value) == 1)
+ /* Just move the argument into place. */
+ ce->value = TREE_VEC_ELT (ce->value, 0);
+ else
+ {
+ /* Update the length of the final CONSTRUCTOR
+ arguments vector, and note that we will need to
+ copy.*/
+ newlen = newlen + TREE_VEC_LENGTH (ce->value) - 1;
+ need_copy_p = true;
+ }
+ }
+ else
+ ce->value = RECUR (ce->value);
}
+ if (need_copy_p)
+ {
+ VEC(constructor_elt,gc) *old_n = n;
+
+ n = VEC_alloc (constructor_elt, gc, newlen);
+ for (idx = 0; VEC_iterate (constructor_elt, old_n, idx, ce);
+ idx++)
+ {
+ if (TREE_CODE (ce->value) == TREE_VEC)
+ {
+ int i, len = TREE_VEC_LENGTH (ce->value);
+ for (i = 0; i < len; ++i)
+ CONSTRUCTOR_APPEND_ELT (n, 0,
+ TREE_VEC_ELT (ce->value, i));
+ }
+ else
+ CONSTRUCTOR_APPEND_ELT (n, 0, ce->value);
+ }
+ }
+
if (TREE_HAS_CONSTRUCTOR (t))
return finish_compound_literal (type, n);
tree parms;
tree fntype;
int result;
+ bool incomplete_argument_packs_p = false;
gcc_assert (TREE_CODE (fn) == TEMPLATE_DECL);
specified template argument values. If a substitution in a
template parameter or in the function type of the function
template results in an invalid type, type deduction fails. */
- int i;
+ tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
+ int i, len = TREE_VEC_LENGTH (tparms);
tree converted_args;
- bool incomplete;
+ bool incomplete = false;
if (explicit_targs == error_mark_node)
return 1;
converted_args
- = (coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (fn),
- explicit_targs, NULL_TREE, tf_none,
+ = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
/*require_all_args=*/false,
/*use_default_args=*/false));
if (converted_args == error_mark_node)
an incomplete set of explicit args, we must not do semantic
processing during substitution as we could create partial
instantiations. */
- incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
+ for (i = 0; i < len; i++)
+ {
+ tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
+ bool parameter_pack = false;
+
+ /* Dig out the actual parm. */
+ if (TREE_CODE (parm) == TYPE_DECL
+ || TREE_CODE (parm) == TEMPLATE_DECL)
+ {
+ parm = TREE_TYPE (parm);
+ parameter_pack = TEMPLATE_TYPE_PARAMETER_PACK (parm);
+ }
+ else if (TREE_CODE (parm) == PARM_DECL)
+ {
+ parm = DECL_INITIAL (parm);
+ parameter_pack = TEMPLATE_PARM_PARAMETER_PACK (parm);
+ }
+
+ if (parameter_pack)
+ {
+ int level, idx;
+ tree targ;
+ template_parm_level_and_index (parm, &level, &idx);
+
+ /* Mark the argument pack as "incomplete". We could
+ still deduce more arguments during unification. */
+ targ = TMPL_ARG (converted_args, level, idx);
+ ARGUMENT_PACK_INCOMPLETE_P(targ) = 1;
+ ARGUMENT_PACK_EXPLICIT_ARGS (targ) = ARGUMENT_PACK_ARGS (targ);
+
+ /* We have some incomplete argument packs. */
+ incomplete_argument_packs_p = true;
+ }
+ }
+
+ if (incomplete_argument_packs_p)
+ /* Any substitution is guaranteed to be incomplete if there
+ are incomplete argument packs, because we can still deduce
+ more arguments. */
+ incomplete = 1;
+ else
+ incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
+
processing_template_decl += incomplete;
fntype = tsubst (fntype, converted_args, tf_none, NULL_TREE);
processing_template_decl -= incomplete;
targs, parms, args, /*subr=*/0,
strict, flags);
+ if (result == 0 && incomplete_argument_packs_p)
+ {
+ int i, len = NUM_TMPL_ARGS (targs);
+
+ /* Clear the "incomplete" flags on all argument packs. */
+ for (i = 0; i < len; i++)
+ {
+ tree arg = TREE_VEC_ELT (targs, i);
+ if (ARGUMENT_PACK_P (arg))
+ {
+ ARGUMENT_PACK_INCOMPLETE_P (arg) = 0;
+ ARGUMENT_PACK_EXPLICIT_ARGS (arg) = NULL_TREE;
+ }
+ }
+ }
+
if (result == 0)
/* All is well so far. Now, check:
while (parms && parms != void_list_node
&& args && args != void_list_node)
{
+ if (TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
+ break;
+
parm = TREE_VALUE (parms);
parms = TREE_CHAIN (parms);
arg = TREE_VALUE (args);
}
}
+
+ if (parms
+ && parms != void_list_node
+ && TREE_CODE (TREE_VALUE (parms)) == TYPE_PACK_EXPANSION)
+ {
+ /* Unify the remaining arguments with the pack expansion type. */
+ tree argvec;
+ tree parmvec = make_tree_vec (1);
+ int len = 0;
+ tree t;
+
+ /* Count the number of arguments that remain. */
+ for (t = args; t && t != void_list_node; t = TREE_CHAIN (t))
+ len++;
+
+ /* Allocate a TREE_VEC and copy in all of the arguments */
+ argvec = make_tree_vec (len);
+ for (i = 0; args && args != void_list_node; args = TREE_CHAIN (args))
+ {
+ TREE_VEC_ELT (argvec, i) = TREE_VALUE (args);
+ ++i;
+ }
+
+ /* Copy the parameter into parmvec. */
+ TREE_VEC_ELT (parmvec, 0) = TREE_VALUE (parms);
+ if (unify_pack_expansion (tparms, targs, parmvec, argvec, strict,
+ /*call_args_p=*/true, /*subr=*/subr))
+ return 1;
+
+ /* Advance to the end of the list of parameters. */
+ parms = TREE_CHAIN (parms);
+ }
+
/* Fail if we've reached the end of the parm list, and more args
are present, and the parm list isn't variadic. */
if (args && args != void_list_node && parms == void_list_node)
return 1;
}
+/* Determines the LEVEL and INDEX for the template parameter PARM. */
+void
+template_parm_level_and_index (tree parm, int* level, int* index)
+{
+ if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ {
+ *index = TEMPLATE_TYPE_IDX (parm);
+ *level = TEMPLATE_TYPE_LEVEL (parm);
+ }
+ else
+ {
+ *index = TEMPLATE_PARM_IDX (parm);
+ *level = TEMPLATE_PARM_LEVEL (parm);
+ }
+}
+
+/* Unifies the remaining arguments in PACKED_ARGS with the pack
+ expansion at the end of PACKED_PARMS. Returns 0 if the type
+ deduction succeeds, 1 otherwise. STRICT is the same as in
+ unify. CALL_ARGS_P is true iff PACKED_ARGS is actually a function
+ call argument list. We'll need to adjust the arguments to make them
+ types. SUBR tells us if this is from a recursive call to
+ type_unification_real. */
+int
+unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
+ tree packed_args, int strict, bool call_args_p,
+ bool subr)
+{
+ tree parm
+ = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1);
+ tree pattern = PACK_EXPANSION_PATTERN (parm);
+ tree pack, packs = NULL_TREE;
+ int i, start = TREE_VEC_LENGTH (packed_parms) - 1;
+ int len = TREE_VEC_LENGTH (packed_args);
+
+ /* Determine the parameter packs we will be deducing from the
+ pattern, and record their current deductions. */
+ for (pack = PACK_EXPANSION_PARAMETER_PACKS (parm);
+ pack; pack = TREE_CHAIN (pack))
+ {
+ tree parm_pack = TREE_VALUE (pack);
+ int idx, level;
+
+ /* Determine the index and level of this parameter pack. */
+ template_parm_level_and_index (parm_pack, &level, &idx);
+
+ /* Keep track of the parameter packs and their corresponding
+ argument packs. */
+ packs = tree_cons (parm_pack, TMPL_ARG (targs, level, idx), packs);
+ TREE_TYPE (packs) = make_tree_vec (len - start);
+ }
+
+ /* Loop through all of the arguments that have not yet been
+ unified and unify each with the pattern. */
+ for (i = start; i < len; i++)
+ {
+ tree parm = pattern;
+
+ /* For each parameter pack, clear out the deduced value so that
+ we can deduce it again. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ int idx, level;
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ TMPL_ARG (targs, level, idx) = NULL_TREE;
+ }
+
+ /* Unify the pattern with the current argument. */
+ {
+ tree arg = TREE_VEC_ELT (packed_args, i);
+ int arg_strict = strict;
+ bool skip_arg_p = false;
+
+ if (call_args_p)
+ {
+ int sub_strict;
+
+ /* This mirrors what we do in type_unification_real. */
+ switch (strict)
+ {
+ case DEDUCE_CALL:
+ sub_strict = (UNIFY_ALLOW_OUTER_LEVEL
+ | UNIFY_ALLOW_MORE_CV_QUAL
+ | UNIFY_ALLOW_DERIVED);
+ break;
+
+ case DEDUCE_CONV:
+ sub_strict = UNIFY_ALLOW_LESS_CV_QUAL;
+ break;
+
+ case DEDUCE_EXACT:
+ sub_strict = UNIFY_ALLOW_NONE;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (!TYPE_P (arg))
+ {
+ gcc_assert (TREE_TYPE (arg) != NULL_TREE);
+ if (type_unknown_p (arg))
+ {
+ /* [temp.deduct.type] A template-argument can be
+ deduced from a pointer to function or pointer
+ to member function argument if the set of
+ overloaded functions does not contain function
+ templates and at most one of a set of
+ overloaded functions provides a unique
+ match. */
+
+ if (resolve_overloaded_unification
+ (tparms, targs, parm, arg, strict, sub_strict)
+ != 0)
+ return 1;
+ skip_arg_p = true;
+ }
+
+ if (!skip_arg_p)
+ {
+ arg = TREE_TYPE (arg);
+ if (arg == error_mark_node)
+ return 1;
+ }
+ }
+
+ arg_strict = sub_strict;
+
+ if (!subr)
+ arg_strict |=
+ maybe_adjust_types_for_deduction (strict, &parm, &arg);
+ }
+
+ if (!skip_arg_p)
+ {
+ if (unify (tparms, targs, parm, arg, arg_strict))
+ return 1;
+ }
+ }
+
+ /* For each parameter pack, collect the deduced value. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ int idx, level;
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ TREE_VEC_ELT (TREE_TYPE (pack), i - start) =
+ TMPL_ARG (targs, level, idx);
+ }
+ }
+
+ /* Verify that the results of unification with the parameter packs
+ produce results consistent with what we've seen before, and make
+ the deduced argument packs available. */
+ for (pack = packs; pack; pack = TREE_CHAIN (pack))
+ {
+ tree old_pack = TREE_VALUE (pack);
+ tree new_args = TREE_TYPE (pack);
+
+ if (old_pack && ARGUMENT_PACK_INCOMPLETE_P (old_pack))
+ {
+ /* Prepend the explicit arguments onto NEW_ARGS. */
+ tree explicit_args = ARGUMENT_PACK_EXPLICIT_ARGS (old_pack);
+ tree old_args = new_args;
+ int i, explicit_len = TREE_VEC_LENGTH (explicit_args);
+ int len = explicit_len + TREE_VEC_LENGTH (old_args);
+
+ /* Copy the explicit arguments. */
+ new_args = make_tree_vec (len);
+ for (i = 0; i < explicit_len; i++)
+ TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (explicit_args, i);
+
+ /* Copy the deduced arguments. */
+ for (; i < len; i++)
+ TREE_VEC_ELT (new_args, i) =
+ TREE_VEC_ELT (old_args, i - explicit_len);
+ }
+
+ if (!old_pack)
+ {
+ tree result;
+ int idx, level;
+
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ /* Build the deduced *_ARGUMENT_PACK. */
+ if (TREE_CODE (TREE_PURPOSE (pack)) == TEMPLATE_PARM_INDEX)
+ {
+ result = make_node (NONTYPE_ARGUMENT_PACK);
+ TREE_TYPE (result) =
+ TREE_TYPE (TEMPLATE_PARM_DECL (TREE_PURPOSE (pack)));
+ TREE_CONSTANT (result) = 1;
+ }
+ else
+ result = make_node (TYPE_ARGUMENT_PACK);
+
+ SET_ARGUMENT_PACK_ARGS (result, new_args);
+
+ /* Note the deduced argument packs for this parameter
+ pack. */
+ TMPL_ARG (targs, level, idx) = result;
+ }
+ else if (ARGUMENT_PACK_INCOMPLETE_P (old_pack)
+ && (ARGUMENT_PACK_ARGS (old_pack)
+ == ARGUMENT_PACK_EXPLICIT_ARGS (old_pack)))
+ {
+ /* We only had the explicitly-provided arguments before, but
+ now we have a complete set of arguments. */
+ int idx, level;
+ tree explicit_args = ARGUMENT_PACK_EXPLICIT_ARGS (old_pack);
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ /* Keep the original deduced argument pack. */
+ TMPL_ARG (targs, level, idx) = old_pack;
+
+ SET_ARGUMENT_PACK_ARGS (old_pack, new_args);
+ ARGUMENT_PACK_INCOMPLETE_P (old_pack) = 1;
+ ARGUMENT_PACK_EXPLICIT_ARGS (old_pack) = explicit_args;
+ }
+ else if (!comp_template_args (ARGUMENT_PACK_ARGS (old_pack),
+ new_args))
+ /* Inconsistent unification of this parameter pack. */
+ return 1;
+ else
+ {
+ int idx, level;
+
+ template_parm_level_and_index (TREE_PURPOSE (pack), &level, &idx);
+
+ /* Keep the original deduced argument pack. */
+ TMPL_ARG (targs, level, idx) = old_pack;
+ }
+ }
+
+ return 0;
+}
+
/* Deduce the value of template parameters. TPARMS is the (innermost)
set of template parameters to a template. TARGS is the bindings
for those template parameters, as determined thus far; TARGS may
return 1;
}
+ /* If ARG is a parameter pack or an expansion, we cannot unify
+ against it unless PARM is also a parameter pack. */
+ if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
+ && !template_parameter_pack_p (parm))
+ return 1;
+
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0;
else
return 1;
+ /* If ARG is a parameter pack or an expansion, we cannot unify
+ against it unless PARM is also a parameter pack. */
+ if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
+ && !TEMPLATE_PARM_PARAMETER_PACK (parm))
+ return 1;
+
TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
return 0;
/* Matched cases are handled by the ARG == PARM test above. */
return 1;
+ case TYPE_ARGUMENT_PACK:
+ case NONTYPE_ARGUMENT_PACK:
+ {
+ tree packed_parms = ARGUMENT_PACK_ARGS (parm);
+ tree packed_args = ARGUMENT_PACK_ARGS (arg);
+ int i, len = TREE_VEC_LENGTH (packed_parms);
+ int argslen = TREE_VEC_LENGTH (packed_args);
+ int parm_variadic_p = 0;
+
+ /* Check if the parameters end in a pack, making them variadic. */
+ if (len > 0
+ && PACK_EXPANSION_P (TREE_VEC_ELT (packed_parms, len - 1)))
+ parm_variadic_p = 1;
+
+ /* If we don't have enough arguments to satisfy the parameters
+ (not counting the pack expression at the end), or we have
+ too many arguments for a parameter list that doesn't end in
+ a pack expression, we can't unify. */
+ if (argslen < (len - parm_variadic_p)
+ || (argslen > len && !parm_variadic_p))
+ return 1;
+
+ /* Unify all of the parameters that precede the (optional)
+ pack expression. */
+ for (i = 0; i < len - parm_variadic_p; ++i)
+ {
+ if (unify (tparms, targs, TREE_VEC_ELT (packed_parms, i),
+ TREE_VEC_ELT (packed_args, i), strict))
+ return 1;
+ }
+
+ if (parm_variadic_p)
+ return unify_pack_expansion (tparms, targs,
+ packed_parms, packed_args,
+ strict, /*call_args_p=*/false,
+ /*subr=*/false);
+ return 0;
+ }
+
+ break;
+
default:
gcc_assert (EXPR_P (parm));
int quals1 = -1;
int quals2 = -1;
+ if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION
+ && TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+ {
+ /* When both arguments are pack expansions, we need only
+ unify the patterns themselves. */
+ arg1 = PACK_EXPANSION_PATTERN (arg1);
+ arg2 = PACK_EXPANSION_PATTERN (arg2);
+
+ /* This is the last comparison we need to do. */
+ len = 0;
+ }
+
if (TREE_CODE (arg1) == REFERENCE_TYPE)
{
arg1 = TREE_TYPE (arg1);
arg1 = TYPE_MAIN_VARIANT (arg1);
arg2 = TYPE_MAIN_VARIANT (arg2);
- deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
- deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+ if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION)
+ {
+ int i, len2 = len + 1;
+ tree parmvec = make_tree_vec (1);
+ tree argvec = make_tree_vec (len2);
+ tree ta = args2;
+
+ /* Setup the parameter vector, which contains only ARG1. */
+ TREE_VEC_ELT (parmvec, 0) = arg1;
+
+ /* Setup the argument vector, which contains the remaining
+ arguments. */
+ for (i = 0; i < len2; i++, ta = TREE_CHAIN (ta))
+ TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
+
+ deduce1 = !unify_pack_expansion (tparms1, targs1, parmvec,
+ argvec, UNIFY_ALLOW_NONE,
+ /*call_args_p=*/false,
+ /*subr=*/0);
+
+ /* We cannot deduce in the other direction, because ARG1 is
+ a pack expansion but ARG2 is not. */
+ deduce2 = 0;
+ }
+ else if (TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+ {
+ int i, len1 = len + 1;
+ tree parmvec = make_tree_vec (1);
+ tree argvec = make_tree_vec (len1);
+ tree ta = args1;
+
+ /* Setup the parameter vector, which contains only ARG1. */
+ TREE_VEC_ELT (parmvec, 0) = arg2;
+
+ /* Setup the argument vector, which contains the remaining
+ arguments. */
+ for (i = 0; i < len1; i++, ta = TREE_CHAIN (ta))
+ TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
+
+ deduce2 = !unify_pack_expansion (tparms2, targs2, parmvec,
+ argvec, UNIFY_ALLOW_NONE,
+ /*call_args_p=*/false,
+ /*subr=*/0);
+
+ /* We cannot deduce in the other direction, because ARG2 is
+ a pack expansion but ARG1 is not.*/
+ deduce1 = 0;
+ }
+
+ else
+ {
+ /* The normal case, where neither argument is a pack
+ expansion. */
+ deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
+ deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+ }
if (!deduce1)
better2 = -1;
if (deduce2 && !deduce1 && !better1)
better1 = 1;
+ if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION
+ || TREE_CODE (arg2) == TYPE_PACK_EXPANSION)
+ /* We have already processed all of the arguments in our
+ handing of the pack expansion type. */
+ len = 0;
+
args1 = TREE_CHAIN (args1);
args2 = TREE_CHAIN (args2);
}
processing_template_decl--;
+ /* All things being equal, if the next argument is a pack expansion
+ for one function but not for the other, prefer the
+ non-variadic function. */
+ if ((better1 > 0) - (better2 > 0) == 0
+ && args1 && TREE_VALUE (args1)
+ && args2 && TREE_VALUE (args2))
+ {
+ if (TREE_CODE (TREE_VALUE (args1)) == TYPE_PACK_EXPANSION)
+ return TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION ? 0 : -1;
+ else if (TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION)
+ return 1;
+ }
+
return (better1 > 0) - (better2 > 0);
}
tree targs;
tree tmpl1, tmpl2;
int winner = 0;
+ bool any_deductions = false;
tmpl1 = TREE_TYPE (pat1);
tmpl2 = TREE_TYPE (pat2);
CLASSTYPE_TI_ARGS (tmpl1),
CLASSTYPE_TI_ARGS (tmpl2));
if (targs)
- --winner;
+ {
+ --winner;
+ any_deductions = true;
+ }
targs = get_class_bindings (TREE_VALUE (pat2),
CLASSTYPE_TI_ARGS (tmpl2),
CLASSTYPE_TI_ARGS (tmpl1));
if (targs)
- ++winner;
+ {
+ ++winner;
+ any_deductions = true;
+ }
--processing_template_decl;
+ /* In the case of a tie where at least one of the class templates
+ has a parameter pack at the end, the template with the most
+ non-packed parameters wins. */
+ if (winner == 0
+ && any_deductions
+ && (template_args_variadic_p (TREE_PURPOSE (pat1))
+ || template_args_variadic_p (TREE_PURPOSE (pat2))))
+ {
+ tree args1 = INNERMOST_TEMPLATE_ARGS (TREE_PURPOSE (pat1));
+ tree args2 = INNERMOST_TEMPLATE_ARGS (TREE_PURPOSE (pat2));
+ int len1 = TREE_VEC_LENGTH (args1);
+ int len2 = TREE_VEC_LENGTH (args2);
+
+ /* We don't count the pack expansion at the end. */
+ if (template_args_variadic_p (TREE_PURPOSE (pat1)))
+ --len1;
+ if (template_args_variadic_p (TREE_PURPOSE (pat2)))
+ --len2;
+
+ if (len1 > len2)
+ return 1;
+ else if (len1 < len2)
+ return -1;
+ }
+
return winner;
}
pattern_parm
= skip_artificial_parms_for (code_pattern,
DECL_ARGUMENTS (code_pattern));
- while (decl_parm)
+ while (decl_parm && !FUNCTION_PARAMETER_PACK_P (pattern_parm))
{
tree parm_type;
tree attributes;
-
+
if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm))
DECL_NAME (decl_parm) = DECL_NAME (pattern_parm);
parm_type = tsubst (TREE_TYPE (pattern_parm), args, tf_error,
decl_parm = TREE_CHAIN (decl_parm);
pattern_parm = TREE_CHAIN (pattern_parm);
}
-
+ /* Merge any parameters that match with the function parameter
+ pack. */
+ if (pattern_parm && FUNCTION_PARAMETER_PACK_P (pattern_parm))
+ {
+ int i, len;
+ tree expanded_types;
+ /* Expand the TYPE_PACK_EXPANSION that provides the types for
+ the parameters in this function parameter pack. */
+ expanded_types = tsubst_pack_expansion (TREE_TYPE (pattern_parm),
+ args, tf_error, NULL_TREE);
+ len = TREE_VEC_LENGTH (expanded_types);
+ for (i = 0; i < len; i++)
+ {
+ tree parm_type;
+ tree attributes;
+
+ if (DECL_NAME (decl_parm) != DECL_NAME (pattern_parm))
+ /* Rename the parameter to include the index. */
+ DECL_NAME (decl_parm) =
+ make_ith_pack_parameter_name (DECL_NAME (pattern_parm), i);
+ parm_type = TREE_VEC_ELT (expanded_types, i);
+ parm_type = type_decays_to (parm_type);
+ if (!same_type_p (TREE_TYPE (decl_parm), parm_type))
+ TREE_TYPE (decl_parm) = parm_type;
+ attributes = DECL_ATTRIBUTES (pattern_parm);
+ if (DECL_ATTRIBUTES (decl_parm) != attributes)
+ {
+ DECL_ATTRIBUTES (decl_parm) = attributes;
+ cplus_decl_attributes (&decl_parm, attributes, /*flags=*/0);
+ }
+ decl_parm = TREE_CHAIN (decl_parm);
+ }
+ }
/* Merge additional specifiers from the CODE_PATTERN. */
if (DECL_DECLARED_INLINE_P (code_pattern)
&& !DECL_DECLARED_INLINE_P (decl))
if (TREE_CODE (gen) == FUNCTION_DECL)
{
tsubst (DECL_ARGUMENTS (gen), gen_args, tf_warning_or_error, d);
- tsubst (TYPE_RAISES_EXCEPTIONS (type), gen_args,
- tf_warning_or_error, d);
+ tsubst_exception_specification (type, gen_args, tf_warning_or_error,
+ d);
/* Don't simply tsubst the function type, as that will give
duplicate warnings about poor parameter qualifications.
The function arguments are the same as the decl_arguments
spec_parm = skip_artificial_parms_for (d, spec_parm);
tmpl_parm = skip_artificial_parms_for (subst_decl, tmpl_parm);
}
- while (tmpl_parm)
+ while (tmpl_parm && !FUNCTION_PARAMETER_PACK_P (tmpl_parm))
{
register_local_specialization (spec_parm, tmpl_parm);
tmpl_parm = TREE_CHAIN (tmpl_parm);
spec_parm = TREE_CHAIN (spec_parm);
}
+ if (tmpl_parm && FUNCTION_PARAMETER_PACK_P (tmpl_parm))
+ {
+ /* Collect all of the extra "packed" parameters into an
+ argument pack. */
+ tree parmvec;
+ tree parmtypevec;
+ tree argpack = make_node (NONTYPE_ARGUMENT_PACK);
+ tree argtypepack = make_node (TYPE_ARGUMENT_PACK);
+ int i, len = 0;
+ tree t;
+
+ /* Count how many parameters remain. */
+ for (t = spec_parm; t; t = TREE_CHAIN (t))
+ len++;
+
+ /* Fill in PARMVEC and PARMTYPEVEC with all of the parameters. */
+ parmvec = make_tree_vec (len);
+ parmtypevec = make_tree_vec (len);
+ for(i = 0; i < len; i++, spec_parm = TREE_CHAIN (spec_parm))
+ {
+ TREE_VEC_ELT (parmvec, i) = spec_parm;
+ TREE_VEC_ELT (parmtypevec, i) = TREE_TYPE (spec_parm);
+ }
+
+ /* Build the argument packs. */
+ SET_ARGUMENT_PACK_ARGS (argpack, parmvec);
+ SET_ARGUMENT_PACK_ARGS (argtypepack, parmtypevec);
+ TREE_TYPE (argpack) = argtypepack;
+
+ /* Register the (value) argument pack as a specialization of
+ TMPL_PARM, then move on. */
+ register_local_specialization (argpack, tmpl_parm);
+ tmpl_parm = TREE_CHAIN (tmpl_parm);
+ }
gcc_assert (!spec_parm);
/* Substitute into the body of the function. */
{
tree decl;
tree init;
+ tree expanded_bases = NULL_TREE;
+ tree expanded_arguments = NULL_TREE;
+ int i, len = 1;
- decl = tsubst_copy (TREE_PURPOSE (t), argvec, tf_warning_or_error,
- NULL_TREE);
- decl = expand_member_init (decl);
- if (decl && !DECL_P (decl))
- in_base_initializer = 1;
-
- init = tsubst_expr (TREE_VALUE (t), argvec, tf_warning_or_error,
- NULL_TREE,
- /*integral_constant_expression_p=*/false);
- in_base_initializer = 0;
+ if (TREE_CODE (TREE_PURPOSE (t)) == TYPE_PACK_EXPANSION)
+ {
+ tree expr;
+ tree arg;
+
+ /* Expand the base class expansion type into separate base
+ classes. */
+ expanded_bases = tsubst_pack_expansion (TREE_PURPOSE (t), argvec,
+ tf_warning_or_error,
+ NULL_TREE);
+ if (expanded_bases == error_mark_node)
+ continue;
+
+ /* We'll be building separate TREE_LISTs of arguments for
+ each base. */
+ len = TREE_VEC_LENGTH (expanded_bases);
+ expanded_arguments = make_tree_vec (len);
+ for (i = 0; i < len; i++)
+ TREE_VEC_ELT (expanded_arguments, i) = NULL_TREE;
+
+ /* Build a dummy EXPR_PACK_EXPANSION that will be used to
+ expand each argument in the TREE_VALUE of t. */
+ expr = make_node (EXPR_PACK_EXPANSION);
+ PACK_EXPANSION_PARAMETER_PACKS (expr) =
+ PACK_EXPANSION_PARAMETER_PACKS (TREE_PURPOSE (t));
+
+ /* Substitute parameter packs into each argument in the
+ TREE_LIST. */
+ in_base_initializer = 1;
+ for (arg = TREE_VALUE (t); arg; arg = TREE_CHAIN (arg))
+ {
+ tree expanded_exprs;
+
+ /* Expand the argument. */
+ SET_PACK_EXPANSION_PATTERN (expr, TREE_VALUE (arg));
+ expanded_exprs = tsubst_pack_expansion (expr, argvec,
+ tf_warning_or_error,
+ NULL_TREE);
+
+ /* Prepend each of the expanded expressions to the
+ corresponding TREE_LIST in EXPANDED_ARGUMENTS. */
+ for (i = 0; i < len; i++)
+ {
+ TREE_VEC_ELT (expanded_arguments, i) =
+ tree_cons (NULL_TREE, TREE_VEC_ELT (expanded_exprs, i),
+ TREE_VEC_ELT (expanded_arguments, i));
+ }
+ }
+ in_base_initializer = 0;
+
+ /* Reverse all of the TREE_LISTs in EXPANDED_ARGUMENTS,
+ since we built them backwards. */
+ for (i = 0; i < len; i++)
+ {
+ TREE_VEC_ELT (expanded_arguments, i) =
+ nreverse (TREE_VEC_ELT (expanded_arguments, i));
+ }
+ }
- if (decl)
- {
- init = build_tree_list (decl, init);
- TREE_CHAIN (init) = inits;
- inits = init;
- }
+ for (i = 0; i < len; ++i)
+ {
+ if (expanded_bases)
+ {
+ decl = TREE_VEC_ELT (expanded_bases, i);
+ decl = expand_member_init (decl);
+ init = TREE_VEC_ELT (expanded_arguments, i);
+ }
+ else
+ {
+ decl = tsubst_copy (TREE_PURPOSE (t), argvec,
+ tf_warning_or_error, NULL_TREE);
+
+ decl = expand_member_init (decl);
+ if (decl && !DECL_P (decl))
+ in_base_initializer = 1;
+
+ init = tsubst_expr (TREE_VALUE (t), argvec,
+ tf_warning_or_error, NULL_TREE,
+ /*integral_constant_expression_p=*/false);
+ in_base_initializer = 0;
+ }
+
+ if (decl)
+ {
+ init = build_tree_list (decl, init);
+ TREE_CHAIN (init) = inits;
+ inits = init;
+ }
+ }
}
return inits;
}
if (TREE_CODE (type) == TYPEOF_TYPE)
return true;
+ /* A template argument pack is dependent if any of its packed
+ arguments are. */
+ if (TREE_CODE (type) == TYPE_ARGUMENT_PACK)
+ {
+ tree args = ARGUMENT_PACK_ARGS (type);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; ++i)
+ if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
+ return true;
+ }
+
+ /* All TYPE_PACK_EXPANSIONs are dependent, because parameter packs must
+ be template parameters. */
+ if (TREE_CODE (type) == TYPE_PACK_EXPANSION)
+ return true;
+
/* The standard does not specifically mention types that are local
to template functions or local classes, but they should be
considered dependent too. For example:
case SIZEOF_EXPR:
case ALIGNOF_EXPR:
/* A `sizeof' expression is value-dependent if the operand is
- type-dependent. */
+ type-dependent or is a pack expansion. */
expression = TREE_OPERAND (expression, 0);
- if (TYPE_P (expression))
+ if (PACK_EXPANSION_P (expression))
+ return true;
+ else if (TYPE_P (expression))
return dependent_type_p (expression);
return type_dependent_expression_p (expression);
such calls are value-dependent. */
return true;
+ case NONTYPE_ARGUMENT_PACK:
+ /* A NONTYPE_ARGUMENT_PACK is value-dependent if any packed argument
+ is value-dependent. */
+ {
+ tree values = ARGUMENT_PACK_ARGS (expression);
+ int i, len = TREE_VEC_LENGTH (values);
+
+ for (i = 0; i < len; ++i)
+ if (value_dependent_expression_p (TREE_VEC_ELT (values, i)))
+ return true;
+
+ return false;
+ }
+
default:
/* A constant expression is value-dependent if any subexpression is
value-dependent. */
/* Returns TRUE if the ARG (a template argument) is dependent. */
-static bool
+bool
dependent_template_arg_p (tree arg)
{
if (!processing_template_decl)
if (TREE_CODE (arg) == TEMPLATE_DECL
|| TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
return dependent_template_p (arg);
+ else if (ARGUMENT_PACK_P (arg))
+ {
+ tree args = ARGUMENT_PACK_ARGS (arg);
+ int i, len = TREE_VEC_LENGTH (args);
+ for (i = 0; i < len; ++i)
+ {
+ if (dependent_template_arg_p (TREE_VEC_ELT (args, i)))
+ return true;
+ }
+
+ return false;
+ }
else if (TYPE_P (arg))
return dependent_type_p (arg);
else
for (j = 0; j < TREE_VEC_LENGTH (level); ++j)
{
tree arg = TREE_VEC_ELT (level, j);
- if (error_operand_p (arg))
- return true;
- else if (TREE_CODE (arg) == TEMPLATE_DECL
- || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
- continue;
- else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg))
- return true;
- else if (!TYPE_P (arg) && TREE_TYPE (arg)
- && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
- return true;
+ tree packed_args = NULL_TREE;
+ int k, len = 1;
+
+ if (ARGUMENT_PACK_P (arg))
+ {
+ /* Look inside the argument pack. */
+ packed_args = ARGUMENT_PACK_ARGS (arg);
+ len = TREE_VEC_LENGTH (packed_args);
+ }
+
+ for (k = 0; k < len; ++k)
+ {
+ if (packed_args)
+ arg = TREE_VEC_ELT (packed_args, k);
+
+ if (error_operand_p (arg))
+ return true;
+ else if (TREE_CODE (arg) == TEMPLATE_DECL
+ || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+ continue;
+ else if (TYPE_P (arg) && TYPE_STRUCTURAL_EQUALITY_P (arg))
+ return true;
+ else if (!TYPE_P (arg) && TREE_TYPE (arg)
+ && TYPE_STRUCTURAL_EQUALITY_P (TREE_TYPE (arg)))
+ return true;
+ }
}
}