diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index a80372c89914454da944809c3cf539cd69881aba..97c3ecb7d1616c0a3f566d62eb03615e1b9098ea 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -1091,7 +1091,7 @@ c_cpp_builtins (cpp_reader *pfile)
       if (cxx_dialect > cxx23)
 	{
 	  /* Set feature test macros for C++26.  */
-	  cpp_define (pfile, "__cpp_constexpr=202306L");
+	  cpp_define (pfile, "__cpp_constexpr=202406L");
 	  cpp_define (pfile, "__cpp_static_assert=202306L");
 	  cpp_define (pfile, "__cpp_placeholder_variables=202306L");
 	  cpp_define (pfile, "__cpp_structured_bindings=202403L");
diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new1.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new1.C
new file mode 100644
index 0000000000000000000000000000000000000000..131b718efa5b2e3cf1b8479559f18fd055542135
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new1.C
@@ -0,0 +1,66 @@
+// C++26 P2747R2 - constexpr placement new
+// { dg-do compile { target c++26 } }
+
+#include "../cpp2a/construct_at.h"
+
+struct S {
+  constexpr S () : a (42), b (43) {}
+  constexpr S (int c, int d) : a (c), b (d) {}
+  int a, b;
+};
+struct T {
+  int a, b;
+};
+
+constexpr bool
+foo ()
+{
+  std::allocator<int> a;
+  auto b = a.allocate (3);
+  ::new (b) int ();
+  ::new (b + 1) int (1);
+  ::new (b + 2) int {2};
+  if (b[0] != 0 || b[1] != 1 || b[2] != 2)
+    return false;
+  a.deallocate (b, 3);
+  std::allocator<S> c;
+  auto d = c.allocate (4);
+  ::new (d) S;
+  ::new (d + 1) S ();
+  ::new (d + 2) S (7, 8);
+  ::new (d + 3) S { 9, 10 };
+  if (d[0].a != 42 || d[0].b != 43
+      || d[1].a != 42 || d[1].b != 43
+      || d[2].a != 7 || d[2].b != 8
+      || d[3].a != 9 || d[3].b != 10)
+    return false;
+  d[0].~S ();
+  d[1].~S ();
+  d[2].~S ();
+  d[3].~S ();
+  c.deallocate (d, 4);
+  std::allocator<T> e;
+  auto f = e.allocate (3);
+  ::new (f) T ();
+  ::new (f + 1) T (7, 8);
+  ::new (f + 2) T { .a = 9, .b = 10 };
+  if (f[0].a != 0 || f[0].b != 0
+      || f[1].a != 7 || f[1].b != 8
+      || f[2].a != 9 || f[2].b != 10)
+    return false;
+  f[0].~T ();
+  f[1].~T ();
+  f[2].~T ();
+  e.deallocate (f, 3);
+  auto g = a.allocate (3);
+  new (g) int[] {1, 2, 3};
+  if (g[0] != 1 || g[1] != 2 || g[2] != 3)
+    return false;
+  new (g) int[] {4, 5};
+  if (g[0] != 4 || g[1] != 5)
+    return false;
+  a.deallocate (g, 3);
+  return true;
+}
+
+static_assert (foo ());
diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new2.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new2.C
new file mode 100644
index 0000000000000000000000000000000000000000..e333185425376696302372f0a1b30e630a07dd3b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new2.C
@@ -0,0 +1,73 @@
+// C++26 P2747R2 - constexpr placement new
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+#include <new>
+
+#ifndef __cpp_lib_constexpr_new
+# error "__cpp_lib_constexpr_new"
+#elif __cpp_lib_constexpr_new < 202406L
+# error "__cpp_lib_constexpr_new < 202406"
+#endif
+
+struct S {
+  constexpr S () : a (42), b (43) {}
+  constexpr S (int c, int d) : a (c), b (d) {}
+  int a, b;
+};
+struct T {
+  int a, b;
+};
+
+constexpr bool
+foo ()
+{
+  std::allocator<int> a;
+  auto b = a.allocate (3);
+  ::new (b) int ();
+  ::new (b + 1) int (1);
+  ::new (b + 2) int {2};
+  if (b[0] != 0 || b[1] != 1 || b[2] != 2)
+    return false;
+  a.deallocate (b, 3);
+  std::allocator<S> c;
+  auto d = c.allocate (4);
+  ::new (d) S;
+  ::new (d + 1) S ();
+  ::new (d + 2) S (7, 8);
+  ::new (d + 3) S { 9, 10 };
+  if (d[0].a != 42 || d[0].b != 43
+      || d[1].a != 42 || d[1].b != 43
+      || d[2].a != 7 || d[2].b != 8
+      || d[3].a != 9 || d[3].b != 10)
+    return false;
+  d[0].~S ();
+  d[1].~S ();
+  d[2].~S ();
+  d[3].~S ();
+  c.deallocate (d, 4);
+  std::allocator<T> e;
+  auto f = e.allocate (3);
+  ::new (f) T ();
+  ::new (f + 1) T (7, 8);
+  ::new (f + 2) T { .a = 9, .b = 10 };
+  if (f[0].a != 0 || f[0].b != 0
+      || f[1].a != 7 || f[1].b != 8
+      || f[2].a != 9 || f[2].b != 10)
+    return false;
+  f[0].~T ();
+  f[1].~T ();
+  f[2].~T ();
+  e.deallocate (f, 3);
+  auto g = a.allocate (3);
+  new (g) int[] {1, 2, 3};
+  if (g[0] != 1 || g[1] != 2 || g[2] != 3)
+    return false;
+  new (g) int[] {4, 5};
+  if (g[0] != 4 || g[1] != 5)
+    return false;
+  a.deallocate (g, 3);
+  return true;
+}
+
+static_assert (foo ());
diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C
new file mode 100644
index 0000000000000000000000000000000000000000..6a06a6e6f32e5dc8cf4ee3d7ae4b43140067035f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C
@@ -0,0 +1,47 @@
+// C++26 P2747R2 - constexpr placement new
+// { dg-do compile { target c++26 } }
+
+#include "../cpp2a/construct_at.h"
+
+struct S {
+  constexpr S () : a (42), b (43) {}
+  constexpr S (int c, int d) : a (c), b (d) {}
+  int a, b;
+};
+struct T {
+  int a, b;
+};
+
+constexpr bool
+foo ()
+{
+  std::allocator<int> a;
+  auto b = a.allocate (3);
+  new (b + 1) int[] {2, 3};	// { dg-error "" "" { xfail *-*-* } }
+  a.deallocate (b, 3);
+  return true;
+}
+
+constexpr bool
+bar ()
+{
+  std::allocator<int> a;
+  auto b = a.allocate (3);
+  new (b) int[] {1, 2, 3, 4};	// { dg-error "array subscript value '3' is outside the bounds of array 'heap ' of type 'int \\\[3\\\]'" }
+  a.deallocate (b, 3);
+  return true;
+}
+
+constexpr bool
+baz ()
+{
+  std::allocator<int> a;
+  auto b = a.allocate (2);
+  new (b) long (42);		// { dg-error "accessing value of 'heap ' through a 'long int' glvalue in a constant expression" }
+  a.deallocate (b, 2);
+  return true;
+}
+
+constexpr bool a = foo ();
+constexpr bool b = bar ();
+constexpr bool c = baz ();
diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
index 8a5fd64d39604b03af738ad9d5f3b826c04cdf51..82be39c996f247576e7f0ac3357bf1b374870dd2 100644
--- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
+++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
@@ -134,8 +134,8 @@
 
 #ifndef __cpp_constexpr
 #  error "__cpp_constexpr"
-#elif __cpp_constexpr != 202306L
-#  error "__cpp_constexpr != 202306L"
+#elif __cpp_constexpr != 202406L
+#  error "__cpp_constexpr != 202406L"
 #endif
 
 #ifndef __cpp_decltype_auto
diff --git a/gcc/testsuite/g++.dg/cpp2a/construct_at.h b/gcc/testsuite/g++.dg/cpp2a/construct_at.h
index 27e92cbb28c5bb84a7f21b453a3014e1e1acb090..ed6165610424fc5e289dec20aa59273ede952253 100644
--- a/gcc/testsuite/g++.dg/cpp2a/construct_at.h
+++ b/gcc/testsuite/g++.dg/cpp2a/construct_at.h
@@ -58,5 +58,18 @@ namespace std
   { l->~T (); }
 }
 
