#include "clang/Basic/SourceLocation.h"
namespace clang {
- class CXXRecordDecl;
class ClassTemplateDecl;
class ClassTemplateSpecializationDecl;
+ class CXXDestructorDecl;
+ class CXXRecordDecl;
class Decl;
class DeclContext;
class FunctionDecl;
/// \brief A function's return type has been deduced.
virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType);
+ /// \brief A virtual destructor's operator delete has been resolved.
+ virtual void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
+ const FunctionDecl *Delete) {}
+
/// \brief An implicit member got a definition.
virtual void CompletedImplicitDefinition(const FunctionDecl *D) {}
bool isImplicitlyDeclared);
static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
- void setOperatorDelete(FunctionDecl *OD) {
- cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete = OD;
- }
+ void setOperatorDelete(FunctionDecl *OD);
const FunctionDecl *getOperatorDelete() const {
return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete;
}
const FunctionDecl *D) override;
void ResolvedExceptionSpec(const FunctionDecl *FD) override;
void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
+ void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
+ const FunctionDecl *Delete) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
isInline, isImplicitlyDeclared);
}
+void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD) {
+ auto *First = cast<CXXDestructorDecl>(getFirstDecl());
+ if (OD && !First->OperatorDelete) {
+ First->OperatorDelete = OD;
+ if (auto *L = getASTMutationListener())
+ L->ResolvedOperatorDelete(First, OD);
+ }
+}
+
void CXXConversionDecl::anchor() { }
CXXConversionDecl *
void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
const FunctionDecl *D) override;
void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) override;
+ void ResolvedOperatorDelete(const CXXDestructorDecl *DD,
+ const FunctionDecl *Delete) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeducedReturnType(FD, ReturnType);
}
+void MultiplexASTMutationListener::ResolvedOperatorDelete(
+ const CXXDestructorDecl *DD, const FunctionDecl *Delete) {
+ for (auto *L : Listeners)
+ L->ResolvedOperatorDelete(DD, Delete);
+}
void MultiplexASTMutationListener::CompletedImplicitDefinition(
const FunctionDecl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
+ UPD_CXX_RESOLVED_DTOR_DELETE,
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
UPD_DECL_MARKED_USED,
void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
- D->OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx);
+ if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>(Record, Idx)) {
+ auto *Canon = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ // FIXME: Check consistency if we have an old and new operator delete.
+ if (!Canon->OperatorDelete)
+ Canon->OperatorDelete = OperatorDelete;
+ }
}
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
std::tie(CD->CtorInitializers, CD->NumCtorInitializers) =
Reader.ReadCXXCtorInitializers(ModuleFile, Record, Idx);
- if (auto *DD = dyn_cast<CXXDestructorDecl>(FD))
- // FIXME: Check consistency.
- DD->setOperatorDelete(Reader.ReadDeclAs<FunctionDecl>(ModuleFile,
- Record, Idx));
// Store the offset of the body so we can lazily load it later.
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;
break;
}
+ case UPD_CXX_RESOLVED_DTOR_DELETE: {
+ // Set the 'operator delete' directly to avoid emitting another update
+ // record.
+ auto *Del = Reader.ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx);
+ auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl());
+ // FIXME: Check consistency if we have an old and new operator delete.
+ if (!First->OperatorDelete)
+ First->OperatorDelete = Del;
+ break;
+ }
+
case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
// FIXME: This doesn't send the right notifications if there are
// ASTMutationListeners other than an ASTWriter.
break;
}
+ case UPD_CXX_RESOLVED_DTOR_DELETE:
+ AddDeclRef(Update.getDecl(), Record);
+ break;
+
case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
addExceptionSpec(
*this,
Record.push_back(Def->isInlined());
AddSourceLocation(Def->getInnerLocStart(), Record);
AddFunctionDefinition(Def, Record);
- if (auto *DD = dyn_cast<CXXDestructorDecl>(Def))
- Record.push_back(GetDeclRef(DD->getOperatorDelete()));
}
OffsetsRecord.push_back(GetDeclRef(D));
DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
}
+void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD,
+ const FunctionDecl *Delete) {
+ assert(!WritingAST && "Already writing the AST!");
+ assert(Delete && "Not given an operator delete");
+ for (auto *D : DD->redecls()) {
+ if (D->isFromASTFile()) {
+ // We added an operator delete that some imported destructor didn't
+ // know about. Add an update record to let importers of us and that
+ // declaration know about it.
+ DeclUpdates[DD].push_back(
+ DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete));
+ return;
+ }
+ }
+}
+
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
assert(!WritingAST && "Already writing the AST!");
if (!D->isFromASTFile())
void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
VisitCXXMethodDecl(D);
- Writer.AddDeclRef(D->OperatorDelete, Record);
+ Writer.AddDeclRef(D->getOperatorDelete(), Record);
Code = serialization::DECL_CXX_DESTRUCTOR;
}
--- /dev/null
+struct X { X(); virtual ~X(); };
--- /dev/null
+struct X { X(); virtual ~X(); };
+inline X::~X() {}
+#include "a.h"
--- /dev/null
+module a { header "a.h" export * }
+module b { header "b.h" export * }
--- /dev/null
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x c++ -std=c++11 -fmodules-cache-path=%t -I %S/Inputs/cxx-dtor -emit-llvm-only %s
+#include "b.h"