Commit 853ef4e5 by Jason Merrill Committed by Jason Merrill

Class template argument deduction refinements

	* call.c (joust): Move deduction guide tiebreaker down.
	* decl.c (start_decl_1, cp_finish_decl, grokdeclarator): Allow class
	deduction with no initializer.
	* pt.c (build_deduction_guide): Handle implicit default/copy ctor.
	(do_class_deduction): Use that rather than special case.
	(do_auto_deduction): Handle null initializer.

From-SVN: r245796
parent ad1de652
2017-02-28 Jason Merrill <jason@redhat.com>
Class template argument deduction refinements
* call.c (joust): Move deduction guide tiebreaker down.
* decl.c (start_decl_1, cp_finish_decl, grokdeclarator): Allow class
deduction with no initializer.
* pt.c (build_deduction_guide): Handle implicit default/copy ctor.
(do_class_deduction): Use that rather than special case.
(do_auto_deduction): Handle null initializer.
2017-02-28 Jakub Jelinek <jakub@redhat.com> 2017-02-28 Jakub Jelinek <jakub@redhat.com>
* decl.c (find_decomp_class_base): Use cond ? G_("...") : G_("...") * decl.c (find_decomp_class_base): Use cond ? G_("...") : G_("...")
......
...@@ -9670,18 +9670,6 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, ...@@ -9670,18 +9670,6 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner; 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, /* or, if not that,
F1 is a non-template function and F2 is a template function F1 is a non-template function and F2 is a template function
specialization. */ specialization. */
...@@ -9719,6 +9707,18 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn, ...@@ -9719,6 +9707,18 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
return winner; 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 /* or, if not that, F2 is from a using-declaration, F1 is not, and the
conversion sequences are equivalent. conversion sequences are equivalent.
(proposed in http://lists.isocpp.org/core/2016/10/1142.php) */ (proposed in http://lists.isocpp.org/core/2016/10/1142.php) */
......
...@@ -5238,13 +5238,15 @@ start_decl_1 (tree decl, bool initialized) ...@@ -5238,13 +5238,15 @@ start_decl_1 (tree decl, bool initialized)
else if (aggregate_definition_p && !complete_p) else if (aggregate_definition_p && !complete_p)
{ {
if (type_uses_auto (type)) if (type_uses_auto (type))
gcc_unreachable (); gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (type));
else else
error ("aggregate %q#D has incomplete type and cannot be defined", {
decl); error ("aggregate %q#D has incomplete type and cannot be defined",
/* Change the type so that assemble_variable will give decl);
DECL an rtl we can live with: (mem (const_int 0)). */ /* Change the type so that assemble_variable will give
type = TREE_TYPE (decl) = error_mark_node; 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. /* 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, ...@@ -6816,14 +6818,17 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
return; return;
} }
gcc_unreachable (); gcc_assert (CLASS_PLACEHOLDER_TEMPLATE (auto_node));
} }
d_init = init; d_init = init;
if (TREE_CODE (d_init) == TREE_LIST if (d_init)
&& !CLASS_PLACEHOLDER_TEMPLATE (auto_node)) {
d_init = build_x_compound_expr_from_list (d_init, ELK_INIT, if (TREE_CODE (d_init) == TREE_LIST
tf_warning_or_error); && !CLASS_PLACEHOLDER_TEMPLATE (auto_node))
d_init = resolve_nondeduced_context (d_init, tf_warning_or_error); 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; enum auto_deduction_context adc = adc_variable_type;
if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl)) if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
adc = adc_decomp_type; adc = adc_decomp_type;
...@@ -12323,19 +12328,12 @@ grokdeclarator (const cp_declarator *declarator, ...@@ -12323,19 +12328,12 @@ grokdeclarator (const cp_declarator *declarator,
if (VAR_P (decl) && !initialized) if (VAR_P (decl) && !initialized)
if (tree auto_node = type_uses_auto (type)) if (tree auto_node = type_uses_auto (type))
{ if (!CLASS_PLACEHOLDER_TEMPLATE (auto_node))
location_t loc = declspecs->locations[ds_type_spec]; {
if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) location_t loc = declspecs->locations[ds_type_spec];
{
error_at (loc, "invalid use of template-name %qE without an "
"argument list", tmpl);
inform (loc, "class template argument deduction "
"requires an initializer");
}
else
error_at (loc, "declaration of %q#D has no initializer", decl); 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) if (storage_class == sc_extern && initialized && !funcdef_flag)
{ {
......
// { 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 { ...@@ -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 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 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,class> struct same;
template <class T> struct same<T,T> {}; template <class T> struct same<T,T> {};
same<decltype(a),A<int>> s1; same<decltype(a),A<int>> s1;
same<decltype(b),A<A<int>&>> s2; same<decltype(b),A<int>> s2;
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
template <class T = void> struct A { }; template <class T = void> struct A { };
A a{}; A a{};
A a2;
// { 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;
// { dg-options -std=c++1z }
#include <initializer_list>
std::initializer_list l { 1, 2, 3 };
...@@ -10,12 +10,13 @@ namespace N ...@@ -10,12 +10,13 @@ namespace N
int K; 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::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::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" } N::K f6; // { dg-error "4:'K' in namespace 'N' does not name a type" }
typename N::A f7; 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 struct B
{ {
...@@ -24,7 +25,7 @@ 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::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" } N::K f6; // { dg-error "6:'K' in namespace 'N' does not name a type" }
typename N::A f7; 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> template <int>
...@@ -36,5 +37,3 @@ struct C ...@@ -36,5 +37,3 @@ struct C
N::K f6; // { dg-error "6:'K' in namespace 'N' 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" } 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 { ...@@ -9,11 +9,11 @@ namespace H {
struct B {}; struct B {};
} }
A a; // { dg-error "template" } A a; // { dg-error "template|no match" }
H::B b; // { dg-error "template" } H::B b; // { dg-error "template|no match" }
int main() { int main() {
A a; // { dg-error "template" } A a; // { dg-error "template|no match" }
H::B b; // { dg-error "template" } H::B b; // { dg-error "template|no match" }
return 0; return 0;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment