jordan_rose created this revision.
jordan_rose added a project: clang.

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.


Repository:
  rL LLVM

https://reviews.llvm.org/D39035

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


Index: test/SemaCXX/warn-global-constructors.cpp
===================================================================
--- test/SemaCXX/warn-global-constructors.cpp
+++ test/SemaCXX/warn-global-constructors.cpp
@@ -126,3 +126,22 @@
 void *array_storage[1];
 const int &global_reference = *(int *)array_storage;
 }
+
+namespace HasUnnamedBitfield {
+  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}}
+}
\ No newline at end of file
Index: test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- test/SemaCXX/constant-expression-cxx11.cpp
+++ test/SemaCXX/constant-expression-cxx11.cpp
@@ -1920,6 +1920,23 @@
     };
     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-error {{division by zero is undefined}}
+    const HasUnnamedBitfield oneZero{1, 0};
+    int b = 1 / oneZero.b; // expected-error {{division by zero is undefined}}
+  }
 }
 
 namespace ZeroSizeTypes {
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -1783,6 +1783,9 @@
       }
     }
     for (const auto *I : RD->fields()) {
+      if (I->isUnnamedBitfield())
+        continue;
+
       if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
                                    Value.getStructField(I->getFieldIndex())))
         return false;


Index: test/SemaCXX/warn-global-constructors.cpp
===================================================================
--- test/SemaCXX/warn-global-constructors.cpp
+++ test/SemaCXX/warn-global-constructors.cpp
@@ -126,3 +126,22 @@
 void *array_storage[1];
 const int &global_reference = *(int *)array_storage;
 }
+
+namespace HasUnnamedBitfield {
+  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}}
+}
\ No newline at end of file
Index: test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- test/SemaCXX/constant-expression-cxx11.cpp
+++ test/SemaCXX/constant-expression-cxx11.cpp
@@ -1920,6 +1920,23 @@
     };
     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-error {{division by zero is undefined}}
+    const HasUnnamedBitfield oneZero{1, 0};
+    int b = 1 / oneZero.b; // expected-error {{division by zero is undefined}}
+  }
 }
 
 namespace ZeroSizeTypes {
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -1783,6 +1783,9 @@
       }
     }
     for (const auto *I : RD->fields()) {
+      if (I->isUnnamedBitfield())
+        continue;
+
       if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
                                    Value.getStructField(I->getFieldIndex())))
         return false;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to