Author: rsmith Date: Thu May 30 18:25:16 2019 New Revision: 362184 URL: http://llvm.org/viewvc/llvm-project?rev=362184&view=rev Log: PR39728: When completing a class, complete the destructor first.
We need to know whether the destructor is trivial in order to tell whether other parts of the class are valid (in particular, this affects whether the type is a literal type, which affects whether defaulted special members can be declared constexpr or are implicitly constexpr). Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=362184&r1=362183&r2=362184&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu May 30 18:25:16 2019 @@ -6125,9 +6125,60 @@ void Sema::CheckCompletedCXXClass(CXXRec if (HasTrivialABI) Record->setHasTrivialSpecialMemberForCall(); + auto CompleteMemberFunction = [&](CXXMethodDecl *M) { + // Check whether the explicitly-defaulted special members are valid. + if (!M->isInvalidDecl() && M->isExplicitlyDefaulted()) + CheckExplicitlyDefaultedSpecialMember(M); + + // For an explicitly defaulted or deleted special member, we defer + // determining triviality until the class is complete. That time is now! + CXXSpecialMember CSM = getSpecialMember(M); + if (!M->isImplicit() && !M->isUserProvided()) { + if (CSM != CXXInvalid) { + M->setTrivial(SpecialMemberIsTrivial(M, CSM)); + // Inform the class that we've finished declaring this member. + Record->finishedDefaultedOrDeletedMember(M); + M->setTrivialForCall( + HasTrivialABI || + SpecialMemberIsTrivial(M, CSM, TAH_ConsiderTrivialABI)); + Record->setTrivialForCallFlags(M); + } + } + + // Set triviality for the purpose of calls if this is a user-provided + // copy/move constructor or destructor. + if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor || + CSM == CXXDestructor) && M->isUserProvided()) { + M->setTrivialForCall(HasTrivialABI); + Record->setTrivialForCallFlags(M); + } + + if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() && + M->hasAttr<DLLExportAttr>()) { + if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && + M->isTrivial() && + (CSM == CXXDefaultConstructor || CSM == CXXCopyConstructor || + CSM == CXXDestructor)) + M->dropAttr<DLLExportAttr>(); + + if (M->hasAttr<DLLExportAttr>()) { + DefineImplicitSpecialMember(*this, M, M->getLocation()); + ActOnFinishInlineFunctionDef(M); + } + } + }; + bool HasMethodWithOverrideControl = false, HasOverridingMethodWithoutOverrideControl = false; if (!Record->isDependentType()) { + // Check the destructor before any other member function. We need to + // determine whether it's trivial in order to determine whether the claas + // type is a literal type, which is a prerequisite for determining whether + // other special member functions are valid and whether they're implicitly + // 'constexpr'. + if (CXXDestructorDecl *Dtor = Record->getDestructor()) + CompleteMemberFunction(Dtor); + for (auto *M : Record->methods()) { // See if a method overloads virtual methods in a base // class without overriding any. @@ -6137,46 +6188,9 @@ void Sema::CheckCompletedCXXClass(CXXRec HasMethodWithOverrideControl = true; else if (M->size_overridden_methods() > 0) HasOverridingMethodWithoutOverrideControl = true; - // Check whether the explicitly-defaulted special members are valid. - if (!M->isInvalidDecl() && M->isExplicitlyDefaulted()) - CheckExplicitlyDefaultedSpecialMember(M); - - // For an explicitly defaulted or deleted special member, we defer - // determining triviality until the class is complete. That time is now! - CXXSpecialMember CSM = getSpecialMember(M); - if (!M->isImplicit() && !M->isUserProvided()) { - if (CSM != CXXInvalid) { - M->setTrivial(SpecialMemberIsTrivial(M, CSM)); - // Inform the class that we've finished declaring this member. - Record->finishedDefaultedOrDeletedMember(M); - M->setTrivialForCall( - HasTrivialABI || - SpecialMemberIsTrivial(M, CSM, TAH_ConsiderTrivialABI)); - Record->setTrivialForCallFlags(M); - } - } - // Set triviality for the purpose of calls if this is a user-provided - // copy/move constructor or destructor. - if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor || - CSM == CXXDestructor) && M->isUserProvided()) { - M->setTrivialForCall(HasTrivialABI); - Record->setTrivialForCallFlags(M); - } - - if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() && - M->hasAttr<DLLExportAttr>()) { - if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && - M->isTrivial() && - (CSM == CXXDefaultConstructor || CSM == CXXCopyConstructor || - CSM == CXXDestructor)) - M->dropAttr<DLLExportAttr>(); - - if (M->hasAttr<DLLExportAttr>()) { - DefineImplicitSpecialMember(*this, M, M->getLocation()); - ActOnFinishInlineFunctionDef(M); - } - } + if (!isa<CXXDestructorDecl>(M)) + CompleteMemberFunction(M); } } 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=362184&r1=362183&r2=362184&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original) +++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Thu May 30 18:25:16 2019 @@ -1205,3 +1205,19 @@ namespace ObjectsUnderConstruction { // The lifetime of 'n' begins at the initialization, not before. constexpr int n = ++const_cast<int&>(n); // expected-error {{constant expression}} expected-note {{modification}} } + +namespace PR39728 { + struct Comment0 { + Comment0 &operator=(const Comment0 &) = default; + ~Comment0() = default; + }; + constexpr void f() { + Comment0 a; + a = a; + } + static_assert((f(), true), ""); + struct Comment1 { + constexpr Comment1 &operator=(const Comment1 &) = default; // OK + ~Comment1() = default; + }; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits