aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-10-01 11:16:44 +0200
committerJakub Jelinek <jakub@redhat.com>2020-10-01 11:16:44 +0200
commit2805fcb32660bc0cdcd5ba54310f1f02651e039f (patch)
tree365c7a4a2491d674e8847fd175ceda5d9ee7beb3
parent85516b71730d8f9401c34407ac3fadf5f1ebfc4e (diff)
downloadgcc-2805fcb32660bc0cdcd5ba54310f1f02651e039f.zip
gcc-2805fcb32660bc0cdcd5ba54310f1f02651e039f.tar.gz
gcc-2805fcb32660bc0cdcd5ba54310f1f02651e039f.tar.bz2
c++: Handle std::construct_at on automatic vars during constant evaluation [PR97195]
As mentioned in the PR, we only support due to a bug in constant expressions std::construct_at on non-automatic variables, because we VERIFY_CONSTANT the second argument of placement new, which fails verification if it is an address of an automatic variable. The following patch fixes it by not performing that verification, the placement new evaluation later on will verify it after it is dereferenced. 2020-10-01 Jakub Jelinek <jakub@redhat.com> PR c++/97195 * constexpr.c (cxx_eval_call_expression): Don't VERIFY_CONSTANT the second argument. * g++.dg/cpp2a/constexpr-new14.C: New test.
-rw-r--r--gcc/cp/constexpr.c3
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C73
2 files changed, 75 insertions, 1 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index dacce58..a118f8a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2342,9 +2342,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
tree arg = CALL_EXPR_ARG (t, i);
arg = cxx_eval_constant_expression (ctx, arg, false,
non_constant_p, overflow_p);
- VERIFY_CONSTANT (arg);
if (i == 1)
arg1 = arg;
+ else
+ VERIFY_CONSTANT (arg);
}
gcc_assert (arg1);
return arg1;
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C
new file mode 100644
index 0000000..fd6f607
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C
@@ -0,0 +1,73 @@
+// PR c++/97195
+// { dg-do compile { target c++20 } }
+
+namespace std
+{
+ typedef __SIZE_TYPE__ size_t;
+
+ template <typename T>
+ struct allocator
+ {
+ constexpr allocator () noexcept {}
+
+ constexpr T *allocate (size_t n)
+ { return static_cast<T *> (::operator new (n * sizeof(T))); }
+
+ constexpr void
+ deallocate (T *p, size_t n)
+ { ::operator delete (p); }
+ };
+
+ template <typename T, typename U = T &&>
+ U __declval (int);
+ template <typename T>
+ T __declval (long);
+ template <typename T>
+ auto declval () noexcept -> decltype (__declval<T> (0));
+
+ template <typename T>
+ struct remove_reference
+ { typedef T type; };
+ template <typename T>
+ struct remove_reference<T &>
+ { typedef T type; };
+ template <typename T>
+ struct remove_reference<T &&>
+ { typedef T type; };
+
+ template <typename T>
+ constexpr T &&
+ forward (typename std::remove_reference<T>::type &t) noexcept
+ { return static_cast<T&&> (t); }
+
+ template<typename T>
+ constexpr T &&
+ forward (typename std::remove_reference<T>::type &&t) noexcept
+ { return static_cast<T&&> (t); }
+
+ template <typename T, typename... A>
+ constexpr auto
+ construct_at (T *l, A &&... a)
+ noexcept (noexcept (::new ((void *) 0) T (std::declval<A> ()...)))
+ -> decltype (::new ((void *) 0) T (std::declval<A> ()...))
+ { return ::new ((void *) l) T (std::forward<A> (a)...); }
+
+ template <typename T>
+ constexpr inline void
+ destroy_at (T *l)
+ { l->~T (); }
+}
+
+inline void *operator new (std::size_t, void *p) noexcept
+{ return p; }
+
+constexpr bool
+foo ()
+{
+ int a = 5;
+ int *p = std::construct_at (&a, -1);
+ if (p[0] != -1)
+ throw 1;
+ return true;
+}
+constexpr bool b = foo ();