PR11614: Mark defaulted special constructors as constexpr if their implicit
definition would satisfy the constexpr requirements.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147128 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index ddb61e5..c1aa35f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -38,7 +38,12 @@
     Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
     HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
     HasMutableFields(false), HasTrivialDefaultConstructor(true),
-    HasConstexprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
+    HasConstexprNonCopyMoveConstructor(false),
+    DefaultedDefaultConstructorIsConstexpr(true),
+    DefaultedCopyConstructorIsConstexpr(true),
+    DefaultedMoveConstructorIsConstexpr(true),
+    HasConstexprDefaultConstructor(false), HasConstexprCopyConstructor(false),
+    HasConstexprMoveConstructor(false), HasTrivialCopyConstructor(true),
     HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
     HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
     HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
@@ -190,6 +195,13 @@
       //   A standard-layout class is a class that: [...]
       //    -- has [...] no virtual base classes
       data().IsStandardLayout = false;
+
+      // C++11 [dcl.constexpr]p4:
+      //   In the definition of a constexpr constructor [...]
+      //    -- the class shall not have any virtual base classes
+      data().DefaultedDefaultConstructorIsConstexpr = false;
+      data().DefaultedCopyConstructorIsConstexpr = false;
+      data().DefaultedMoveConstructorIsConstexpr = false;
     } else {
       // C++ [class.ctor]p5:
       //   A default constructor is trivial [...] if:
@@ -221,6 +233,32 @@
         data().HasTrivialCopyAssignment = false;
       if (!BaseClassDecl->hasTrivialMoveAssignment())
         data().HasTrivialMoveAssignment = false;
+
+      // C++11 [class.ctor]p6:
+      //   If that user-written default cosntructor would satisfy the
+      //   requirements of a constexpr constructor, the implicitly-defined
+      //   default constructor is constexpr.
+      if (!BaseClassDecl->hasConstexprDefaultConstructor())
+        data().DefaultedDefaultConstructorIsConstexpr = false;
+
+      // C++11 [class.copy]p13:
+      //   If the implicitly-defined constructor would satisfy the requirements
+      //   of a constexpr constructor, the implicitly-defined constructor is
+      //   constexpr.
+      // C++11 [dcl.constexpr]p4:
+      //    -- every constructor involved in initializing [...] base class
+      //       sub-objects shall be a constexpr constructor
+      if (!BaseClassDecl->hasConstexprCopyConstructor())
+        data().DefaultedCopyConstructorIsConstexpr = false;
+      if (BaseClassDecl->hasDeclaredMoveConstructor() ||
+          BaseClassDecl->needsImplicitMoveConstructor())
+        // FIXME: If the implicit move constructor generated for the base class
+        // would be ill-formed, the implicit move constructor generated for the
+        // derived class calls the base class' copy constructor.
+        data().DefaultedMoveConstructorIsConstexpr &=
+          !BaseClassDecl->hasConstexprMoveConstructor();
+      else if (!BaseClassDecl->hasConstexprCopyConstructor())
+        data().DefaultedMoveConstructorIsConstexpr = false;
     }
     
     // C++ [class.ctor]p3:
@@ -471,13 +509,21 @@
     // If this is a special member function, note that it was added and then
     // return early.
     if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
