On Wed, Oct 28, 2020 at 03:18:18PM -0400, Jason Merrill via Gcc-patches wrote: > On 10/16/20 11:31 AM, Marek Polacek wrote: > > In this testcase we weren't able to deduce b's type: > > > > template<typename T> void Task() { } > > auto b = { &Task<int> }; > > > > because resolve_nondeduced_context doesn't iterate on the {}'s elements. > > So make sure to look into {} too. We don't need to handle nested {} > > here. > > Why don't we? That rationale should be in a comment.
I don't think we can deduce from a nested init-list; none of the following work: #include <initializer_list> template<typename T> void fn() {}; struct X { } x; auto a = { { fn<int> } }; // unable to deduce std::initializer_list<auto> from {{fn<int>}} auto b = { { x, x } }; // unable to deduce std::initializer_list<auto> from {{x, x}} auto c = { { 1 } }; // unable to deduce std::initializer_list<auto> from {{1}} clang++ says "cannot deduce actual type for variable 'a' with type 'auto' from initializer list". I've added a comment: -- >8 -- In this testcase we weren't able to deduce b's type: template<typename T> void Task() { } auto b = { &Task<int> }; because resolve_nondeduced_context doesn't iterate on the {}'s elements. So make sure to look into {} too. We don't need to handle nested {} here. We could either tweak resolve_nondeduced_context to handle CONSTRUCTORs or add a _ctor version, but then resolve_nondeduced_context_or_error would need some changes too -- it'd have to check the result of a call to r_n_c for each element. gcc/cp/ChangeLog: PR c++/93107 * pt.c (do_auto_deduction): Call resolve_nondeduced_context for the elements of a { } list. gcc/testsuite/ChangeLog: PR c++/93107 * g++.dg/cpp0x/initlist-deduce3.C: New test. --- gcc/cp/pt.c | 8 ++++++- gcc/testsuite/g++.dg/cpp0x/initlist-deduce3.C | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-deduce3.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 531554d702d..b569644514c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29241,7 +29241,13 @@ do_auto_deduction (tree type, tree init, tree auto_node, if (type == error_mark_node) return error_mark_node; - init = resolve_nondeduced_context (init, complain); + if (BRACE_ENCLOSED_INITIALIZER_P (init)) + /* We don't recurse here because we can't deduce from a nested + initializer_list. */ + for (constructor_elt &elt : *CONSTRUCTOR_ELTS (init)) + elt.value = resolve_nondeduced_context (elt.value, complain); + else + init = resolve_nondeduced_context (init, complain); if (context == adc_decomp_type && auto_node == type diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-deduce3.C b/gcc/testsuite/g++.dg/cpp0x/initlist-deduce3.C new file mode 100644 index 00000000000..b8417d7bf0c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-deduce3.C @@ -0,0 +1,22 @@ +// PR c++/93107 +// { dg-do compile { target c++11 } } + +using size_t = decltype(sizeof 0); + +namespace std { + template<typename T> struct initializer_list { + const T *ptr; + size_t n; + initializer_list(const T*, size_t); + }; +} + +template<typename T> +void Task() {} + +auto a = &Task<int>; +auto b = { &Task<int> }; +auto e{ &Task<int> }; +auto f = { &Task<int>, &Task<int> }; +std::initializer_list<void(*)()> c = { &Task<int> }; +auto d = { static_cast<void(*)()>(&Task<int>) }; base-commit: 79991e2348a864ace6ea2bf108a7502862f1129f -- 2.28.0