The C++17 copy elision code in build_special_member_call was creating a temporary and then eliding the copy directly, but creating that temporary meant building a cleanup, which requires the destructor to be callable. And we shouldn't require that when building a new-expression. Fixed by using the new tf_no_cleanup flag.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit f41a463a7fba438a5127dc15e1043f287a16e9ad Author: Jason Merrill <ja...@redhat.com> Date: Sun Feb 19 20:41:23 2017 -0800 PR c++/78139 - destructor needed by new-expression * call.c (build_special_member_call): Use tf_no_cleanup. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index d6d3a8f..93fae0d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8356,9 +8356,15 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args, /* FIXME P0135 doesn't say how to handle direct initialization from a type with a suitable conversion operator. Let's handle it like copy-initialization, but allowing explict conversions. */ + tsubst_flags_t sub_complain = tf_warning; + if (!is_dummy_object (instance)) + /* If we're using this to initialize a non-temporary object, don't + require the destructor to be accessible. */ + sub_complain |= tf_no_cleanup; if (!reference_related_p (class_type, TREE_TYPE (arg))) arg = perform_implicit_conversion_flags (class_type, arg, - tf_warning, flags); + sub_complain, + flags); if ((TREE_CODE (arg) == TARGET_EXPR || TREE_CODE (arg) == CONSTRUCTOR) && (same_type_ignoring_top_level_qualifiers_p diff --git a/gcc/testsuite/g++.dg/init/new48.C b/gcc/testsuite/g++.dg/init/new48.C new file mode 100644 index 0000000..528a582 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/new48.C @@ -0,0 +1,18 @@ +// PR c++/78139 + +struct A +{ + A(int); +private: + ~A(); +}; + +struct B +{ + B(void*); +}; + +int main() +{ + B(new A(42)); +}