-inline void *operator new (std::size_t, void *p) noexcept
+#if __cpp_constexpr >= 202406L
+constexpr
+#else
+inline
+#endif
+void *operator new (std::size_t, void *p) noexcept
+{ return p; }
+
+#if __cpp_constexpr >= 202406L
+constexpr
+#else
+inline
+#endif
+void *operator new[] (std::size_t, void *p) noexcept
 { return p; }
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index ee0a9e45c441d272ed925bdaa3fc3da35db071ab..6791c6f6f93678ae473648361b6a161db883705d 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1838,6 +1838,15 @@ ftms = {
   };
 };
 
+ftms = {
+  name = constexpr_new;
+  values = {
+    v = 202406;
+    cxxmin = 26;
+    extra_cond = "__cpp_constexpr >= 202406L";
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index cee497d7443fa2eafde5975696e996d81c0d0533..0b78cb94ecc97dda9ffced2b8fdb1b498e71ea9a 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2033,4 +2033,14 @@
 #endif /* !defined(__cpp_lib_ranges_concat) && defined(__glibcxx_want_ranges_concat) */
 #undef __glibcxx_want_ranges_concat
 
+#if !defined(__cpp_lib_constexpr_new)
+# if (__cplusplus >  202302L) && (__cpp_constexpr >= 202406L)
+#  define __glibcxx_constexpr_new 202406L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_new)
+#   define __cpp_lib_constexpr_new 202406L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_constexpr_new) && defined(__glibcxx_want_constexpr_new) */
+#undef __glibcxx_want_constexpr_new
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new
index 8b07150fb94941bd29a334cfa178c922255ea394..2e2038e1a82ccbcd2e73becedeb1665b6fb660e8 100644
--- a/libstdc++-v3/libsupc++/new
+++ b/libstdc++-v3/libsupc++/new
@@ -43,6 +43,7 @@
 #define __glibcxx_want_launder
 #define __glibcxx_want_hardware_interference_size
 #define __glibcxx_want_destroying_delete
+#define __glibcxx_want_constexpr_new
 #include <bits/version.h>
 
 #pragma GCC visibility push(default)
@@ -175,12 +176,22 @@ void operator delete[](void*, std::size_t, std::align_val_t)
 #endif // __cpp_sized_deallocation
 #endif // __cpp_aligned_new
 
+#if __cpp_lib_constexpr_new >= 202406L
+# define _GLIBCXX_PLACEMENT_CONSTEXPR constexpr
+#else
+# define _GLIBCXX_PLACEMENT_CONSTEXPR inline
+#endif
+
 // Default placement versions of operator new.
-_GLIBCXX_NODISCARD inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
+_GLIBCXX_NODISCARD _GLIBCXX_PLACEMENT_CONSTEXPR
+void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
 { return __p; }
-_GLIBCXX_NODISCARD inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
+_GLIBCXX_NODISCARD _GLIBCXX_PLACEMENT_CONSTEXPR
+void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
 { return __p; }
 
+#undef _GLIBCXX_PLACEMENT_CONSTEXPR
+
 // Default placement versions of operator delete.
 inline void operator delete  (void*, void*) _GLIBCXX_USE_NOEXCEPT { }
 inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { }