mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 08:16:49 +00:00
PR11614: Mark defaulted special constructors as constexpr if their implicit
definition would satisfy the constexpr requirements. llvm-svn: 147128
This commit is contained in:
parent
1c3b1efa58
commit
cc36f698af
@ -366,10 +366,34 @@ class CXXRecordDecl : public RecordDecl {
|
||||
bool HasTrivialDefaultConstructor : 1;
|
||||
|
||||
/// HasConstexprNonCopyMoveConstructor - True when this class has at least
|
||||
/// one constexpr constructor which is neither the copy nor move
|
||||
/// constructor.
|
||||
/// one user-declared constexpr constructor which is neither the copy nor
|
||||
/// move constructor.
|
||||
bool HasConstexprNonCopyMoveConstructor : 1;
|
||||
|
||||
/// DefaultedDefaultConstructorIsConstexpr - True if a defaulted default
|
||||
/// constructor for this class would be constexpr.
|
||||
bool DefaultedDefaultConstructorIsConstexpr : 1;
|
||||
|
||||
/// DefaultedCopyConstructorIsConstexpr - True if a defaulted copy
|
||||
/// constructor for this class would be constexpr.
|
||||
bool DefaultedCopyConstructorIsConstexpr : 1;
|
||||
|
||||
/// DefaultedMoveConstructorIsConstexpr - True if a defaulted move
|
||||
/// constructor for this class would be constexpr.
|
||||
bool DefaultedMoveConstructorIsConstexpr : 1;
|
||||
|
||||
/// HasConstexprDefaultConstructor - True if this class has a constexpr
|
||||
/// default constructor (either user-declared or implicitly declared).
|
||||
bool HasConstexprDefaultConstructor : 1;
|
||||
|
||||
/// HasConstexprCopyConstructor - True if this class has a constexpr copy
|
||||
/// constructor (either user-declared or implicitly declared).
|
||||
bool HasConstexprCopyConstructor : 1;
|
||||
|
||||
/// HasConstexprMoveConstructor - True if this class has a constexpr move
|
||||
/// constructor (either user-declared or implicitly declared).
|
||||
bool HasConstexprMoveConstructor : 1;
|
||||
|
||||
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
||||
/// constructor.
|
||||
///
|
||||
@ -946,19 +970,62 @@ public:
|
||||
/// mutable field.
|
||||
bool hasMutableFields() const { return data().HasMutableFields; }
|
||||
|
||||
// hasTrivialDefaultConstructor - Whether this class has a trivial default
|
||||
// constructor
|
||||
// (C++0x [class.ctor]p5)
|
||||
/// hasTrivialDefaultConstructor - Whether this class has a trivial default
|
||||
/// constructor (C++11 [class.ctor]p5).
|
||||
bool hasTrivialDefaultConstructor() const {
|
||||
return data().HasTrivialDefaultConstructor &&
|
||||
(!data().UserDeclaredConstructor ||
|
||||
data().DeclaredDefaultConstructor);
|
||||
}
|
||||
|
||||
// hasConstexprNonCopyMoveConstructor - Whether this class has at least one
|
||||
// constexpr constructor other than the copy or move constructors.
|
||||
/// hasConstexprNonCopyMoveConstructor - Whether this class has at least one
|
||||
/// constexpr constructor other than the copy or move constructors.
|
||||
bool hasConstexprNonCopyMoveConstructor() const {
|
||||
return data().HasConstexprNonCopyMoveConstructor;
|
||||
return data().HasConstexprNonCopyMoveConstructor ||
|
||||
(!hasUserDeclaredConstructor() &&
|
||||
defaultedDefaultConstructorIsConstexpr());
|
||||
}
|
||||
|
||||
/// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default
|
||||
/// constructor for this class would be constexpr.
|
||||
bool defaultedDefaultConstructorIsConstexpr() const {
|
||||
return data().DefaultedDefaultConstructorIsConstexpr;
|
||||
}
|
||||
|
||||
/// defaultedCopyConstructorIsConstexpr - Whether a defaulted copy
|
||||
/// constructor for this class would be constexpr.
|
||||
bool defaultedCopyConstructorIsConstexpr() const {
|
||||
return data().DefaultedCopyConstructorIsConstexpr;
|
||||
}
|
||||
|
||||
/// defaultedMoveConstructorIsConstexpr - Whether a defaulted move
|
||||
/// constructor for this class would be constexpr.
|
||||
bool defaultedMoveConstructorIsConstexpr() const {
|
||||
return data().DefaultedMoveConstructorIsConstexpr;
|
||||
}
|
||||
|
||||
/// hasConstexprDefaultConstructor - Whether this class has a constexpr
|
||||
/// default constructor.
|
||||
bool hasConstexprDefaultConstructor() const {
|
||||
return data().HasConstexprDefaultConstructor ||
|
||||
(!data().UserDeclaredConstructor &&
|
||||
data().DefaultedDefaultConstructorIsConstexpr && isLiteral());
|
||||
}
|
||||
|
||||
/// hasConstexprCopyConstructor - Whether this class has a constexpr copy
|
||||
/// constructor.
|
||||
bool hasConstexprCopyConstructor() const {
|
||||
return data().HasConstexprCopyConstructor ||
|
||||
(!data().DeclaredCopyConstructor &&
|
||||
data().DefaultedCopyConstructorIsConstexpr && isLiteral());
|
||||
}
|
||||
|
||||
/// hasConstexprMoveConstructor - Whether this class has a constexpr move
|
||||
/// constructor.
|
||||
bool hasConstexprMoveConstructor() const {
|
||||
return data().HasConstexprMoveConstructor ||
|
||||
(needsImplicitMoveConstructor() &&
|
||||
data().DefaultedMoveConstructorIsConstexpr && isLiteral());
|
||||
}
|
||||
|
||||
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
||||
|
@ -4685,6 +4685,9 @@ def err_incorrect_defaulted_exception_spec : Error<
|
||||
"copy constructor|move constructor|copy assignment operator|move assignment "
|
||||
"operator|destructor}0 does not match the "
|
||||
"calculated one">;
|
||||
def err_incorrect_defaulted_constexpr : Error<
|
||||
"defaulted definition of %select{default constructor|copy constructor|"
|
||||
"move constructor}0 is not constexpr">;
|
||||
def err_out_of_line_default_deletes : Error<
|
||||
"defaulting this %select{default constructor|copy constructor|move "
|
||||
"constructor|copy assignment operator|move assignment operator|destructor}0 "
|
||||
|
@ -38,7 +38,12 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
||||
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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||
// 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 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||
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 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||
// 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 @@ NotASpecialMember:;
|
||||
// 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 @@ NotASpecialMember:;
|
||||
// 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 @@ NotASpecialMember:;
|
||||
// user-provided [...]
|
||||
if (UserProvided)
|
||||
data().HasTrivialMoveConstructor = false;
|
||||
|
||||
if (Constructor->isConstexpr())
|
||||
data().HasConstexprMoveConstructor = true;
|
||||
}
|
||||
}
|
||||
if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
|
||||
@ -578,8 +634,18 @@ NotASpecialMember:;
|
||||
// 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 @@ NotASpecialMember:;
|
||||
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 @@ NotASpecialMember:;
|
||||
// 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:
|
||||
|
@ -1591,6 +1591,29 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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::VisitInitListExpr(const InitListExpr *E) {
|
||||
|
||||
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 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
|
||||
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);
|
||||
|
||||
|
@ -3756,6 +3756,18 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
|
||||
*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 @@ void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
|
||||
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 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
|
||||
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 @@ void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
|
||||
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 @@ void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
|
||||
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 @@ void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
|
||||
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 @@ void Sema::CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *CD) {
|
||||
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 @@ void Sema::CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *MD) {
|
||||
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 @@ void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
|
||||
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 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
|
||||
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 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
|
||||
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 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
|
||||
|
||||
// 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,
|
||||
|
@ -42,13 +42,12 @@ class C2 {} constexpr; // expected-error {{class cannot be marked constexpr}}
|
||||
struct S2 {} constexpr; // expected-error {{struct cannot be marked constexpr}}
|
||||
union U2 {} constexpr; // expected-error {{union cannot be marked constexpr}}
|
||||
enum E2 {} constexpr; // expected-error {{enum cannot be marked constexpr}}
|
||||
// FIXME: Mark default constructors as 'constexpr' when appropriate.
|
||||
constexpr class C3 {} c3 = C3(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
|
||||
constexpr struct S3 {} s3 = S3(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
|
||||
constexpr class C3 {} c3 = C3();
|
||||
constexpr struct S3 {} s3 = S3();
|
||||
constexpr union U3 {} u3 = {};
|
||||
constexpr enum E3 { V3 } e3 = V3;
|
||||
class C4 {} constexpr c4 = C4(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
|
||||
struct S4 {} constexpr s4 = S4(); // unexpected-error {{must be initialized by a constant expression}} unexpected-note {{non-constexpr constructor}} unexpected-note {{here}}
|
||||
class C4 {} constexpr c4 = C4();
|
||||
struct S4 {} constexpr s4 = S4();
|
||||
union U4 {} constexpr u4 = {};
|
||||
enum E4 { V4 } constexpr e4 = V4;
|
||||
constexpr int; // expected-error {{constexpr can only be used in variable and function declarations}}
|
||||
|
@ -30,7 +30,7 @@ struct SS : S {
|
||||
|
||||
// The definition of a constexpr function shall satisfy the following
|
||||
// constraints:
|
||||
struct T : SS { // expected-note {{base class 'SS' of non-literal type}}
|
||||
struct T : SS, NonLiteral { // expected-note {{base class 'NonLiteral' of non-literal type}}
|
||||
constexpr T(); // expected-error {{non-literal type 'T' cannot have constexpr members}}
|
||||
|
||||
// - it shall not be virtual;
|
||||
|
@ -0,0 +1,55 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
||||
|
||||
// An explicitly-defaulted function may be declared constexpr only if it would
|
||||
// have been implicitly declared as constexpr.
|
||||
struct S1 {
|
||||
constexpr S1() = default; // expected-error {{defaulted definition of default constructor is not constexpr}}
|
||||
constexpr S1(const S1&) = default;
|
||||
constexpr S1(S1&&) = default;
|
||||
constexpr S1 &operator=(const S1&) = default; // expected-error {{explicitly-defaulted copy assignment operator may not have}}
|
||||
constexpr S1 &operator=(S1&&) = default; // expected-error {{explicitly-defaulted move assignment operator may not have}}
|
||||
constexpr ~S1() = default; // expected-error {{destructor cannot be marked constexpr}}
|
||||
int n;
|
||||
};
|
||||
struct NoCopyMove {
|
||||
constexpr NoCopyMove() {}
|
||||
NoCopyMove(const NoCopyMove&);
|
||||
NoCopyMove(NoCopyMove&&);
|
||||
};
|
||||
struct S2 {
|
||||
constexpr S2() = default;
|
||||
constexpr S2(const S2&) = default; // expected-error {{defaulted definition of copy constructor is not constexpr}}
|
||||
constexpr S2(S2&&) = default; // expected-error {{defaulted definition of move constructor is not constexpr}}
|
||||
NoCopyMove ncm;
|
||||
};
|
||||
|
||||
// If a function is explicitly defaulted on its first declaration
|
||||
// -- it is implicitly considered to be constexpr if the implicit declaration
|
||||
// would be
|
||||
struct S3 {
|
||||
S3() = default; // expected-note {{here}}
|
||||
S3(const S3&) = default;
|
||||
S3(S3&&) = default;
|
||||
constexpr S3(int n) : n(n) {}
|
||||
int n;
|
||||
};
|
||||
constexpr S3 s3a = S3(0);
|
||||
constexpr S3 s3b = s3a;
|
||||
constexpr S3 s3c = S3(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
|
||||
|
||||
struct S4 {
|
||||
S4() = default;
|
||||
S4(const S4&) = default; // expected-note {{here}}
|
||||
S4(S4&&) = default; // expected-note {{here}}
|
||||
NoCopyMove ncm;
|
||||
};
|
||||
constexpr S4 s4a; // ok
|
||||
constexpr S4 s4b = S4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
|
||||
constexpr S4 s4c = s4a; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
|
||||
|
||||
struct S5 {
|
||||
constexpr S5();
|
||||
int n = 1, m = n + 3;
|
||||
};
|
||||
constexpr S5::S5() = default;
|
||||
static_assert(S5().m == 4, "");
|
55
clang/test/CXX/special/class.copy/p13-0x.cpp
Normal file
55
clang/test/CXX/special/class.copy/p13-0x.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
||||
|
||||
// If the implicitly-defined constructor would satisfy the requirements of a
|
||||
// constexpr constructor, the implicitly-defined constructor is constexpr.
|
||||
struct Constexpr1 {
|
||||
constexpr Constexpr1() : n(0) {}
|
||||
int n;
|
||||
};
|
||||
constexpr Constexpr1 c1a = Constexpr1(Constexpr1()); // ok
|
||||
constexpr Constexpr1 c1b = Constexpr1(Constexpr1(c1a)); // ok
|
||||
|
||||
struct Constexpr2 {
|
||||
Constexpr1 ce1;
|
||||
constexpr Constexpr2() = default;
|
||||
constexpr Constexpr2(const Constexpr2 &o) : ce1(o.ce1) {}
|
||||
// no move constructor
|
||||
};
|
||||
|
||||
constexpr Constexpr2 c2a = Constexpr2(Constexpr2()); // ok
|
||||
constexpr Constexpr2 c2b = Constexpr2(Constexpr2(c2a)); // ok
|
||||
|
||||
struct Constexpr3 {
|
||||
Constexpr2 ce2;
|
||||
// all special constructors are constexpr, move ctor calls ce2's copy ctor
|
||||
};
|
||||
|
||||
constexpr Constexpr3 c3a = Constexpr3(Constexpr3()); // ok
|
||||
constexpr Constexpr3 c3b = Constexpr3(Constexpr3(c3a)); // ok
|
||||
|
||||
struct NonConstexprCopy {
|
||||
constexpr NonConstexprCopy() = default;
|
||||
NonConstexprCopy(const NonConstexprCopy &);
|
||||
constexpr NonConstexprCopy(NonConstexprCopy &&) = default;
|
||||
|
||||
int n = 42;
|
||||
};
|
||||
|
||||
NonConstexprCopy::NonConstexprCopy(const NonConstexprCopy &) = default; // expected-note {{here}}
|
||||
|
||||
constexpr NonConstexprCopy ncc1 = NonConstexprCopy(NonConstexprCopy()); // ok
|
||||
constexpr NonConstexprCopy ncc2 = ncc1; // expected-error {{constant expression}} expected-note {{non-constexpr constructor}}
|
||||
|
||||
struct NonConstexprDefault {
|
||||
NonConstexprDefault() = default;
|
||||
constexpr NonConstexprDefault(int n) : n(n) {}
|
||||
int n;
|
||||
};
|
||||
struct Constexpr4 {
|
||||
NonConstexprDefault ncd;
|
||||
};
|
||||
|
||||
constexpr NonConstexprDefault ncd = NonConstexprDefault(NonConstexprDefault(1));
|
||||
constexpr Constexpr4 c4a = { ncd };
|
||||
constexpr Constexpr4 c4b = Constexpr4(c4a);
|
||||
constexpr Constexpr4 c4c = Constexpr4(static_cast<Constexpr4&&>(const_cast<Constexpr4&>(c4b)));
|
49
clang/test/CXX/special/class.ctor/p6-0x.cpp
Normal file
49
clang/test/CXX/special/class.ctor/p6-0x.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
|
||||
|
||||
// Implicitly-defined default constructors are constexpr if the implicit
|
||||
// definition would be.
|
||||
struct NonConstexpr1 { // expected-note {{here}}
|
||||
int a;
|
||||
};
|
||||
struct NonConstexpr2 { // expected-note {{here}}
|
||||
NonConstexpr1 nl;
|
||||
};
|
||||
constexpr NonConstexpr1 nc1 = NonConstexpr1(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr1'}}
|
||||
constexpr NonConstexpr2 nc2 = NonConstexpr2(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr2'}}
|
||||
|
||||
struct Constexpr1 {};
|
||||
constexpr Constexpr1 c1 = Constexpr1(); // ok
|
||||
struct NonConstexpr3 : virtual Constexpr1 {};
|
||||
constexpr NonConstexpr3 nc3 = NonConstexpr3(); // expected-error {{constant expression}} expected-note {{non-literal type 'const NonConstexpr3'}}
|
||||
|
||||
struct Constexpr2 {
|
||||
int a = 0;
|
||||
};
|
||||
constexpr Constexpr2 c2 = Constexpr2(); // ok
|
||||
|
||||
int n;
|
||||
struct Member {
|
||||
Member() : a(n) {}
|
||||
constexpr Member(int&a) : a(a) {}
|
||||
int &a;
|
||||
};
|
||||
struct NonConstexpr4 { // expected-note {{here}}
|
||||
Member m;
|
||||
};
|
||||
constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4'}}
|
||||
struct Constexpr3 {
|
||||
constexpr Constexpr3() : m(n) {}
|
||||
Member m;
|
||||
};
|
||||
constexpr Constexpr3 c3 = Constexpr3(); // ok
|
||||
struct Constexpr4 {
|
||||
Constexpr3 m;
|
||||
};
|
||||
constexpr Constexpr4 c4 = Constexpr4(); // ok
|
||||
|
||||
|
||||
// This rule breaks some legal C++98 programs!
|
||||
struct A {}; // expected-note {{here}}
|
||||
struct B {
|
||||
friend A::A(); // expected-error {{non-constexpr declaration of 'A' follows constexpr declaration}}
|
||||
};
|
@ -86,7 +86,7 @@ namespace TemplateArgumentConversion {
|
||||
|
||||
using IntParam0 = IntParam<0>;
|
||||
using IntParam0 = IntParam<id(0)>;
|
||||
using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}} expected-error {{not an integral constant expression}}
|
||||
using IntParam0 = IntParam<MemberZero().zero>; // expected-error {{did you mean to call it with no arguments?}}
|
||||
}
|
||||
|
||||
namespace CaseStatements {
|
||||
@ -517,16 +517,15 @@ struct D {
|
||||
};
|
||||
static_assert(D().c.n == 42, "");
|
||||
|
||||
struct E { // expected-note {{here}}
|
||||
struct E {
|
||||
constexpr E() : p(&p) {} // expected-note {{pointer to temporary cannot be used to initialize a member in a constant expression}}
|
||||
void *p;
|
||||
};
|
||||
constexpr const E &e1 = E(); // expected-error {{constant expression}} expected-note {{in call to 'E()'}} expected-note {{temporary created here}}
|
||||
// This is a constant expression if we elide the copy constructor call, and
|
||||
// is not a constant expression if we don't! But we do, so it is.
|
||||
// FIXME: The move constructor is not currently implicitly defined as constexpr.
|
||||
constexpr E e2 = E(); // unexpected-error {{constant expression}} unexpected-note {{here}} unexpected-note {{non-constexpr constructor 'E' cannot be used in a constant expression}}
|
||||
static_assert(e2.p == &e2.p, ""); // unexpected-error {{constant expression}} unexpected-note {{initializer of 'e2' is not a constant expression}}
|
||||
constexpr E e2 = E();
|
||||
static_assert(e2.p == &e2.p, "");
|
||||
constexpr E e3;
|
||||
static_assert(e3.p == &e3.p, "");
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
enum E {};
|
||||
|
||||
struct Z {}; // expected-note {{here}}
|
||||
struct Z {};
|
||||
typedef int Integer;
|
||||
|
||||
struct X {
|
||||
@ -14,5 +14,5 @@ struct X {
|
||||
|
||||
struct Y {
|
||||
enum E : int(2);
|
||||
enum E : Z(); // expected-error{{not an integer constant}} expected-note {{non-constexpr constructor 'Z'}}
|
||||
enum E : Z(); // expected-error{{not an integer constant}}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user