[PATCH] c++: Handle std::construct_at on automatic vars during constant evaluation [PR97195]

Jakub Jelinek jakub@redhat.com
Wed Sep 30 08:01:36 GMT 2020


Hi!

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.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2020-09-30  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.

--- gcc/cp/constexpr.c.jj	2020-09-22 21:08:01.993199681 +0200
+++ gcc/cp/constexpr.c	2020-09-29 18:37:09.517051012 +0200
@@ -2342,9 +2342,10 @@ cxx_eval_call_expression (const constexp
 	      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;
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C.jj	2020-09-29 18:40:52.834785887 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C	2020-09-29 18:40:47.707860852 +0200
@@ -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 ();

	Jakub



More information about the Gcc-patches mailing list