type_specializations->remove_elt (&elt);
elt.tmpl = tmpl;
- elt.args = INNERMOST_TEMPLATE_ARGS (elt.args);
+ CLASSTYPE_TI_ARGS (inst)
+ = elt.args = INNERMOST_TEMPLATE_ARGS (elt.args);
spec_entry **slot
= type_specializations->find_slot (&elt, INSERT);
/* Now hash operands as usual. */
break;
+ case CALL_EXPR:
+ {
+ tree fn = CALL_EXPR_FN (arg);
+ if (tree name = dependent_name (fn))
+ {
+ if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+ val = iterative_hash_template_arg (TREE_OPERAND (fn, 1), val);
+ fn = name;
+ }
+ val = iterative_hash_template_arg (fn, val);
+ call_expr_arg_iterator ai;
+ for (tree x = first_call_expr_arg (arg, &ai); x;
+ x = next_call_expr_arg (&ai))
+ val = iterative_hash_template_arg (x, val);
+ return val;
+ }
+
default:
break;
}
class expansion. */
ppd.visited = new hash_set<tree>;
ppd.parameter_packs = ¶meter_packs;
- ppd.type_pack_expansion_p = true;
+ ppd.type_pack_expansion_p = false;
gcc_assert (TYPE_P (TREE_PURPOSE (arg)));
cp_walk_tree (&TREE_PURPOSE (arg), &find_parameter_packs_r,
&ppd, ppd.visited);
process_template_parm could fail. */
tree reqs = finish_shorthand_constraint (parm, constr);
- pushdecl (decl);
+ decl = pushdecl (decl);
+ if (!is_non_type)
+ parm = decl;
/* Build the parameter node linking the parameter declaration,
its default argument (if any), and its constraints (if any). */
tree vec = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm));
for (int i = 0; i < TREE_VEC_LENGTH (vec); ++i)
- fixed_parameter_pack_p_1 (TREE_VALUE (TREE_VEC_ELT (vec, i)), ppd);
+ {
+ tree p = TREE_VALUE (TREE_VEC_ELT (vec, i));
+ if (template_parameter_pack_p (p))
+ /* Any packs in the type are expanded by this parameter. */;
+ else
+ fixed_parameter_pack_p_1 (p, ppd);
+ }
}
/* PARM is a template parameter pack. Return any parameter packs used in
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
|| cxx_dialect >= cxx17)
{
+ /* Calling build_converted_constant_expr might create a call to
+ a conversion function with a value-dependent argument, which
+ could invoke taking the address of a temporary representing
+ the result of the conversion. */
+ if (COMPOUND_LITERAL_P (expr)
+ && CONSTRUCTOR_IS_DEPENDENT (expr)
+ && MAYBE_CLASS_TYPE_P (expr_type)
+ && TYPE_HAS_CONVERSION (expr_type))
+ {
+ expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
+ IMPLICIT_CONV_EXPR_NONTYPE_ARG (expr) = true;
+ return expr;
+ }
/* C++17: A template-argument for a non-type template-parameter shall
be a converted constant expression (8.20) of the type of the
template-parameter. */
args and the converted args. If that succeeds, A is at least as
specialized as P, so they match.*/
tree pargs = template_parms_level_to_args (parm_parms);
+ pargs = add_outermost_template_args (outer_args, pargs);
++processing_template_decl;
pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none,
/*require_all*/true, /*use_default*/true);
int j, len = TREE_VEC_LENGTH (packed_parms);
for (j = 0; j < len; ++j)
{
- tree t = TREE_TYPE (TREE_VEC_ELT (packed_parms, j));
- if (invalid_nontype_parm_type_p (t, complain))
+ tree t = TREE_VEC_ELT (packed_parms, j);
+ if (TREE_CODE (t) == PARM_DECL
+ && invalid_nontype_parm_type_p (TREE_TYPE (t), complain))
return error_mark_node;
}
/* We don't know how many args we have yet, just
arg = NULL_TREE;
if (template_parameter_pack_p (TREE_VALUE (parm))
+ && (arg || !(complain & tf_partial))
&& !(arg && ARGUMENT_PACK_P (arg)))
{
/* Some arguments will be placed in the
: (TREE_CODE (found) == TYPE_DECL
? DECL_TI_TEMPLATE (found)
: CLASSTYPE_TI_TEMPLATE (found)));
+
+ if (DECL_CLASS_TEMPLATE_P (found)
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (found)))
+ {
+ /* If this partial instantiation is specialized, we want to
+ use it for hash table lookup. */
+ elt.tmpl = found;
+ elt.args = arglist = INNERMOST_TEMPLATE_ARGS (arglist);
+ hash = spec_hasher::hash (&elt);
+ }
}
// Build template info for the new specialization.
elt.spec = t;
slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT);
+ gcc_checking_assert (*slot == NULL);
entry = ggc_alloc<spec_entry> ();
*entry = elt;
*slot = entry;
static int
argument_pack_element_is_expansion_p (tree arg_pack, int i)
{
+ if (TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT)
+ /* We're being called before this happens in tsubst_pack_expansion. */
+ arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack);
tree vec = ARGUMENT_PACK_ARGS (arg_pack);
if (i >= TREE_VEC_LENGTH (vec))
return 0;
hash = hash_tmpl_and_args (t, full_args);
spec = retrieve_specialization (t, full_args, hash);
if (spec != NULL_TREE)
- return spec;
+ {
+ if (TYPE_P (spec))
+ /* Type partial instantiations are stored as the type by
+ lookup_template_class_1, not here as the template. */
+ spec = CLASSTYPE_TI_TEMPLATE (spec);
+ return spec;
+ }
}
/* Make a new template decl. It will be similar to the
DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec);
SET_DECL_IMPLICIT_INSTANTIATION (r);
- register_specialization (r, gen_tmpl, argvec, false, hash);
+ if (!error_operand_p (r) || (complain & tf_error))
+ register_specialization (r, gen_tmpl, argvec, false, hash);
}
else
{
{
/* First try name lookup to find the instantiation. */
r = lookup_name (DECL_NAME (t));
- if (r && !is_capture_proxy (r))
+ if (r)
{
- /* Make sure that the one we found is the one we want. */
- tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
- if (ctx != DECL_CONTEXT (r))
- r = NULL_TREE;
+ if (!VAR_P (r))
+ {
+ /* During error-recovery we may find a non-variable,
+ even an OVERLOAD: just bail out and avoid ICEs and
+ duplicate diagnostics (c++/62207). */
+ gcc_assert (seen_error ());
+ return error_mark_node;
+ }
+ if (!is_capture_proxy (r))
+ {
+ /* Make sure the one we found is the one we want. */
+ tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
+ if (ctx != DECL_CONTEXT (r))
+ r = NULL_TREE;
+ }
}
if (r)
}
gcc_assert (cp_unevaluated_operand || TREE_STATIC (r)
|| decl_constant_var_p (r)
- || errorcount || sorrycount);
+ || seen_error ());
if (!processing_template_decl
&& !TREE_STATIC (r))
r = process_outer_var_ref (r, complain);
{
tree r = tsubst_copy (t, args, complain, in_decl);
/* ??? We're doing a subset of finish_id_expression here. */
- if (VAR_P (r)
- && !processing_template_decl
- && !cp_unevaluated_operand
- && (TREE_STATIC (r) || DECL_EXTERNAL (r))
- && CP_DECL_THREAD_LOCAL_P (r))
- {
- if (tree wrap = get_tls_wrapper_fn (r))
- /* Replace an evaluated use of the thread_local variable with
- a call to its wrapper. */
- r = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
- }
+ if (tree wrap = maybe_get_tls_wrapper_call (r))
+ /* Replace an evaluated use of the thread_local variable with
+ a call to its wrapper. */
+ r = wrap;
else if (outer_automatic_var_p (r))
r = process_outer_var_ref (r, complain);
substitution context. */
explicit_targs
= (coerce_template_parms (tparms, explicit_targs, NULL_TREE,
- complain,
+ complain|tf_partial,
/*require_all_args=*/false,
/*use_default_args=*/false));
if (explicit_targs == error_mark_node)
}
else
{
+ /* Even if the call is happening in template context, getting
+ here means it's non-dependent, and a default argument is
+ considered a separate definition under [temp.decls], so we can
+ do this substitution without processing_template_decl. This
+ is important if the default argument contains something that
+ might be instantiation-dependent like access (87480). */
+ processing_template_decl_sentinel s;
tree substed = NULL_TREE;
- if (saw_undeduced == 1 && processing_template_decl == 0)
+ if (saw_undeduced == 1)
{
/* First instatiate in template context, in case we still
depend on undeduced template parameters. */
args = INNERMOST_TEMPLATE_ARGS (args);
}
+ /* The caller hasn't called push_to_top_level yet, but we need
+ get_partial_spec_bindings to be done in non-template context so that we'll
+ fully resolve everything. */
+ processing_template_decl_sentinel ptds;
+
for (t = DECL_TEMPLATE_SPECIALIZATIONS (main_tmpl); t; t = TREE_CHAIN (t))
{
tree spec_args;
if (DECL_CLONED_FUNCTION_P (fn))
fn = DECL_CLONED_FUNCTION (fn);
+
+ tree orig_fn = NULL_TREE;
+ /* For a member friend template we can get a TEMPLATE_DECL. Let's use
+ its FUNCTION_DECL for the rest of this function -- push_access_scope
+ doesn't accept TEMPLATE_DECLs. */
+ if (DECL_FUNCTION_TEMPLATE_P (fn))
+ {
+ orig_fn = fn;
+ fn = DECL_TEMPLATE_RESULT (fn);
+ }
+
fntype = TREE_TYPE (fn);
spec = TYPE_RAISES_EXCEPTIONS (fntype);
push_deferring_access_checks (dk_no_deferred);
input_location = DECL_SOURCE_LOCATION (fn);
- /* A new stack interferes with pop_access_scope. */
- {
- /* Set up the list of local specializations. */
- local_specialization_stack lss (lss_copy);
-
- tree save_ccp = current_class_ptr;
- tree save_ccr = current_class_ref;
- /* If needed, set current_class_ptr for the benefit of
- tsubst_copy/PARM_DECL. */
- tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
- if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
- {
- tree this_parm = DECL_ARGUMENTS (tdecl);
- current_class_ptr = NULL_TREE;
- current_class_ref = cp_build_fold_indirect_ref (this_parm);
- current_class_ptr = this_parm;
- }
+ tree save_ccp = current_class_ptr;
+ tree save_ccr = current_class_ref;
+ /* If needed, set current_class_ptr for the benefit of
+ tsubst_copy/PARM_DECL. */
+ tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
+ {
+ tree this_parm = DECL_ARGUMENTS (tdecl);
+ current_class_ptr = NULL_TREE;
+ current_class_ref = cp_build_fold_indirect_ref (this_parm);
+ current_class_ptr = this_parm;
+ }
- /* Create substitution entries for the parameters. */
- register_parameter_specializations (tdecl, fn);
+ /* If this function is represented by a TEMPLATE_DECL, then
+ the deferred noexcept-specification might still contain
+ dependent types, even after substitution. And we need the
+ dependency check functions to work in build_noexcept_spec. */
+ if (orig_fn)
+ ++processing_template_decl;
- /* Do deferred instantiation of the noexcept-specifier. */
- noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
- DEFERRED_NOEXCEPT_ARGS (noex),
- tf_warning_or_error, fn,
- /*function_p=*/false,
- /*i_c_e_p=*/true);
- current_class_ptr = save_ccp;
- current_class_ref = save_ccr;
- spec = build_noexcept_spec (noex, tf_warning_or_error);
- }
+ /* Do deferred instantiation of the noexcept-specifier. */
+ noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
+ DEFERRED_NOEXCEPT_ARGS (noex),
+ tf_warning_or_error, fn,
+ /*function_p=*/false,
+ /*i_c_e_p=*/true);
+
+ current_class_ptr = save_ccp;
+ current_class_ref = save_ccr;
+
+ /* Build up the noexcept-specification. */
+ spec = build_noexcept_spec (noex, tf_warning_or_error);
+
+ if (orig_fn)
+ --processing_template_decl;
pop_deferring_access_checks ();
pop_access_scope (fn);
}
TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+ if (orig_fn)
+ TREE_TYPE (orig_fn) = TREE_TYPE (fn);
}
FOR_EACH_CLONE (clone, fn)
|| TREE_CODE (expression) == WILDCARD_DECL)
return true;
+ /* A lambda-expression in template context is dependent. dependent_type_p is
+ true for a lambda in the scope of a class or function template, but that
+ doesn't cover all template contexts, like a default template argument. */
+ if (TREE_CODE (expression) == LAMBDA_EXPR)
+ return true;
+
/* A fold expression is type-dependent. */
if (TREE_CODE (expression) == UNARY_LEFT_FOLD_EXPR
|| TREE_CODE (expression) == UNARY_RIGHT_FOLD_EXPR
if (init && undeduced_auto_decl (init))
return type;
+ /* We may be doing a partial substitution, but we still want to replace
+ auto_node. */
+ complain &= ~tf_partial;
+
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
/* C++17 class template argument deduction. */
return do_class_deduction (type, tmpl, init, flags, complain);