diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-31 01:25:16 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-31 01:25:16 +0000 |
commit | dbd3ce92e691848a34fb7623b487d699de7674d7 (patch) | |
tree | 356923c33f037f0068b5ef01fd53fe713264dd20 /clang | |
parent | 059b823e709a90d3b5d2d24663830e59b3bdded9 (diff) | |
download | bcm5719-llvm-dbd3ce92e691848a34fb7623b487d699de7674d7.tar.gz bcm5719-llvm-dbd3ce92e691848a34fb7623b487d699de7674d7.zip |
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).
llvm-svn: 362184
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 92 | ||||
-rw-r--r-- | clang/test/SemaCXX/constant-expression-cxx1y.cpp | 16 |
2 files changed, 69 insertions, 39 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 35863a32662..0956aff21e1 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6125,9 +6125,60 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { 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(CXXRecordDecl *Record) { 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); } } diff --git a/clang/test/SemaCXX/constant-expression-cxx1y.cpp b/clang/test/SemaCXX/constant-expression-cxx1y.cpp index fe69d105023..6a344c8d4a5 100644 --- a/clang/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx1y.cpp @@ -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; + }; +} |