C++17 changes how we describe prvalues so that they express initialization of an object to be named later, rather than objects themselves. This happens to match the front end's use of TARGET_EXPR pretty closely, so I think we don't need to do much more than disable the code that forces us to copy a TARGET_EXPR into another TARGET_EXPR.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 054719b1c1f71236999ea4082cb3207c42cf883c Author: Jason Merrill <ja...@redhat.com> Date: Wed Oct 5 12:59:30 2016 -0400 Implement P0135R1, Guaranteed copy elision. * c-opts.c (set_std_cxx1z): Set flag_elide_constructors to 2. * cvt.c (ocp_convert): Don't re-copy a TARGET_EXPR in C++17. diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index c5a699d..977348f1 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -1579,6 +1579,7 @@ set_std_cxx1z (int iso) flag_isoc94 = 1; flag_isoc99 = 1; flag_isoc11 = 1; + flag_elide_constructors = 2; cxx_dialect = cxx1z; lang_hooks.name = "GNU C++14"; /* Pretend C++14 till standarization. */ } diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 2f5f15a..4de9745 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -693,8 +693,11 @@ ocp_convert (tree type, tree expr, int convtype, int flags, if (error_operand_p (e)) return error_mark_node; - if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP)) - /* We need a new temporary; don't take this shortcut. */; + if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP) + && !(flag_elide_constructors >= 2 + && TREE_CODE (e) == TARGET_EXPR)) + /* We need a new temporary; don't take this shortcut. But in C++17, don't + force a temporary if we already have one. */; else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e))) { if (same_type_p (type, TREE_TYPE (e))) diff --git a/gcc/testsuite/g++.dg/cpp1z/elide1.C b/gcc/testsuite/g++.dg/cpp1z/elide1.C new file mode 100644 index 0000000..a0538bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/elide1.C @@ -0,0 +1,16 @@ +// { dg-options -std=c++1z } + +struct A +{ + A(); + A(const A&) = delete; +}; + +bool b; +A a = A(); +A a1 = b ? A() : A(); +A a2 = (42, A()); + +A f(); +A a3 = f(); +A a4 = b ? A() : f();