-      if (Constructor->isDefaultConstructor())
+      if (Constructor->isDefaultConstructor()) {
         data().DeclaredDefaultConstructor = true;
-      else if (Constructor->isCopyConstructor())
+        if (Constructor->isConstexpr()) {
+          data().HasConstexprDefaultConstructor = true;
+          data().HasConstexprNonCopyMoveConstructor = true;
+        }
+      } else if (Constructor->isCopyConstructor()) {
         data().DeclaredCopyConstructor = true;
-      else if (Constructor->isMoveConstructor())
+        if (Constructor->isConstexpr())
+          data().HasConstexprCopyConstructor = true;
+      } else if (Constructor->isMoveConstructor()) {
         data().DeclaredMoveConstructor = true;
-      else
+        if (Constructor->isConstexpr())
+          data().HasConstexprMoveConstructor = true;
+      } else
         goto NotASpecialMember;
       return;
     } else if (isa<CXXDestructorDecl>(D)) {
@@ -507,14 +553,18 @@
     // to all functions.
     bool UserProvided = Constructor->isUserProvided();
 
-    // C++0x [class.ctor]p5:
-    //   A default constructor is trivial if it is not user-provided [...]
     if (Constructor->isDefaultConstructor()) {
       data().DeclaredDefaultConstructor = true;
       if (UserProvided) {
+        // C++0x [class.ctor]p5:
+        //   A default constructor is trivial if it is not user-provided [...]
         data().HasTrivialDefaultConstructor = false;
         data().UserProvidedDefaultConstructor = true;
       }
+      if (Constructor->isConstexpr()) {
+        data().HasConstexprDefaultConstructor = true;
+        data().HasConstexprNonCopyMoveConstructor = true;
+      }
     }
 
     // Note when we have a user-declared copy or move constructor, which will
@@ -529,6 +579,9 @@
         //   user-provided [...]
         if (UserProvided)
           data().HasTrivialCopyConstructor = false;
+
+        if (Constructor->isConstexpr())
+          data().HasConstexprCopyConstructor = true;
       } else if (Constructor->isMoveConstructor()) {
         data().UserDeclaredMoveConstructor = true;
         data().DeclaredMoveConstructor = true;
@@ -538,6 +591,9 @@
         //   user-provided [...]
         if (UserProvided)
           data().HasTrivialMoveConstructor = false;
+
+        if (Constructor->isConstexpr())
+          data().HasConstexprMoveConstructor = true;
       }
     }
     if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
@@ -578,8 +634,18 @@
     // C++11 [class.dtor]p5: 
     //   A destructor is trivial if it is not user-provided and if
     //    -- the destructor is not virtual.
-    if (DD->isUserProvided() || DD->isVirtual())
+    if (DD->isUserProvided() || DD->isVirtual()) {
       data().HasTrivialDestructor = false;
+      // C++11 [dcl.constexpr]p1:
+      //   The constexpr specifier shall be applied only to [...] the
+      //   declaration of a static data member of a literal type.
+      // C++11 [basic.types]p10:
+      //   A type is a literal type if it is [...] a class type that [...] has
+      //   a trivial destructor.
+      data().DefaultedDefaultConstructorIsConstexpr = false;
+      data().DefaultedCopyConstructorIsConstexpr = false;
+      data().DefaultedMoveConstructorIsConstexpr = false;
+    }
     
     return;
   }
@@ -746,7 +812,7 @@
       CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
       if (FieldRec->getDefinition()) {
         // C++0x [class.ctor]p5:
-        //   A defulat constructor is trivial [...] if:
+        //   A default constructor is trivial [...] if:
         //    -- for all the non-static data members of its class that are of
         //       class type (or array thereof), each such class has a trivial
         //       default constructor.
@@ -818,7 +884,41 @@
         // Keep track of the presence of mutable fields.
         if (FieldRec->hasMutableFields())
           data().HasMutableFields = true;
+
+        // C++11 [class.copy]p13:
+        //   If the implicitly-defined constructor would satisfy the
+        //   requirements of a constexpr constructor, the implicitly-defined
+        //   constructor is constexpr.
+        // C++11 [dcl.constexpr]p4:
+        //    -- every constructor involved in initializing non-static data
+        //       members [...] shall be a constexpr constructor
+        if (!Field->hasInClassInitializer() &&
+            !FieldRec->hasConstexprDefaultConstructor())
+          // The standard requires any in-class initializer to be a constant
+          // expression. We consider this to be a defect.
+          data().DefaultedDefaultConstructorIsConstexpr = false;
+
+        if (!FieldRec->hasConstexprCopyConstructor())
+          data().DefaultedCopyConstructorIsConstexpr = false;
+
+        if (FieldRec->hasDeclaredMoveConstructor() ||
+            FieldRec->needsImplicitMoveConstructor())
+          // FIXME: If the implicit move constructor generated for the member's
+          // class would be ill-formed, the implicit move constructor generated
+          // for this class calls the member's copy constructor.
+          data().DefaultedMoveConstructorIsConstexpr &=
+            FieldRec->hasConstexprMoveConstructor();
+        else if (!FieldRec->hasConstexprCopyConstructor())
+          data().DefaultedMoveConstructorIsConstexpr = false;
       }
