r222387 - Fix bug where a trivial constexpr copy/move operation couldn't copy from an

Richard Smith richard-llvm at metafoo.co.uk
Wed Nov 19 13:27:17 PST 2014


Author: rsmith
Date: Wed Nov 19 15:27:17 2014
New Revision: 222387

URL: http://llvm.org/viewvc/llvm-project?rev=222387&view=rev
Log:
Fix bug where a trivial constexpr copy/move operation couldn't copy from an
empty non-constexpr object. Such a copy doesn't break any of the constexpr
rules.

Modified:
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=222387&r1=222386&r2=222387&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Nov 19 15:27:17 2014
@@ -3657,6 +3657,22 @@ static bool CheckConstexprFunction(EvalI
   return false;
 }
 
+/// Determine if a class has any fields that might need to be copied by a
+/// trivial copy or move operation.
+static bool hasFields(const CXXRecordDecl *RD) {
+  if (!RD || RD->isEmpty())
+    return false;
+  for (auto *FD : RD->fields()) {
+    if (FD->isUnnamedBitfield())
+      continue;
+    return true;
+  }
+  for (auto &Base : RD->bases())
+    if (hasFields(Base.getType()->getAsCXXRecordDecl()))
+      return true;
+  return false;
+}
+
 namespace {
 typedef SmallVector<APValue, 8> ArgVector;
 }
@@ -3695,8 +3711,12 @@ static bool HandleFunctionCall(SourceLoc
   // For a trivial copy or move assignment, perform an APValue copy. This is
   // essential for unions, where the operations performed by the assignment
   // operator cannot be represented as statements.
+  //
+  // Skip this for non-union classes with no fields; in that case, the defaulted
+  // copy/move does not actually read the object.
   const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
-  if (MD && MD->isDefaulted() && MD->isTrivial()) {
+  if (MD && MD->isDefaulted() && MD->isTrivial() &&
+      (MD->getParent()->isUnion() || hasFields(MD->getParent()))) {
     assert(This &&
            (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
     LValue RHS;
@@ -3753,11 +3773,18 @@ static bool HandleConstructorCall(Source
   }
 
   // For a trivial copy or move constructor, perform an APValue copy. This is
-  // essential for unions, where the operations performed by the constructor
-  // cannot be represented by ctor-initializers.
+  // essential for unions (or classes with anonymous union members), where the
+  // operations performed by the constructor cannot be represented by
+  // ctor-initializers.
+  //
+  // Skip this for empty non-union classes; we should not perform an
+  // lvalue-to-rvalue conversion on them because their copy constructor does not
+  // actually read them.
   if (Definition->isDefaulted() &&
       ((Definition->isCopyConstructor() && Definition->isTrivial()) ||
-       (Definition->isMoveConstructor() && Definition->isTrivial()))) {
+       (Definition->isMoveConstructor() && Definition->isTrivial())) &&
+      (Definition->getParent()->isUnion() ||
+       hasFields(Definition->getParent()))) {
     LValue RHS;
     RHS.setFrom(Info.Ctx, ArgValues[0]);
     return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=222387&r1=222386&r2=222387&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Wed Nov 19 15:27:17 2014
@@ -1942,3 +1942,16 @@ namespace PR19010 {
 void PR21327(int a, int b) {
   static_assert(&a + 1 != &b, ""); // expected-error {{constant expression}}
 }
+
+namespace EmptyClass {
+  struct E1 {} e1;
+  union E2 {} e2; // expected-note {{here}}
+  struct E3 : E1 {} e3;
+
+  // The defaulted copy constructor for an empty class does not read any
+  // members. The defaulted copy constructor for an empty union reads the
+  // object representation.
+  constexpr E1 e1b(e1);
+  constexpr E2 e2b(e2); // expected-error {{constant expression}} expected-note{{read of non-const}} expected-note {{in call}}
+  constexpr E3 e3b(e3);
+}

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=222387&r1=222386&r2=222387&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Wed Nov 19 15:27:17 2014
@@ -910,3 +910,31 @@ namespace PR17331 {
   constexpr int ARR[] = { 1, 2, 3, 4, 5 };
   static_assert(sum(ARR) == 15, "");
 }
+
+namespace EmptyClass {
+  struct E1 {} e1;
+  union E2 {} e2; // expected-note 4{{here}}
+  struct E3 : E1 {} e3;
+
+  template<typename E>
+  constexpr int f(E &a, int kind) {
+    switch (kind) {
+    case 0: { E e(a); return 0; } // expected-note {{read}} expected-note {{in call}}
+    case 1: { E e(static_cast<E&&>(a)); return 0; } // expected-note {{read}} expected-note {{in call}}
+    case 2: { E e; e = a; return 0; } // expected-note {{read}} expected-note {{in call}}
+    case 3: { E e; e = static_cast<E&&>(a); return 0; } // expected-note {{read}} expected-note {{in call}}
+    }
+  }
+  constexpr int test1 = f(e1, 0);
+  constexpr int test2 = f(e2, 0); // expected-error {{constant expression}} expected-note {{in call}}
+  constexpr int test3 = f(e3, 0);
+  constexpr int test4 = f(e1, 1);
+  constexpr int test5 = f(e2, 1); // expected-error {{constant expression}} expected-note {{in call}}
+  constexpr int test6 = f(e3, 1);
+  constexpr int test7 = f(e1, 2);
+  constexpr int test8 = f(e2, 2); // expected-error {{constant expression}} expected-note {{in call}}
+  constexpr int test9 = f(e3, 2);
+  constexpr int testa = f(e1, 3);
+  constexpr int testb = f(e2, 3); // expected-error {{constant expression}} expected-note {{in call}}
+  constexpr int testc = f(e3, 3);
+}





More information about the cfe-commits mailing list