On 21 March 2017 at 01:44, Jason Merrill <ja...@redhat.com> wrote: >> It looks strange to me. Why not change the definition of check_new instead >> of changing the condition that uses it? > > Agreed. Also, let's factor the new tests out into a function, say > non_allocating_fn_p.
This also conveniently let's me provide a ChangeLog that reads like a Real Front-End Developer would've written it. :) New tests re-tested on Linux-x64, running full suite on Linux-PPC64. 2017-03-21 Ville Voutilainen <ville.voutilai...@gmail.com> gcc/ PR c++/35878 * cp/init.c (non_allocating_fn_p): New. (build_new_1): Call it. testsuite/ PR c++/35878 * g++.dg/init/pr35878_1.C: New. * g++.dg/init/pr35878_2.C: Likewise. * g++.dg/init/pr35878_3.C: Likewise.
diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 8bfcbde..dc5a5f7 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2693,6 +2693,21 @@ malloc_alignment () return MAX (max_align_t_align(), MALLOC_ABI_ALIGNMENT); } +/* Determine whether an allocation function is a namespace-scope + non-replaceable placement new function. See DR 1748. + TODO: Enable in all standard modes. */ +static bool non_allocating_fn_p (tree alloc_fn) +{ + if ((cxx_dialect > cxx14) && DECL_NAMESPACE_SCOPE_P (alloc_fn)) + { + tree first_arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn))); + if ((TREE_VALUE (first_arg) == ptr_type_node) + && TREE_CHAIN (first_arg) == void_list_node) + return false; + } + return true; +} + /* Generate code for a new-expression, including calling the "operator new" function, initializing the object, and, if an exception occurs during construction, cleaning up. The arguments are as for @@ -3171,7 +3186,8 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, So check for a null exception spec on the op new we just called. */ nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn)); - check_new = (flag_check_new || nothrow); + check_new = flag_check_new + || (nothrow && non_allocating_fn_p (alloc_fn)); if (cookie_size) { diff --git a/gcc/testsuite/g++.dg/init/pr35878_1.C b/gcc/testsuite/g++.dg/init/pr35878_1.C new file mode 100644 index 0000000..b45c009 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/pr35878_1.C @@ -0,0 +1,21 @@ +// { dg-options "-O2 --std=gnu++11" } +// { dg-do compile } +// { dg-final { scan-assembler "test.*%rdi, %rdi" { target i?86-*-* x86_64-*-* } } } +#include <new> +#include <utility> + +struct s1{ + int a; + int b; + int c; +}; + +void f1 (s1 * v, s1&& s) +{ + new (v) s1(std::move(s)); +} + +void f2 (s1 * v, s1&& s) +{ + *v = std::move(s); +} diff --git a/gcc/testsuite/g++.dg/init/pr35878_2.C b/gcc/testsuite/g++.dg/init/pr35878_2.C new file mode 100644 index 0000000..0664494 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/pr35878_2.C @@ -0,0 +1,21 @@ +// { dg-options "-O2 --std=gnu++17 -fcheck-new" } +// { dg-do compile } +// { dg-final { scan-assembler "test.*%rdi, %rdi" { target i?86-*-* x86_64-*-* } } } +#include <new> +#include <utility> + +struct s1{ + int a; + int b; + int c; +}; + +void f1 (s1 * v, s1&& s) +{ + new (v) s1(std::move(s)); +} + +void f2 (s1 * v, s1&& s) +{ + *v = std::move(s); +} diff --git a/gcc/testsuite/g++.dg/init/pr35878_3.C b/gcc/testsuite/g++.dg/init/pr35878_3.C new file mode 100644 index 0000000..8a5614f --- /dev/null +++ b/gcc/testsuite/g++.dg/init/pr35878_3.C @@ -0,0 +1,21 @@ +// { dg-options "-O2 --std=gnu++17" } +// { dg-do compile } +// { dg-final { scan-assembler-not "test.*%rdi, %rdi" { target i?86-*-* x86_64-*-* } } } +#include <new> +#include <utility> + +struct s1{ + int a; + int b; + int c; +}; + +void f1 (s1 * v, s1&& s) +{ + new (v) s1(std::move(s)); +} + +void f2 (s1 * v, s1&& s) +{ + *v = std::move(s); +}