On Tue, Oct 4, 2016 at 4:42 PM, Jason Merrill <ja...@redhat.com> wrote: > C++17 adds the ability to omit the template arguments for a class > template when declaring a variable with an initializer, much like auto > but supporting a wider variety of initialization. This is intended to > replace functions like make_tuple. > > Tested x86_64-pc-linux-gnu, applying to trunk.
A few tweaks...
commit 492ab670ad2c1ddc11c59bb77220c5a996b0f87a Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Wed Oct 5 01:24:38 2016 +0000 PR c++/77852 - class deduction from list-init * pt.c (do_class_deduction): Handle list-initialization. (do_auto_deduction): Call it sooner. (build_deduction_guide): Use tsubst_arg_types. (rewrite_template_parm): Don't copy_type. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@240765 138bc75d-0d04-0410-961f-82ee72b054a4 diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 491c637..2fce793 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -12612,6 +12612,18 @@ make_tree_vector_from_list (tree list) return ret; } +/* Get a new tree vector of the values of a CONSTRUCTOR. */ + +vec<tree, va_gc> * +make_tree_vector_from_ctor (tree ctor) +{ + vec<tree,va_gc> *ret = make_tree_vector (); + vec_safe_reserve (ret, CONSTRUCTOR_NELTS (ctor)); + for (unsigned i = 0; i < CONSTRUCTOR_NELTS (ctor); ++i) + ret->quick_push (CONSTRUCTOR_ELT (ctor, i)->value); + return ret; +} + /* Get a new tree vector which is a copy of an existing one. */ vec<tree, va_gc> * diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index c88619b..28aebec 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1111,6 +1111,7 @@ extern vec<tree, va_gc> *make_tree_vector (void); extern void release_tree_vector (vec<tree, va_gc> *); extern vec<tree, va_gc> *make_tree_vector_single (tree); extern vec<tree, va_gc> *make_tree_vector_from_list (tree); +extern vec<tree, va_gc> *make_tree_vector_from_ctor (tree); extern vec<tree, va_gc> *make_tree_vector_copy (const vec<tree, va_gc> *); /* Used for communication between c_common_type_for_mode and diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f923666..e6b1368 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -24178,7 +24178,7 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level, if (TREE_CODE (olddecl) == TYPE_DECL || TREE_CODE (olddecl) == TEMPLATE_DECL) { - newtype = copy_type (TREE_TYPE (olddecl)); + newtype = cxx_make_type (TREE_CODE (TREE_TYPE (olddecl))); TYPE_MAIN_VARIANT (newtype) = newtype; } else @@ -24340,7 +24340,8 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) /* Now we have a final set of template parms to substitute into the function signature. */ targs = template_parms_to_args (tparms); - fparms = tsubst (fparms, tsubst_args, complain, ctor); + 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); @@ -24376,6 +24377,8 @@ do_class_deduction (tree tmpl, tree init, tsubst_flags_t complain) vec<tree,va_gc> *args; if (TREE_CODE (init) == TREE_LIST) args = make_tree_vector_from_list (init); + else if (BRACE_ENCLOSED_INITIALIZER_P (init)) + args = make_tree_vector_from_ctor (init); else args = make_tree_vector_single (init); @@ -24465,6 +24468,10 @@ do_auto_deduction (tree type, tree init, tree auto_node, from ahead of time isn't worth the trouble. */ return type; + if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) + /* C++17 class template argument deduction. */ + return do_class_deduction (tmpl, init, complain); + /* [dcl.spec.auto]: Obtain P from T by replacing the occurrences of auto with either a new invented type template parameter U or, if the initializer is a braced-init-list (8.5.4), with @@ -24510,9 +24517,6 @@ do_auto_deduction (tree type, tree init, tree auto_node, return error_mark_node; } } - else if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) - /* C++17 class template argument deduction. */ - return do_class_deduction (tmpl, init, complain); else { tree parms = build_tree_list (NULL_TREE, type); diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction14.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction14.C new file mode 100644 index 0000000..1c7e34e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction14.C @@ -0,0 +1,15 @@ +// { dg-options -std=c++1z } + +#include <vector> + +template<class T> struct container { + container(T t) {} + template<class Iter> container(Iter beg, Iter end); +}; +template<class Iter> +container(Iter b, Iter e) // { dg-message "iterator_traits.int" } + -> container<typename std::iterator_traits<Iter>::value_type>; +std::vector<double> v = { /* ... */ }; +container c(7); // OK, deduces int for T +auto d = container(v.begin(), v.end()); // OK, deduces double for T +container e{5, 6}; // { dg-error "" } int is not an iterator diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction15.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction15.C new file mode 100644 index 0000000..72ed478 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction15.C @@ -0,0 +1,9 @@ +// { dg-options -std=c++1z } + +#include <utility> + +int main() +{ + std::pair x{42, 666}; +} + diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction16.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction16.C new file mode 100644 index 0000000..b32869f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction16.C @@ -0,0 +1,9 @@ +// { dg-options -std=c++1z } + +template <class... T> +struct A +{ + template <class...Us> A(Us&&...); +}; + +A a(1,2);