]> granicus.if.org Git - clang/commitdiff
Unnamed bitfields don't block constant evaluation of constexpr ctors
authorJordan Rose <jordan_rose@apple.com>
Tue, 24 Oct 2017 02:17:07 +0000 (02:17 +0000)
committerJordan Rose <jordan_rose@apple.com>
Tue, 24 Oct 2017 02:17:07 +0000 (02:17 +0000)
C++14 [dcl.constexpr]p4 states that in the body of a constexpr
constructor,

> every non-variant non-static data member and base class sub-object
  shall be initialized

However, [class.bit]p2 notes that

> Unnamed bit-fields are not members and cannot be initialized.

Therefore, we should make sure to filter them out of the check that
all fields are initialized.

Fixing this makes the constant evaluator a bit smarter, and
specifically allows constexpr constructors to avoid tripping
-Wglobal-constructors when the type contains unnamed bitfields.

Reviewed at https://reviews.llvm.org/D39035.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316408 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
test/SemaCXX/constant-expression-cxx11.cpp
test/SemaCXX/warn-global-constructors.cpp

index c25b3b6322fe5c1e7f0f562fad51f63b77cd1d90..c09c99386c36afc21d101e5ac0357fb4d4381202 100644 (file)
@@ -1818,6 +1818,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
       }
     }
     for (const auto *I : RD->fields()) {
+      if (I->isUnnamedBitfield())
+        continue;
+
       if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
                                    Value.getStructField(I->getFieldIndex())))
         return false;
index 68b82c7d96fdd956822af6f6a9e436657b421252..51dd6199e63a65abe5a88a9ea13f619bea7d7baf 100644 (file)
@@ -1931,6 +1931,22 @@ namespace Bitfields {
     };
     static_assert(X::f(3) == -1, "3 should truncate to -1");
   }
+
+  struct HasUnnamedBitfield {
+    unsigned a;
+    unsigned : 20;
+    unsigned b;
+
+    constexpr HasUnnamedBitfield() : a(), b() {}
+    constexpr HasUnnamedBitfield(unsigned a, unsigned b) : a(a), b(b) {}
+  };
+
+  void testUnnamedBitfield() {
+    const HasUnnamedBitfield zero{};
+    int a = 1 / zero.b; // expected-warning {{division by zero is undefined}}
+    const HasUnnamedBitfield oneZero{1, 0};
+    int b = 1 / oneZero.b; // expected-warning {{division by zero is undefined}}
+  }
 }
 
 namespace ZeroSizeTypes {
index 856826414a8b3e284802fe3a104f15b1323cf059..430f239a3ed7e1274e06729ff3d53a8c8f5804bc 100644 (file)
@@ -126,3 +126,22 @@ namespace pr20420 {
 void *array_storage[1];
 const int &global_reference = *(int *)array_storage;
 }
+
+namespace bitfields {
+  struct HasUnnamedBitfield {
+    unsigned a;
+    unsigned : 20;
+    unsigned b;
+
+    constexpr HasUnnamedBitfield() : a(), b() {}
+    constexpr HasUnnamedBitfield(unsigned a, unsigned b) : a(a), b(b) {}
+    explicit HasUnnamedBitfield(unsigned a) {}
+  };
+
+  const HasUnnamedBitfield zeroConst{};
+  HasUnnamedBitfield zeroMutable{};
+  const HasUnnamedBitfield explicitConst{1, 2};
+  HasUnnamedBitfield explicitMutable{1, 2};
+  const HasUnnamedBitfield nonConstexprConst{1}; // expected-warning {{global constructor}}
+  HasUnnamedBitfield nonConstexprMutable{1}; // expected-warning {{global constructor}}
+}