forked from OSchip/llvm-project
[modules] When emitting an update record containing the body of a destructor,
also emit the updated 'operator delete' looked up for that destructor. Switch from UpdateDecl to an actual update record when this happens due to implicitly defining a special member function and unify this code path and the one for instantiating a function definition. llvm-svn: 215132
This commit is contained in:
parent
54c340b76a
commit
4d2357948b
|
@ -25,8 +25,8 @@ enum DeclUpdateKind {
|
|||
UPD_CXX_ADDED_IMPLICIT_MEMBER,
|
||||
UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION,
|
||||
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
|
||||
UPD_CXX_ADDED_FUNCTION_DEFINITION,
|
||||
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
|
||||
UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION,
|
||||
UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
|
||||
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
|
||||
UPD_CXX_DEDUCED_RETURN_TYPE,
|
||||
|
|
|
@ -3273,7 +3273,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
|
|||
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
|
||||
break;
|
||||
|
||||
case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: {
|
||||
case UPD_CXX_ADDED_FUNCTION_DEFINITION: {
|
||||
FunctionDecl *FD = cast<FunctionDecl>(D);
|
||||
if (Reader.PendingBodies[FD]) {
|
||||
// FIXME: Maybe check for ODR violations.
|
||||
|
@ -3296,6 +3296,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
|
|||
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;
|
||||
|
|
|
@ -4629,17 +4629,17 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
|
|||
Record.push_back(GetDeclRef(Update.getDecl()));
|
||||
break;
|
||||
|
||||
case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
|
||||
AddSourceLocation(Update.getLoc(), Record);
|
||||
break;
|
||||
|
||||
case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION:
|
||||
case UPD_CXX_ADDED_FUNCTION_DEFINITION:
|
||||
// An updated body is emitted last, so that the reader doesn't need
|
||||
// to skip over the lazy body to reach statements for other records.
|
||||
Record.pop_back();
|
||||
HasUpdatedBody = true;
|
||||
break;
|
||||
|
||||
case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER:
|
||||
AddSourceLocation(Update.getLoc(), Record);
|
||||
break;
|
||||
|
||||
case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
|
||||
auto *RD = cast<CXXRecordDecl>(D);
|
||||
AddUpdatedDeclContext(RD->getPrimaryContext());
|
||||
|
@ -4709,10 +4709,12 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
|
|||
|
||||
if (HasUpdatedBody) {
|
||||
const FunctionDecl *Def = cast<FunctionDecl>(D);
|
||||
Record.push_back(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION);
|
||||
Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
|
||||
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));
|
||||
|
@ -5704,9 +5706,8 @@ void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
|
|||
if (!D->isFromASTFile())
|
||||
return; // Declaration not imported from PCH.
|
||||
|
||||
// Implicit decl from a PCH was defined.
|
||||
// FIXME: Should implicit definition be a separate FunctionDecl?
|
||||
RewriteDecl(D);
|
||||
// Implicit function decl from a PCH was defined.
|
||||
DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
|
||||
}
|
||||
|
||||
void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
|
||||
|
@ -5714,10 +5715,8 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
|
|||
if (!D->isFromASTFile())
|
||||
return;
|
||||
|
||||
// Since the actual instantiation is delayed, this really means that we need
|
||||
// to update the instantiation location.
|
||||
DeclUpdates[D].push_back(
|
||||
DeclUpdate(UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION));
|
||||
DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
|
||||
}
|
||||
|
||||
void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
|
||||
|
|
|
@ -18,3 +18,9 @@ namespace ImplicitSpecialMembers {
|
|||
C c2(c); D d2(d);
|
||||
}
|
||||
}
|
||||
|
||||
namespace OperatorDeleteLookup {
|
||||
// Trigger definition of A::~A() and lookup of operator delete.
|
||||
// Likewise for B<int>::~B().
|
||||
inline void f() { A a; B<int> b; }
|
||||
}
|
||||
|
|
|
@ -32,3 +32,9 @@ namespace ImplicitSpecialMembers {
|
|||
D(int);
|
||||
};
|
||||
}
|
||||
|
||||
namespace OperatorDeleteLookup {
|
||||
struct A { void operator delete(void*); virtual ~A() = default; };
|
||||
template<typename T> struct B { void operator delete(void*); virtual ~B() {} typedef int t; };
|
||||
typedef B<int>::t b_int_instantated;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ int b = h();
|
|||
// CHECK-DAG: define linkonce_odr {{signext i32|i32}} @_Z3minIiET_S0_S0_(i32
|
||||
int c = min(1, 2);
|
||||
|
||||
// CHECK-LABEL: define {{.*}} @_ZN20OperatorDeleteLookup1AD0Ev(
|
||||
// CHECK: call void @_ZN20OperatorDeleteLookup1AdlEPv(
|
||||
|
||||
namespace ImplicitSpecialMembers {
|
||||
// CHECK-LABEL: define {{.*}} @_ZN22ImplicitSpecialMembers1DC2EOS0_(
|
||||
// CHECK: call {{.*}} @_ZN22ImplicitSpecialMembers1AC1ERKS0_(
|
||||
|
@ -45,6 +48,12 @@ namespace ImplicitSpecialMembers {
|
|||
D d3(static_cast<D&&>(d1));
|
||||
}
|
||||
|
||||
namespace OperatorDeleteLookup {
|
||||
// Trigger emission of B's vtable and deleting dtor.
|
||||
// This requires us to know what operator delete was selected.
|
||||
void g() { f(); }
|
||||
}
|
||||
|
||||
// CHECK: define available_externally {{signext i32|i32}} @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align
|
||||
|
||||
// CHECK: attributes #[[ALWAYS_INLINE]] = {{.*}} alwaysinline
|
||||
|
|
Loading…
Reference in New Issue