+    } else {
+      // Base element type of field is a non-class type.
+      if (!T->isLiteralType()) {
+        data().DefaultedDefaultConstructorIsConstexpr = false;
+        data().DefaultedCopyConstructorIsConstexpr = false;
+        data().DefaultedMoveConstructorIsConstexpr = false;
+      } else if (!Field->hasInClassInitializer())
+        data().DefaultedDefaultConstructorIsConstexpr = false;
     }
 
     // C++0x [class]p7:
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 8e6682b..c58a568 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1591,6 +1591,29 @@
   }
 }
 
+/// CheckTrivialDefaultConstructor - Check whether a constructor is a trivial
+/// default constructor. If so, we'll fold it whether or not it's marked as
+/// constexpr. If it is marked as constexpr, we will never implicitly define it,
+/// so we need special handling.
+static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
+                                    const CXXConstructorDecl *CD) {
+  if (!CD->isTrivial() || !CD->isDefaultConstructor())
+    return false;
+
+  if (!CD->isConstexpr()) {
+    if (Info.getLangOpts().CPlusPlus0x) {
+      // FIXME: If DiagDecl is an implicitly-declared special member function,
+      // we should be much more explicit about why it's not constexpr.
+      Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
+        << /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
+      Info.Note(CD->getLocation(), diag::note_declared_at);
+    } else {
+      Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+    }
+  }
+  return true;
+}
+
 /// CheckConstexprFunction - Check that a function can be called in a constant
 /// expression.
 static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
@@ -2790,6 +2813,16 @@
 
 bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
   const CXXConstructorDecl *FD = E->getConstructor();
+  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) {
+    const CXXRecordDecl *RD = FD->getParent();
+    if (RD->isUnion())
+      Result = APValue((FieldDecl*)0);
+    else
+      Result = APValue(APValue::UninitStruct(), RD->getNumBases(),
+                       std::distance(RD->field_begin(), RD->field_end()));
+    return true;
+  }
+
   const FunctionDecl *Definition = 0;
   FD->getBody(Definition);
 
@@ -3144,6 +3177,18 @@
     return true;
 
   const CXXConstructorDecl *FD = E->getConstructor();
