diff --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def --- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def +++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def @@ -242,4 +242,8 @@ /// const-qualified reference parameter or a non-reference parameter. FIELD(HasDeclaredCopyAssignmentWithConstParam, 1, MERGE_OR) +/// Whether the destructor is no-return. Either explicitly, or if any +/// base classes or fields have a no-return destructor +FIELD(IsAnyDestructorNoReturn, 1, NO_MERGE) + #undef FIELD diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1480,7 +1480,7 @@ /// Returns true if the class destructor, or any implicitly invoked /// destructors are marked noreturn. - bool isAnyDestructorNoReturn() const; + bool isAnyDestructorNoReturn() const { return data().IsAnyDestructorNoReturn; } /// If the class is a local class [class.local], returns /// the enclosing function declaration. diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -108,7 +108,8 @@ ImplicitCopyConstructorCanHaveConstParamForNonVBase(true), ImplicitCopyAssignmentHasConstParam(true), HasDeclaredCopyConstructorWithConstParam(false), - HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false), + HasDeclaredCopyAssignmentWithConstParam(false), + IsAnyDestructorNoReturn(false), IsLambda(false), IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false), HasODRHash(false), Definition(D) {} @@ -424,6 +425,9 @@ if (!BaseClassDecl->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; + if (BaseClassDecl->isAnyDestructorNoReturn()) + data().IsAnyDestructorNoReturn = true; + // C++11 [class.copy]p18: // The implicitly-declared copy assignment operator for a class X will // have the form 'X& X::operator=(const X&)' if each direct base class B @@ -836,6 +840,9 @@ data().HasTrivialSpecialMembers &= ~SMF_Destructor; data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor; } + + if (DD->isNoReturn()) + data().IsAnyDestructorNoReturn = true; } // Handle member functions. @@ -1233,6 +1240,8 @@ data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor; if (!FieldRec->hasIrrelevantDestructor()) data().HasIrrelevantDestructor = false; + if (FieldRec->isAnyDestructorNoReturn()) + data().IsAnyDestructorNoReturn = true; if (FieldRec->hasObjectMember()) setHasObjectMember(true); if (FieldRec->hasVolatileMember()) @@ -1888,29 +1897,6 @@ return R.empty() ? nullptr : dyn_cast(R.front()); } -bool CXXRecordDecl::isAnyDestructorNoReturn() const { - // Destructor is noreturn. - if (const CXXDestructorDecl *Destructor = getDestructor()) - if (Destructor->isNoReturn()) - return true; - - // Check base classes destructor for noreturn. - for (const auto &Base : bases()) - if (const CXXRecordDecl *RD = Base.getType()->getAsCXXRecordDecl()) - if (RD->isAnyDestructorNoReturn()) - return true; - - // Check fields for noreturn. - for (const auto *Field : fields()) - if (const CXXRecordDecl *RD = - Field->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) - if (RD->isAnyDestructorNoReturn()) - return true; - - // All destructors are not noreturn. - return false; -} - static bool isDeclContextInNamespace(const DeclContext *DC) { while (!DC->isTranslationUnit()) { if (DC->isNamespace())