r291480 - Allow constexpr construction of subobjects unconditionally, not just in C++14.

David L. Jones via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 9 13:38:08 PST 2017


Author: dlj
Date: Mon Jan  9 15:38:07 2017
New Revision: 291480

URL: http://llvm.org/viewvc/llvm-project?rev=291480&view=rev
Log:
Allow constexpr construction of subobjects unconditionally, not just in C++14.

Summary:
Per https://wg21.link/CWG1677, the C++11 standard did not clarify that constant
initialization of an object allowed constexpr brace-or-equal initialization of
subobjects:

  struct foo_t { union { int i; volatile int j; } u; };

  __attribute__((__require_constant_initialization__))
  static const foo_t x = {{0}};

Because foo_t::u has a volatile member, the initializer for x fails. However,
there is really no good reason, because this:

  union foo_u { int i; volatile int j; };
  __attribute__((__require_constant_initialization__))
  static const foo_u x = {0};

does have a constant initializer.

(This was triggered by musl's pthread_mutex_t type when building under C++11.)

Reviewers: rsmith

Subscribers: EricWF, cfe-commits

Differential Revision: https://reviews.llvm.org/D28427

Added:
    cfe/trunk/test/CXX/basic/basic.start/basic.start.init/p2.cpp
Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/CodeGenCXX/global-array-destruction.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=291480&r1=291479&r2=291480&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Jan  9 15:38:07 2017
@@ -1627,8 +1627,17 @@ static bool CheckLiteralType(EvalInfo &I
   // C++1y: A constant initializer for an object o [...] may also invoke
   // constexpr constructors for o and its subobjects even if those objects
   // are of non-literal class types.
-  if (Info.getLangOpts().CPlusPlus14 && This &&
-      Info.EvaluatingDecl == This->getLValueBase())
+  //
+  // C++11 missed this detail for aggregates, so classes like this:
+  //   struct foo_t { union { int i; volatile int j; } u; };
+  // are not (obviously) initializable like so:
+  //   __attribute__((__require_constant_initialization__))
+  //   static const foo_t x = {{0}};
+  // because "i" is a subobject with non-literal initialization (due to the
+  // volatile member of the union). See:
+  //   http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
+  // Therefore, we use the C++1y behavior.
+  if (This && Info.EvaluatingDecl == This->getLValueBase())
     return true;
 
   // Prvalue constant expressions must be of literal types.

Added: cfe/trunk/test/CXX/basic/basic.start/basic.start.init/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.start/basic.start.init/p2.cpp?rev=291480&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.start/basic.start.init/p2.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.start/basic.start.init/p2.cpp Mon Jan  9 15:38:07 2017
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -verify %s -pedantic-errors -std=c++11
+// RUN: %clang_cc1 -verify %s -pedantic-errors -std=c++14
+// expected-no-diagnostics
+
+struct foo_t {
+  union {
+    int i;
+    volatile int j;
+  } u;
+};
+
+__attribute__((__require_constant_initialization__))
+static const foo_t x = {{0}};
+
+union foo_u {
+  int i;
+  volatile int j;
+};
+
+__attribute__((__require_constant_initialization__))
+static const foo_u y = {0};

Modified: cfe/trunk/test/CodeGenCXX/global-array-destruction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/global-array-destruction.cpp?rev=291480&r1=291479&r2=291480&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/global-array-destruction.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/global-array-destruction.cpp Mon Jan  9 15:38:07 2017
@@ -39,7 +39,7 @@ struct T {
 T t[2][3] = { 1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10, 11.0, 12 };
 
 // CHECK: call {{.*}} @__cxa_atexit
-// CHECK: getelementptr inbounds ({{.*}} bitcast {{.*}}* @t to %struct.T*), i64 6
+// CHECK: getelementptr inbounds ({{.*}} getelementptr inbounds ([2 x [3 x {{.*}}]], [2 x [3 x {{.*}}]]* @t, i32 0, i32 0, i32 0), i64 6)
 // CHECK: call void @_ZN1TD1Ev
 // CHECK: icmp eq {{.*}} @t
 // CHECK: br i1 {{.*}}
@@ -47,9 +47,9 @@ T t[2][3] = { 1.0, 2, 3.0, 4, 5.0, 6, 7.
 static T t2[2][3] = { 1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10, 11.0, 12 };
 
 // CHECK: call {{.*}} @__cxa_atexit
-// CHECK: getelementptr inbounds ({{.*}} bitcast {{.*}}* @_ZL2t2 to %struct.T*), i64 6
+// CHECK: getelementptr inbounds ({{.*}} getelementptr inbounds ([2 x [3 x {{.*}}]], [2 x [3 x {{.*}}]]* @_ZL2t2, i32 0, i32 0, i32 0), i64 6)
 // CHECK: call void @_ZN1TD1Ev
-// CHECK: icmp eq {{.*}} @_ZL2t
+// CHECK: icmp eq {{.*}} @_ZL2t2
 // CHECK: br i1 {{.*}}
 
 using U = T[2][3];




More information about the cfe-commits mailing list