+
+  if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD)) {
+    const CXXRecordDecl *RD = FD->getParent();
+    if (RD->isUnion())
+      Result.getArrayFiller() = APValue((FieldDecl*)0);
+    else
+      Result.getArrayFiller() =
+          APValue(APValue::UninitStruct(), RD->getNumBases(),
+                  std::distance(RD->field_begin(), RD->field_end()));
+    return true;
+  }
+
   const FunctionDecl *Definition = 0;
   FD->getBody(Definition);
 
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f8c02ba..7f743f5 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3756,6 +3756,18 @@
                           *ExceptionType = Context.getFunctionType(
                          Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
 
+  // C++11 [dcl.fct.def.default]p2:
+  //   An explicitly-defaulted function may be declared constexpr only if it
+  //   would have been implicitly declared as constexpr,
+  if (CD->isConstexpr()) {
+    if (!CD->getParent()->defaultedDefaultConstructorIsConstexpr()) {
+      Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+        << CXXDefaultConstructor;
+      HadError = true;
+    }
+  }
+  //   and may have an explicit exception-specification only if it is compatible
+  //   with the exception-specification on the implicit declaration.
   if (CtorType->hasExceptionSpec()) {
     if (CheckEquivalentExceptionSpec(
           PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3765,11 +3777,20 @@
           CtorType, CD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
-    // We set the declaration to have the computed exception spec here.
-    // We know there are no parameters.
+  }
+
+  //   If a function is explicitly defaulted on its first declaration,
+  if (First) {
+    //  -- it is implicitly considered to be constexpr if the implicit
+    //     definition would be,
+    CD->setConstexpr(CD->getParent()->defaultedDefaultConstructorIsConstexpr());
+
+    //  -- it is implicitly considered to have the same
+    //     exception-specification as if it had been implicitly declared
+    //
+    // FIXME: a compatible, but different, explicit exception specification
+    // will be silently overridden. We should issue a warning if this happens.
     EPI.ExtInfo = CtorType->getExtInfo();
-    CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
   }
 
   if (HadError) {
@@ -3823,6 +3844,18 @@
     HadError = true;
   }
 
+  // C++11 [dcl.fct.def.default]p2:
+  //   An explicitly-defaulted function may be declared constexpr only if it
+  //   would have been implicitly declared as constexpr,
+  if (CD->isConstexpr()) {
+    if (!CD->getParent()->defaultedCopyConstructorIsConstexpr()) {
+      Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+        << CXXCopyConstructor;
+      HadError = true;
+    }
+  }
+  //   and may have an explicit exception-specification only if it is compatible
+  //   with the exception-specification on the implicit declaration.
   if (CtorType->hasExceptionSpec()) {
     if (CheckEquivalentExceptionSpec(
           PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3832,10 +3865,23 @@
           CtorType, CD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
-    // We set the declaration to have the computed exception spec here.
-    // We duplicate the one parameter type.
+  }
+
+  //   If a function is explicitly defaulted on its first declaration,
+  if (First) {
+    //  -- it is implicitly considered to be constexpr if the implicit
+    //     definition would be,
+    CD->setConstexpr(CD->getParent()->defaultedCopyConstructorIsConstexpr());
+
+    //  -- it is implicitly considered to have the same
+    //     exception-specification as if it had been implicitly declared, and
+    //
+    // FIXME: a compatible, but different, explicit exception specification
+    // will be silently overridden. We should issue a warning if this happens.
     EPI.ExtInfo = CtorType->getExtInfo();
+
+    //  -- [...] it shall have the same parameter type as if it had been
+    //     implicitly declared.
     CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
   }
 
@@ -3917,7 +3963,8 @@
           OperType, MD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
+  }
+  if (First) {
     // We set the declaration to have the computed exception spec here.
     // We duplicate the one parameter type.
     EPI.RefQualifier = OperType->getRefQualifier();
@@ -3974,6 +4021,18 @@
     HadError = true;
   }
 
+  // C++11 [dcl.fct.def.default]p2:
+  //   An explicitly-defaulted function may be declared constexpr only if it
+  //   would have been implicitly declared as constexpr,
+  if (CD->isConstexpr()) {
+    if (!CD->getParent()->defaultedMoveConstructorIsConstexpr()) {
+      Diag(CD->getLocStart(), diag::err_incorrect_defaulted_constexpr)
+        << CXXMoveConstructor;
+      HadError = true;
+    }
+  }
+  //   and may have an explicit exception-specification only if it is compatible
+  //   with the exception-specification on the implicit declaration.
   if (CtorType->hasExceptionSpec()) {
     if (CheckEquivalentExceptionSpec(
           PDiag(diag::err_incorrect_defaulted_exception_spec)
@@ -3983,10 +4042,23 @@
           CtorType, CD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
-    // We set the declaration to have the computed exception spec here.
-    // We duplicate the one parameter type.
+  }
+
+  //   If a function is explicitly defaulted on its first declaration,
+  if (First) {
+    //  -- it is implicitly considered to be constexpr if the implicit
+    //     definition would be,
+    CD->setConstexpr(CD->getParent()->defaultedMoveConstructorIsConstexpr());
+
+    //  -- it is implicitly considered to have the same
+    //     exception-specification as if it had been implicitly declared, and
+    //
+    // FIXME: a compatible, but different, explicit exception specification
+    // will be silently overridden. We should issue a warning if this happens.
     EPI.ExtInfo = CtorType->getExtInfo();
+
+    //  -- [...] it shall have the same parameter type as if it had been
+    //     implicitly declared.
     CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
   }
 
@@ -4066,7 +4138,8 @@
           OperType, MD->getLocation())) {
       HadError = true;
     }
-  } else if (First) {
+  }
+  if (First) {
     // We set the declaration to have the computed exception spec here.
     // We duplicate the one parameter type.
     EPI.RefQualifier = OperType->getRefQualifier();
@@ -4113,7 +4186,8 @@
       DD->setInvalidDecl();
       return;
     }
-  } else if (First) {
+  }
+  if (First) {
     // We set the declaration to have the computed exception spec here.
     // There are no parameters.
     EPI.ExtInfo = DtorType->getExtInfo();
@@ -6792,16 +6866,12 @@
   DeclarationName Name
     = Context.DeclarationNames.getCXXConstructorName(ClassType);
   DeclarationNameInfo NameInfo(Name, ClassLoc);
-  CXXConstructorDecl *DefaultCon
-    = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
-                                 Context.getFunctionType(Context.VoidTy,
-                                                         0, 0, EPI),
-                                 /*TInfo=*/0,
-                                 /*isExplicit=*/false,
-                                 /*isInline=*/true,
-                                 /*isImplicitlyDeclared=*/true,
-                                 // FIXME: apply the rules for definitions here
-                                 /*isConstexpr=*/false);
+  CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo,
+      Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0,
+      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+      /*isConstexpr=*/ClassDecl->defaultedDefaultConstructorIsConstexpr() &&
+        getLangOptions().CPlusPlus0x);
   DefaultCon->setAccess(AS_public);
   DefaultCon->setDefaulted();
   DefaultCon->setImplicit();
@@ -8476,21 +8546,17 @@
   DeclarationNameInfo NameInfo(Name, ClassLoc);
 
   //   An implicitly-declared copy constructor is an inline public
-  //   member of its class. 
-  CXXConstructorDecl *CopyConstructor
-    = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
-                                 Context.getFunctionType(Context.VoidTy,
-                                                         &ArgType, 1, EPI),
-                                 /*TInfo=*/0,
-                                 /*isExplicit=*/false,
-                                 /*isInline=*/true,
-                                 /*isImplicitlyDeclared=*/true,
-                                 // FIXME: apply the rules for definitions here
-                                 /*isConstexpr=*/false);
+  //   member of its class.
+  CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo,
+      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+      /*isConstexpr=*/ClassDecl->defaultedCopyConstructorIsConstexpr() &&
+        getLangOptions().CPlusPlus0x);
   CopyConstructor->setAccess(AS_public);
   CopyConstructor->setDefaulted();
   CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
-  
+
   // Note that we have declared this constructor.
   ++ASTContext::NumImplicitCopyConstructorsDeclared;
   
@@ -8631,21 +8697,17 @@
 
   // C++0x [class.copy]p11:
   //   An implicitly-declared copy/move constructor is an inline public
-  //   member of its class. 
-  CXXConstructorDecl *MoveConstructor
-    = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
-                                 Context.getFunctionType(Context.VoidTy,
-                                                         &ArgType, 1, EPI),
-                                 /*TInfo=*/0,
-                                 /*isExplicit=*/false,
-                                 /*isInline=*/true,
-                                 /*isImplicitlyDeclared=*/true,
-                                 // FIXME: apply the rules for definitions here
-                                 /*isConstexpr=*/false);
+  //   member of its class.
+  CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo,
+      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
+      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
+      /*isConstexpr=*/ClassDecl->defaultedMoveConstructorIsConstexpr() &&
+        getLangOptions().CPlusPlus0x);
   MoveConstructor->setAccess(AS_public);
   MoveConstructor->setDefaulted();
   MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
-  
+
   // Add the parameter to the constructor.
   ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
                                                ClassLoc, ClassLoc,