Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5924,6 +5924,7 @@ void CheckDeductionGuideTemplate(FunctionTemplateDecl *TD); void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); + void CheckExplicitlyDefaultedSpecialMemberConstexpr(CXXMethodDecl *MD); void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD, const FunctionProtoType *T); void CheckDelayedMemberExceptionSpecs(); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -6020,6 +6020,7 @@ bool HasMethodWithOverrideControl = false, HasOverridingMethodWithoutOverrideControl = false; + CXXMethodDecl *CopyAssignment = nullptr, *MoveAssignment = nullptr; if (!Record->isDependentType()) { for (auto *M : Record->methods()) { // See if a method overloads virtual methods in a base @@ -6049,6 +6050,11 @@ } } + if (CSM == CXXCopyAssignment) + CopyAssignment = M; + else if (CSM == CXXMoveAssignment) + MoveAssignment = M; + // Set triviality for the purpose of calls if this is a user-provided // copy/move constructor or destructor. if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor || @@ -6071,6 +6077,22 @@ } } } + + // Now we can decide whether the special members are constexpr. + auto ActOnSpecialMember = [this, &Record](CXXMethodDecl *MD) { + if (!MD->isInvalidDecl() && MD->isExplicitlyDefaulted()) { + CheckExplicitlyDefaultedSpecialMemberConstexpr(MD); + Record->finishedDefaultedOrDeletedMember(MD); + } + }; + for (auto *M : Record->ctors()) + ActOnSpecialMember(M); + if (CopyAssignment) + ActOnSpecialMember(CopyAssignment); + if (MoveAssignment) + ActOnSpecialMember(MoveAssignment); + if (CXXDestructorDecl *CD = Record->getDestructor()) + ActOnSpecialMember(CD); } if (HasMethodWithOverrideControl && @@ -6532,20 +6554,8 @@ // 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, - // Do not apply this rule to members of class templates, since core issue 1358 - // makes such functions always instantiate to constexpr functions. For - // functions which cannot be constexpr (for non-constructors in C++11 and for - // destructors in C++1y), this is checked elsewhere. - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, - HasConstParam); - if ((getLangOpts().CPlusPlus14 ? !isa(MD) - : isa(MD)) && - MD->isConstexpr() && !Constexpr && - MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { - Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM; - // FIXME: Explain why the special member can't be constexpr. - HadError = true; - } + // We need to delay this, because at this point we may not have enough + // information to determine if MD is really constexpr or not. // and may have an explicit exception-specification only if it is compatible // with the exception-specification on the implicit declaration. @@ -6568,8 +6578,6 @@ if (First) { // -- it is implicitly considered to be constexpr if the implicit // definition would be, - MD->setConstexpr(Constexpr); - // -- it is implicitly considered to have the same exception-specification // as if it had been implicitly declared, FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); @@ -6598,6 +6606,39 @@ MD->setInvalidDecl(); } +void Sema::CheckExplicitlyDefaultedSpecialMemberConstexpr(CXXMethodDecl *MD) { + CXXSpecialMember CSM = getSpecialMember(MD); + assert(MD && MD->isExplicitlyDefaulted() && CSM != CXXInvalid && + "not an explicitly-defaulted special member"); + + const FunctionProtoType *Type = MD->getType()->getAs(); + + unsigned ExpectedParams = + CSM != CXXDefaultConstructor && CSM != CXXDestructor; + QualType ArgType = ExpectedParams ? Type->getParamType(0) : QualType(); + + bool HasConstParam = ExpectedParams && ArgType->isReferenceType() && + ArgType->getPointeeType().isConstQualified(); + + // Do not apply this rule to members of class templates, since core issue 1358 + // makes such functions always instantiate to constexpr functions. For + // functions which cannot be constexpr (for non-constructors in C++11 and for + // destructors in C++1y), this is checked elsewhere. + bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, MD->getParent(), + CSM, HasConstParam); + if ((getLangOpts().CPlusPlus14 ? !isa(MD) + : isa(MD)) && + MD->isConstexpr() && !Constexpr && + MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) { + Diag(MD->getLocStart(), diag::err_incorrect_defaulted_constexpr) << CSM; + // FIXME: Explain why the special member can't be constexpr. + MD->setInvalidDecl(); + } + + if (MD == MD->getCanonicalDecl()) + MD->setConstexpr(Constexpr); +} + /// Check whether the exception specification provided for an /// explicitly-defaulted special member matches the exception specification /// that would have been generated for an implicit special member, per @@ -14519,6 +14560,7 @@ return; CheckExplicitlyDefaultedSpecialMember(MD); + CheckExplicitlyDefaultedSpecialMemberConstexpr(MD); if (!MD->isInvalidDecl()) DefineImplicitSpecialMember(*this, MD, DefaultLoc);