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);