@@ -9670,18 +9670,6 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner;
}
- /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */
- if (deduction_guide_p (cand1->fn))
- {
- gcc_assert (deduction_guide_p (cand2->fn));
- /* We distinguish between candidates from an explicit deduction guide and
- candidates built from a constructor based on DECL_ARTIFICIAL. */
- int art1 = DECL_ARTIFICIAL (cand1->fn);
- int art2 = DECL_ARTIFICIAL (cand2->fn);
- if (art1 != art2)
- return art2 - art1;
- }
-
/* or, if not that,
F1 is a non-template function and F2 is a template function
specialization. */
@@ -9719,6 +9707,18 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner;
}
+ /* F1 is generated from a deduction-guide (13.3.1.8) and F2 is not */
+ if (deduction_guide_p (cand1->fn))
+ {
+ gcc_assert (deduction_guide_p (cand2->fn));
+ /* We distinguish between candidates from an explicit deduction guide and
+ candidates built from a constructor based on DECL_ARTIFICIAL. */
+ int art1 = DECL_ARTIFICIAL (cand1->fn);
+ int art2 = DECL_ARTIFICIAL (cand2->fn);
+ if (art1 != art2)
+ return art2 - art1;
+ }
+
/* or, if not that, F2 is from a using-declaration, F1 is not, and the
conversion sequences are equivalent.
(proposed in http://lists.isocpp.org/core/2016/10/1142.php) */
@@ -5238,13 +5238,15 @@ start_decl_1 (tree decl, bool initialized)
else if (aggregate_definition_p && !complete_p)
{
if (type_uses_auto (type))
- gcc_unreachable ();
+ gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (type));
else
- error ("aggregate %q#D has incomplete type and cannot be defined",
- decl);
- /* Change the type so that assemble_variable will give
- DECL an rtl we can live with: (mem (const_int 0)). */
- type = TREE_TYPE (decl) = error_mark_node;
+ {
+ error ("aggregate %q#D has incomplete type and cannot be defined",
+ decl);
+ /* Change the type so that assemble_variable will give
+ DECL an rtl we can live with: (mem (const_int 0)). */
+ type = TREE_TYPE (decl) = error_mark_node;
+ }
}
/* Create a new scope to hold this declaration if necessary.
@@ -6816,14 +6818,17 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
return;
}
- gcc_unreachable ();
+ gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (auto_node));
}
d_init = init;
- if (TREE_CODE (d_init) == TREE_LIST
- && !CLASS_PLACEHOLDER_TEMPLATE (auto_node))
- d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
- tf_warning_or_error);
- d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
+ if (d_init)
+ {
+ if (TREE_CODE (d_init) == TREE_LIST
+ && !CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+ d_init = build_x_compound_expr_from_list (d_init, ELK_INIT,
+ tf_warning_or_error);
+ d_init = resolve_nondeduced_context (d_init, tf_warning_or_error);
+ }
enum auto_deduction_context adc = adc_variable_type;
if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
adc = adc_decomp_type;
@@ -12323,19 +12328,12 @@ grokdeclarator (const cp_declarator *declarator,
if (VAR_P (decl) && !initialized)
if (tree auto_node = type_uses_auto (type))
- {
- location_t loc = declspecs->locations[ds_type_spec];
- if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
- {
- error_at (loc, "invalid use of template-name %qE without an "
- "argument list", tmpl);
- inform (loc, "class template argument deduction "
- "requires an initializer");
- }
- else
+ if (!CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+ {
+ location_t loc = declspecs->locations[ds_type_spec];
error_at (loc, "declaration of %q#D has no initializer", decl);
- TREE_TYPE (decl) = error_mark_node;
- }
+ TREE_TYPE (decl) = error_mark_node;
+ }
if (storage_class == sc_extern && initialized && !funcdef_flag)
{
@@ -24941,103 +24941,137 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
}
/* Returns a C++17 class deduction guide template based on the constructor
- CTOR. */
+ CTOR. As a special case, CTOR can be a RECORD_TYPE for an implicit default
+ guide, or REFERENCE_TYPE for an implicit copy/move guide. */
static tree
build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
{
- if (outer_args)
- ctor = tsubst (ctor, outer_args, complain, ctor);
- tree type = DECL_CONTEXT (ctor);
- tree fn_tmpl;
- if (TREE_CODE (ctor) == TEMPLATE_DECL)
+ tree type, tparms, targs, fparms, fargs, ci;
+ bool memtmpl = false;
+ bool explicit_p;
+ location_t loc;
+
+ if (TYPE_P (ctor))
{
- fn_tmpl = ctor;
- ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
+ type = ctor;
+ bool copy_p = TREE_CODE (type) == REFERENCE_TYPE;
+ if (copy_p)
+ {
+ type = TREE_TYPE (type);
+ fparms = tree_cons (NULL_TREE, type, void_list_node);
+ }
+ else
+ fparms = void_list_node;
+
+ tree ctmpl = CLASSTYPE_TI_TEMPLATE (type);
+ tparms = DECL_TEMPLATE_PARMS (ctmpl);
+ targs = CLASSTYPE_TI_ARGS (type);
+ ci = NULL_TREE;
+ fargs = NULL_TREE;
+ loc = DECL_SOURCE_LOCATION (ctmpl);
+ explicit_p = false;
}
else
- fn_tmpl = DECL_TI_TEMPLATE (ctor);
+ {
+ if (outer_args)
+ ctor = tsubst (ctor, outer_args, complain, ctor);
+ type = DECL_CONTEXT (ctor);
+ tree fn_tmpl;
+ if (TREE_CODE (ctor) == TEMPLATE_DECL)
+ {
+ fn_tmpl = ctor;
+ ctor = DECL_TEMPLATE_RESULT (fn_tmpl);
+ }
+ else
+ fn_tmpl = DECL_TI_TEMPLATE (ctor);
- tree tparms = DECL_TEMPLATE_PARMS (fn_tmpl);
- /* If type is a member class template, DECL_TI_ARGS (ctor) will have fully
- specialized args for the enclosing class. Strip those off, as the
- deduction guide won't have those template parameters. */
- tree targs = get_innermost_template_args (DECL_TI_ARGS (ctor),
- TMPL_PARMS_DEPTH (tparms));
- /* Discard the 'this' parameter. */
- tree fparms = FUNCTION_ARG_CHAIN (ctor);
- tree fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor));
- tree ci = get_constraints (ctor);
+ tparms = DECL_TEMPLATE_PARMS (fn_tmpl);
+ /* If type is a member class template, DECL_TI_ARGS (ctor) will have
+ fully specialized args for the enclosing class. Strip those off, as
+ the deduction guide won't have those template parameters. */
+ targs = get_innermost_template_args (DECL_TI_ARGS (ctor),
+ TMPL_PARMS_DEPTH (tparms));
+ /* Discard the 'this' parameter. */
+ fparms = FUNCTION_ARG_CHAIN (ctor);
+ fargs = TREE_CHAIN (DECL_ARGUMENTS (ctor));
+ ci = get_constraints (ctor);
+ loc = DECL_SOURCE_LOCATION (ctor);
+ explicit_p = DECL_NONCONVERTING_P (ctor);
- if (PRIMARY_TEMPLATE_P (fn_tmpl))
- {
- /* For a member template constructor, we need to flatten the two template
- parameter lists into one, and then adjust the function signature
- accordingly. This gets...complicated. */
- ++processing_template_decl;
- tree save_parms = current_template_parms;
+ if (PRIMARY_TEMPLATE_P (fn_tmpl))
+ {
+ memtmpl = true;
- /* For a member template we should have two levels of parms/args, one for
- the class and one for the constructor. We stripped specialized args
- for further enclosing classes above. */
- const int depth = 2;
- gcc_assert (TMPL_ARGS_DEPTH (targs) == depth);
+ /* For a member template constructor, we need to flatten the two
+ template parameter lists into one, and then adjust the function
+ signature accordingly. This gets...complicated. */
+ ++processing_template_decl;
+ tree save_parms = current_template_parms;
- /* Template args for translating references to the two-level template
- parameters into references to the one-level template parameters we are
- creating. */
- tree tsubst_args = copy_node (targs);
- TMPL_ARGS_LEVEL (tsubst_args, depth)
- = copy_node (TMPL_ARGS_LEVEL (tsubst_args, depth));
+ /* For a member template we should have two levels of parms/args, one
+ for the class and one for the constructor. We stripped
+ specialized args for further enclosing classes above. */
+ const int depth = 2;
+ gcc_assert (TMPL_ARGS_DEPTH (targs) == depth);
- /* Template parms for the constructor template. */
- tree ftparms = TREE_VALUE (tparms);
- unsigned flen = TREE_VEC_LENGTH (ftparms);
- /* Template parms for the class template. */
- tparms = TREE_CHAIN (tparms);
- tree ctparms = TREE_VALUE (tparms);
- unsigned clen = TREE_VEC_LENGTH (ctparms);
- /* Template parms for the deduction guide start as a copy of the template
- parms for the class. We set current_template_parms for
- lookup_template_class_1. */
- current_template_parms = tparms = copy_node (tparms);
- tree new_vec = TREE_VALUE (tparms) = make_tree_vec (flen + clen);
- for (unsigned i = 0; i < clen; ++i)
- TREE_VEC_ELT (new_vec, i) = TREE_VEC_ELT (ctparms, i);
+ /* Template args for translating references to the two-level template
+ parameters into references to the one-level template parameters we
+ are creating. */
+ tree tsubst_args = copy_node (targs);
+ TMPL_ARGS_LEVEL (tsubst_args, depth)
+ = copy_node (TMPL_ARGS_LEVEL (tsubst_args, depth));
- /* Now we need to rewrite the constructor parms to append them to the
- class parms. */
- for (unsigned i = 0; i < flen; ++i)
- {
- unsigned index = i + clen;
- unsigned level = 1;
- tree oldelt = TREE_VEC_ELT (ftparms, i);
- tree olddecl = TREE_VALUE (oldelt);
- tree newdecl = rewrite_template_parm (olddecl, index, level,
- tsubst_args, complain);
- tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
- tsubst_args, complain, ctor);
- tree list = build_tree_list (newdef, newdecl);
- TEMPLATE_PARM_CONSTRAINTS (list)
- = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
- tsubst_args, complain, ctor);
- TREE_VEC_ELT (new_vec, index) = list;
- TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
- }
+ /* Template parms for the constructor template. */
+ tree ftparms = TREE_VALUE (tparms);
+ unsigned flen = TREE_VEC_LENGTH (ftparms);
+ /* Template parms for the class template. */
+ tparms = TREE_CHAIN (tparms);
+ tree ctparms = TREE_VALUE (tparms);
+ unsigned clen = TREE_VEC_LENGTH (ctparms);
+ /* Template parms for the deduction guide start as a copy of the
+ template parms for the class. We set current_template_parms for
+ lookup_template_class_1. */
+ current_template_parms = tparms = copy_node (tparms);
+ tree new_vec = TREE_VALUE (tparms) = make_tree_vec (flen + clen);
+ for (unsigned i = 0; i < clen; ++i)
+ TREE_VEC_ELT (new_vec, i) = TREE_VEC_ELT (ctparms, i);
+
+ /* Now we need to rewrite the constructor parms to append them to the
+ class parms. */
+ for (unsigned i = 0; i < flen; ++i)
+ {
+ unsigned index = i + clen;
+ unsigned level = 1;
+ tree oldelt = TREE_VEC_ELT (ftparms, i);
+ tree olddecl = TREE_VALUE (oldelt);
+ tree newdecl = rewrite_template_parm (olddecl, index, level,
+ tsubst_args, complain);
+ tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
+ tsubst_args, complain, ctor);
+ tree list = build_tree_list (newdef, newdecl);
+ TEMPLATE_PARM_CONSTRAINTS (list)
+ = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
+ tsubst_args, complain, ctor);
+ TREE_VEC_ELT (new_vec, index) = list;
+ TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
+ }
- /* Now we have a final set of template parms to substitute into the
- function signature. */
- targs = template_parms_to_args (tparms);
- fparms = tsubst_arg_types (fparms, tsubst_args, NULL_TREE,
- complain, ctor);
- fargs = tsubst (fargs, tsubst_args, complain, ctor);
- if (ci)
- ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor);
+ /* Now we have a final set of template parms to substitute into the
+ function signature. */
+ targs = template_parms_to_args (tparms);
+ fparms = tsubst_arg_types (fparms, tsubst_args, NULL_TREE,
+ complain, ctor);
+ fargs = tsubst (fargs, tsubst_args, complain, ctor);
+ if (ci)
+ ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor);
- current_template_parms = save_parms;
- --processing_template_decl;
+ current_template_parms = save_parms;
+ --processing_template_decl;
+ }
}
- else
+
+ if (!memtmpl)
{
/* Copy the parms so we can set DECL_PRIMARY_TEMPLATE. */
tparms = copy_node (tparms);
@@ -25046,12 +25080,12 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain)
}
tree fntype = build_function_type (type, fparms);
- tree ded_fn = build_lang_decl_loc (DECL_SOURCE_LOCATION (ctor),
+ tree ded_fn = build_lang_decl_loc (loc,
FUNCTION_DECL,
dguide_name (type), fntype);
DECL_ARGUMENTS (ded_fn) = fargs;
DECL_ARTIFICIAL (ded_fn) = true;
- DECL_NONCONVERTING_P (ded_fn) = DECL_NONCONVERTING_P (ctor);
+ DECL_NONCONVERTING_P (ded_fn) = explicit_p;
tree ded_tmpl = build_template_decl (ded_fn, tparms, /*member*/false);
DECL_ARTIFICIAL (ded_tmpl) = true;
DECL_TEMPLATE_RESULT (ded_tmpl) = ded_fn;
@@ -25085,27 +25119,16 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
tree type = TREE_TYPE (tmpl);
vec<tree,va_gc> *args;
- if (TREE_CODE (init) == TREE_LIST)
+ if (init == NULL_TREE
+ || TREE_CODE (init) == TREE_LIST)
args = make_tree_vector_from_list (init);
- else if (BRACE_ENCLOSED_INITIALIZER_P (init))
+ else if (BRACE_ENCLOSED_INITIALIZER_P (init)
+ && !TYPE_HAS_LIST_CTOR (type)
+ && !is_std_init_list (type))
args = make_tree_vector_from_ctor (init);
else
args = make_tree_vector_single (init);
- if (args->length() == 1)
- {
- /* First try to deduce directly, since we don't have implicitly-declared
- constructors yet. */
- tree parms = build_tree_list (NULL_TREE, type);
- tree tparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
- tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
- int err = type_unification_real (tparms, targs, parms, &(*args)[0],
- 1, /*subr*/false, DEDUCE_CALL,
- LOOKUP_NORMAL, NULL, /*explain*/false);
- if (err == 0)
- return tsubst (type, targs, complain, tmpl);
- }
-
tree dname = dguide_name (tmpl);
tree cands = lookup_qualified_name (CP_DECL_CONTEXT (tmpl), dname,
/*type*/false, /*complain*/false,
@@ -25121,6 +25144,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
type = TREE_TYPE (most_general_template (tmpl));
}
+ bool saw_default = false;
+ bool saw_copy = false;
if (CLASSTYPE_METHOD_VEC (type))
// FIXME cache artificial deduction guides
for (tree fns = CLASSTYPE_CONSTRUCTORS (type); fns; fns = OVL_NEXT (fns))
@@ -25128,21 +25153,30 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
tree fn = OVL_CURRENT (fns);
tree guide = build_deduction_guide (fn, outer_args, complain);
cands = ovl_cons (guide, cands);
+
+ tree parms = FUNCTION_FIRST_USER_PARMTYPE (fn);
+ if (sufficient_parms_p (parms))
+ saw_default = true;
+ if (parms && sufficient_parms_p (TREE_CHAIN (parms)))
+ {
+ tree pt = TREE_VALUE (parms);
+ if (TREE_CODE (pt) == REFERENCE_TYPE
+ && (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (pt), type)))
+ saw_copy = true;
+ }
}
- if (cands == NULL_TREE)
+ if (!saw_default && args->length() == 0)
{
- if (args->length() == 0)
- {
- /* Try tmpl<>. */
- tree t = lookup_template_class (tmpl, NULL_TREE, NULL_TREE,
- NULL_TREE, false, tf_none);
- if (t != error_mark_node)
- return t;
- }
- error ("cannot deduce template arguments for %qT, as it has "
- "no deduction guides or user-declared constructors", type);
- return error_mark_node;
+ tree guide = build_deduction_guide (type, outer_args, complain);
+ cands = ovl_cons (guide, cands);
+ }
+ if (!saw_copy && args->length() == 1)
+ {
+ tree guide = build_deduction_guide (build_reference_type (type),
+ outer_args, complain);
+ cands = ovl_cons (guide, cands);
}
/* Prune explicit deduction guides in copy-initialization context. */
@@ -25225,7 +25259,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
if (init == error_mark_node)
return error_mark_node;
- if (type_dependent_expression_p (init)
+ if (init && type_dependent_expression_p (init)
&& context != adc_unify)
/* Defining a subset of type-dependent expressions that we can deduce
from ahead of time isn't worth the trouble. */
new file mode 100644
@@ -0,0 +1,11 @@
+// { dg-options -std=c++1z }
+
+#include <initializer_list>
+template <class T>
+struct A
+{
+ A (std::initializer_list<T>);
+};
+
+A a{1,2};
+
@@ -15,10 +15,10 @@ template<class T> struct A {
template<class T, int N = remove_ref_t<T>::value> A(T&&, int*) -> A<T>; //#3
A a{1,0}; // uses #1 to deduce A<int> and initializes with #1
-A b{a,0}; // uses #3 (not #2) to deduce A<A<int>&> and initializes with #1
+A b{a,0}; // uses #2 to deduce A<int> and initializes with #2
template <class,class> struct same;
template <class T> struct same<T,T> {};
same<decltype(a),A<int>> s1;
-same<decltype(b),A<A<int>&>> s2;
+same<decltype(b),A<int>> s2;
@@ -3,4 +3,4 @@
template <class T = void> struct A { };
A a{};
-
+A a2;
new file mode 100644
@@ -0,0 +1,22 @@
+// { dg-options -std=c++1z }
+
+template <class T> struct A {
+ A(T); // #1
+ A(const A&); // #2
+};
+
+template <class T> A(T) -> A<T>; // #3
+
+A a (42); // uses #3 to deduce A<int> and initializes with #1
+A b = a; // uses #2 (not #3) to deduce A<int> and initializes with #2; #2 is more specialized
+
+template <class T> A(A<T>) -> A<A<T>>; // #4
+
+A b2 = a; // uses #4 to deduce A<A<int>> and initializes with #1; #4 is as specialized as #2
+
+template <class,class> struct same;
+template <class T> struct same<T,T> {};
+
+same<decltype(a),A<int>> s1;
+same<decltype(b),A<int>> s2;
+same<decltype(b2),A<A<int>>> s3;
new file mode 100644
@@ -0,0 +1,5 @@
+// { dg-options -std=c++1z }
+
+#include <initializer_list>
+
+std::initializer_list l { 1, 2, 3 };
@@ -10,12 +10,13 @@ namespace N
int K;
}
-N::A f2; // { dg-error "1:invalid use of template-name 'N::A' without an argument list" }
+N::A f2; // { dg-error "1:invalid use of template-name 'N::A' without an argument list" "" { target c++14_down } }
+ // { dg-error "deduction|no match" "" { target c++1z } .-1 }
N::INVALID f3; // { dg-error "4:'INVALID' in namespace 'N' does not name a type" }
N::C::INVALID f4; // { dg-error "7:'INVALID' in 'struct N::C' does not name a type" }
N::K f6; // { dg-error "4:'K' in namespace 'N' does not name a type" }
typename N::A f7;
-// { dg-error "13:invalid use of template-name 'N::A' without an argument list" "13" { target *-*-* } 17 }
+// { dg-error "13:invalid use of template-name 'N::A' without an argument list" "13" { target *-*-* } .-1 }
struct B
{
@@ -24,7 +25,7 @@ struct B
N::C::INVALID f4; // { dg-error "9:'INVALID' in 'struct N::C' does not name a type" }
N::K f6; // { dg-error "6:'K' in namespace 'N' does not name a type" }
typename N::A f7;
-// { dg-error "15:invalid use of template-name 'N::A' without an argument list" "15" { target *-*-* } 26 }
+// { dg-error "15:invalid use of template-name 'N::A' without an argument list" "15" { target *-*-* } .-1 }
};
template <int>
@@ -36,5 +37,3 @@ struct C
N::K f6; // { dg-error "6:'K' in namespace 'N' does not name a type" }
typename N::A f7; // { dg-error "15:invalid use of template-name 'N::A' without an argument list" }
};
-
-// { dg-bogus "bogus excess errors in declaration" "bogus excess errors in declaration" { target *-*-* } 17 }
@@ -9,11 +9,11 @@ namespace H {
struct B {};
}
-A a; // { dg-error "template" }
-H::B b; // { dg-error "template" }
+A a; // { dg-error "template|no match" }
+H::B b; // { dg-error "template|no match" }
int main() {
- A a; // { dg-error "template" }
- H::B b; // { dg-error "template" }
+ A a; // { dg-error "template|no match" }
+ H::B b; // { dg-error "template|no match" }
return 0;
}