tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
tree specargs = CLASSTYPE_TI_ARGS (type);
tree inner_args = INNERMOST_TEMPLATE_ARGS (specargs);
- tree inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
tree main_inner_parms = DECL_INNERMOST_TEMPLATE_PARMS (maintmpl);
+ tree inner_parms;
int nargs = TREE_VEC_LENGTH (inner_args);
- int ntparms = TREE_VEC_LENGTH (inner_parms);
+ int ntparms;
int i;
int did_error_intro = 0;
struct template_parm_data tpd;
struct template_parm_data tpd2;
+ gcc_assert (current_template_parms);
+
+ inner_parms = INNERMOST_TEMPLATE_PARMS (current_template_parms);
+ ntparms = TREE_VEC_LENGTH (inner_parms);
+
/* We check that each of the template parameters given in the
partial specialization is used in the argument list to the
specialization. For example:
if (TREE_PURPOSE (parm))
seen_def_arg_p = 1;
- else if (seen_def_arg_p)
+ else if (seen_def_arg_p
+ && !template_parameter_pack_p (TREE_VALUE (parm)))
{
error ("no default argument for %qD", TREE_VALUE (parm));
/* For better subsequent error-recovery, we indicate that
else if (is_primary
&& !is_partial
&& !is_friend_decl
+ /* Don't complain about an enclosing partial
+ specialization. */
+ && parm_level == parms
&& TREE_CODE (decl) == TYPE_DECL
&& i < ntparms - 1
&& template_parameter_pack_p (TREE_VALUE (parm)))
[temp.mem]. */
bool member_template_p = false;
- if (decl == error_mark_node)
- return decl;
+ if (decl == error_mark_node || !current_template_parms)
+ return error_mark_node;
/* See if this is a partial specialization. */
is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)
D<int, C> d;
i.e. the parameter list of TT depends on earlier parameters. */
- if (!dependent_type_p (TREE_TYPE (arg))
+ if (!uses_template_parms (TREE_TYPE (arg))
&& !same_type_p
(tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),
TREE_TYPE (arg)))
if (invalid_nontype_parm_type_p (t, complain))
return error_mark_node;
- if (!uses_template_parms (orig_arg) && !uses_template_parms (t))
+ if (template_parameter_pack_p (parm) && ARGUMENT_PACK_P (orig_arg))
+ {
+ if (same_type_p (t, TREE_TYPE (orig_arg)))
+ val = orig_arg;
+ else
+ {
+ /* Not sure if this is reachable, but it doesn't hurt
+ to be robust. */
+ error ("type mismatch in nontype parameter pack");
+ val = error_mark_node;
+ }
+ }
+ else if (!uses_template_parms (orig_arg) && !uses_template_parms (t))
/* We used to call digest_init here. However, digest_init
will report errors, which we don't want when complain
is zero. More importantly, digest_init will try too
parameters. */
int variadic_p = 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);
/* Determine if there are any parameter packs. */
{
tree tparm = TREE_VALUE (TREE_VEC_ELT (parms, parm_idx));
if (template_parameter_pack_p (tparm))
- {
- variadic_p = 1;
- break;
- }
+ ++variadic_p;
}
- if ((nargs > nparms - variadic_p && !variadic_p)
+ inner_args = INNERMOST_TEMPLATE_ARGS (args);
+ /* If there are 0 or 1 parameter packs, we need to expand any argument
+ packs so that we can deduce a parameter pack from some non-packed args
+ followed by an argument pack, as in variadic85.C. If there are more
+ than that, we need to leave argument packs intact so the arguments are
+ assigned to the right parameter packs. This should only happen when
+ dealing with a nested class inside a partial specialization of a class
+ template, as in variadic92.C. */
+ if (variadic_p <= 1)
+ inner_args = expand_template_argument_pack (inner_args);
+
+ nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
+ if ((nargs > nparms && !variadic_p)
|| (nargs < nparms - variadic_p
&& require_all_args
&& (!use_default_args
}
/* Calculate the next argument. */
- if (template_parameter_pack_p (TREE_VALUE (parm)))
+ if (arg_idx < nargs)
+ arg = TREE_VEC_ELT (inner_args, arg_idx);
+ else
+ arg = NULL_TREE;
+
+ if (template_parameter_pack_p (TREE_VALUE (parm))
+ && !(arg && ARGUMENT_PACK_P (arg)))
{
- /* All remaining arguments will be placed in the
- template parameter pack PARM. */
- arg = coerce_template_parameter_pack (parms, parm_idx, args,
- inner_args, arg_idx,
- new_args, &lost,
- in_decl, complain);
-
+ /* All remaining arguments will be placed in the
+ template parameter pack PARM. */
+ arg = coerce_template_parameter_pack (parms, parm_idx, args,
+ inner_args, arg_idx,
+ new_args, &lost,
+ in_decl, complain);
+
/* Store this argument. */
if (arg == error_mark_node)
lost++;
TREE_VEC_ELT (new_inner_args, parm_idx) = arg;
- /* We are done with all of the arguments. */
- arg_idx = nargs;
-
+ /* We are done with all of the arguments. */
+ arg_idx = nargs;
+
continue;
}
- else if (arg_idx < nargs)
- {
- arg = TREE_VEC_ELT (inner_args, arg_idx);
-
- if (arg && PACK_EXPANSION_P (arg))
+ else if (arg)
+ {
+ if (PACK_EXPANSION_P (arg))
{
if (complain & tf_error)
{
+ /* FIXME this restriction was removed by N2555; see
+ bug 35722. */
/* If ARG is a pack expansion, but PARM is not a
template parameter pack (if it were, we would have
handled it above), we're trying to expand into a
fixed-length argument list. */
if (TREE_CODE (arg) == EXPR_PACK_EXPANSION)
- error ("cannot expand %<%E%> into a fixed-length "
+ sorry ("cannot expand %<%E%> into a fixed-length "
"argument list", arg);
else
- error ("cannot expand %<%T%> into a fixed-length "
+ sorry ("cannot expand %<%T%> into a fixed-length "
"argument list", arg);
}
return error_mark_node;
return PACK_EXPANSION_P (nt)
&& template_args_equal (PACK_EXPANSION_PATTERN (ot),
PACK_EXPANSION_PATTERN (nt));
+ else if (ARGUMENT_PACK_P (ot))
+ {
+ int i, len;
+ tree opack, npack;
+
+ if (!ARGUMENT_PACK_P (nt))
+ return 0;
+
+ opack = ARGUMENT_PACK_ARGS (ot);
+ npack = ARGUMENT_PACK_ARGS (nt);
+ len = TREE_VEC_LENGTH (opack);
+ if (TREE_VEC_LENGTH (npack) != len)
+ return 0;
+ for (i = 0; i < len; ++i)
+ if (!template_args_equal (TREE_VEC_ELT (opack, i),
+ TREE_VEC_ELT (npack, i)))
+ return 0;
+ return 1;
+ }
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;
d1 = DECL_NAME (templ);
}
else if (TREE_CODE (d1) == TEMPLATE_DECL
+ && DECL_TEMPLATE_RESULT (d1)
&& TREE_CODE (DECL_TEMPLATE_RESULT (d1)) == TYPE_DECL)
{
templ = d1;
return level;
}
+/* Returns TRUE if PARM is a parameter of the template TEMPL. */
+
+bool
+parameter_of_template_p (tree parm, tree templ)
+{
+ tree parms;
+ int i;
+
+ if (!parm || !templ)
+ return false;
+
+ gcc_assert (DECL_TEMPLATE_PARM_P (parm));
+ gcc_assert (TREE_CODE (templ) == TEMPLATE_DECL);
+
+ parms = DECL_TEMPLATE_PARMS (templ);
+ parms = INNERMOST_TEMPLATE_PARMS (parms);
+
+ for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
+ if (parm == TREE_VALUE (TREE_VEC_ELT (parms, i)))
+ return true;
+
+ return false;
+}
+
/* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL. ARGS is the
vector of template arguments, as for tsubst.
DECL_PENDING_INLINE_INFO (r) = 0;
DECL_PENDING_INLINE_P (r) = 0;
DECL_SAVED_TREE (r) = NULL_TREE;
+ DECL_STRUCT_FUNCTION (r) = NULL;
TREE_USED (r) = 0;
if (DECL_CLONED_FUNCTION (r))
{
{
tree type;
- type =
- finish_decltype_type (tsubst_expr
- (DECLTYPE_TYPE_EXPR (t), args,
- complain, in_decl,
- /*integral_constant_expression_p=*/false),
+ ++skip_evaluation;
+
+ type = tsubst_expr (DECLTYPE_TYPE_EXPR (t), args,
+ complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+
+ --skip_evaluation;
+
+ type =
+ finish_decltype_type (type,
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
return cp_build_qualified_type_real (type,
cp_type_quals (t)
{
case PARM_DECL:
r = retrieve_local_specialization (t);
- gcc_assert (r != NULL);
+
+ if (r == NULL)
+ {
+ /* This can happen for a parameter name used later in a function
+ declaration (such as in a late-specified return type).
+ Replace it with an arbitrary expression with the same type
+ (*(T*)0). This should only occur in an unevaluated context
+ (i.e. decltype). */
+ gcc_assert (skip_evaluation);
+ r = non_reference (TREE_TYPE (t));
+ r = tsubst (r, args, complain, in_decl);
+ r = build_pointer_type (r);
+ r = build_c_cast (r, null_node);
+ return cp_build_indirect_ref (r, NULL, tf_warning_or_error);
+ }
+
if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
r = ARGUMENT_PACK_SELECT_ARG (r);
mark_used (r);
#define RECUR(NODE) \
tsubst_expr ((NODE), args, complain, in_decl, \
integral_constant_expression_p)
- tree decl, init, cond, incr;
+ tree decl, init, cond, incr, auto_node;
init = TREE_VEC_ELT (OMP_FOR_INIT (t), i);
gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
decl = RECUR (TREE_OPERAND (init, 0));
init = TREE_OPERAND (init, 1);
+ auto_node = type_uses_auto (TREE_TYPE (decl));
+ if (auto_node && init)
+ {
+ tree init_expr = init;
+ if (TREE_CODE (init_expr) == DECL_EXPR)
+ init_expr = DECL_INITIAL (DECL_EXPR_DECL (init_expr));
+ init_expr = RECUR (init_expr);
+ TREE_TYPE (decl)
+ = do_auto_deduction (TREE_TYPE (decl), init_expr, auto_node);
+ }
gcc_assert (!type_dependent_expression_p (decl));
if (!CLASS_TYPE_P (TREE_TYPE (decl)))
pack expansion where the parameter packs
used in that expansion were of length
zero. */
- init = build_default_init (TREE_TYPE (decl),
- NULL_TREE);
+ init = build_value_init (TREE_TYPE (decl));
else
init = t;
}
}
r = build_constructor (init_list_type_node, n);
+ CONSTRUCTOR_IS_DIRECT_INIT (r) = CONSTRUCTOR_IS_DIRECT_INIT (t);
if (TREE_HAS_CONSTRUCTOR (t))
return finish_compound_literal (type, r);
Emit an error under control of COMPLAIN, and return TRUE on error. */
static bool
-check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)
+check_instantiated_arg (tree tmpl, tree t, tsubst_flags_t complain)
{
- int ix, len = DECL_NTPARMS (tmpl);
- bool result = false;
+ if (ARGUMENT_PACK_P (t))
+ {
+ tree vec = ARGUMENT_PACK_ARGS (t);
+ int len = TREE_VEC_LENGTH (vec);
+ bool result = false;
+ int i;
- for (ix = 0; ix != len; ix++)
+ for (i = 0; i < len; ++i)
+ if (check_instantiated_arg (tmpl, TREE_VEC_ELT (vec, i), complain))
+ result = true;
+ return result;
+ }
+ else if (TYPE_P (t))
{
- tree t = TREE_VEC_ELT (args, ix);
+ /* [basic.link]: A name with no linkage (notably, the name
+ of a class or enumeration declared in a local scope)
+ shall not be used to declare an entity with linkage.
+ This implies that names with no linkage cannot be used as
+ template arguments. */
+ tree nt = no_linkage_check (t, /*relaxed_p=*/false);
- if (TYPE_P (t))
+ if (nt)
{
- /* [basic.link]: A name with no linkage (notably, the name
- of a class or enumeration declared in a local scope)
- shall not be used to declare an entity with linkage.
- This implies that names with no linkage cannot be used as
- template arguments. */
- tree nt = no_linkage_check (t, /*relaxed_p=*/false);
-
- if (nt)
- {
- /* DR 488 makes use of a type with no linkage cause
- type deduction to fail. */
- if (complain & tf_error)
- {
- if (TYPE_ANONYMOUS_P (nt))
- error ("%qT is/uses anonymous type", t);
- else
- error ("template argument for %qD uses local type %qT",
- tmpl, t);
- }
- result = true;
- }
- /* In order to avoid all sorts of complications, we do not
- allow variably-modified types as template arguments. */
- else if (variably_modified_type_p (t, NULL_TREE))
+ /* DR 488 makes use of a type with no linkage cause
+ type deduction to fail. */
+ if (complain & tf_error)
{
- if (complain & tf_error)
- error ("%qT is a variably modified type", t);
- result = true;
+ if (TYPE_ANONYMOUS_P (nt))
+ error ("%qT is/uses anonymous type", t);
+ else
+ error ("template argument for %qD uses local type %qT",
+ tmpl, t);
}
+ return true;
}
- /* A non-type argument of integral or enumerated type must be a
- constant. */
- else if (TREE_TYPE (t)
- && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t))
- && !TREE_CONSTANT (t))
+ /* In order to avoid all sorts of complications, we do not
+ allow variably-modified types as template arguments. */
+ else if (variably_modified_type_p (t, NULL_TREE))
{
if (complain & tf_error)
- error ("integral expression %qE is not constant", t);
- result = true;
+ error ("%qT is a variably modified type", t);
+ return true;
}
}
+ /* A non-type argument of integral or enumerated type must be a
+ constant. */
+ else if (TREE_TYPE (t)
+ && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t))
+ && !TREE_CONSTANT (t))
+ {
+ if (complain & tf_error)
+ error ("integral expression %qE is not constant", t);
+ return true;
+ }
+ return false;
+}
+
+static bool
+check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)
+{
+ int ix, len = DECL_NTPARMS (tmpl);
+ bool result = false;
+
+ for (ix = 0; ix != len; ix++)
+ {
+ if (check_instantiated_arg (tmpl, TREE_VEC_ELT (args, ix), complain))
+ result = true;
+ }
if (result && (complain & tf_error))
error (" trying to instantiate %qD", tmpl);
return result;
input_location = saved_loc;
if (at_eof && !pattern_defined
- && DECL_EXPLICIT_INSTANTIATION (d))
+ && DECL_EXPLICIT_INSTANTIATION (d)
+ && DECL_NOT_REALLY_EXTERN (d))
/* [temp.explicit]
The definition of a non-exported function template, a