Skip to content

Commit 08a90c6

Browse files
committed
Fix issue with /Zc:dllexportInlines-
1 parent 3dc8666 commit 08a90c6

File tree

10 files changed

+103
-69
lines changed

10 files changed

+103
-69
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
382382
mutable llvm::DenseMap<const CXXDestructorDecl *, FunctionDecl *>
383383
GlobalArrayOperatorDeletesForVirtualDtor;
384384

385+
/// To remember which types did require a vector deleting dtor.
386+
llvm::DenseSet<const CXXRecordDecl *> RequireVectorDeletingDtor;
387+
385388
/// The next string literal "version" to allocate during constant evaluation.
386389
/// This is used to distinguish between repeated evaluations of the same
387390
/// string literal.
@@ -3494,6 +3497,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
34943497
OperatorDeleteKind K) const;
34953498
bool dtorHasOperatorDelete(const CXXDestructorDecl *Dtor,
34963499
OperatorDeleteKind K) const;
3500+
void setClassNeedsVectorDeletingDestructor(const CXXRecordDecl *RD);
3501+
bool classNeedsVectorDeletingDestructor(const CXXRecordDecl *RD);
34973502

34983503
/// Retrieve the context for computing mangling numbers in the given
34993504
/// DeclContext.

clang/lib/AST/ASTContext.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13402,6 +13402,26 @@ ASTContext::getOperatorDeleteForVDtor(const CXXDestructorDecl *Dtor,
1340213402
return nullptr;
1340313403
}
1340413404

13405+
bool ASTContext::classNeedsVectorDeletingDestructor(const CXXRecordDecl *RD) {
13406+
if (!getTargetInfo().emitVectorDeletingDtors(getLangOpts()))
13407+
return false;
13408+
CXXDestructorDecl *Dtor = RD->getDestructor();
13409+
// The compiler can't know if new[]/delete[] will be used outside of the DLL,
13410+
// so just force vector deleting destructor emission if dllexport is present.
13411+
// This matches MSVC behavior.
13412+
if (Dtor && Dtor->isVirtual() && Dtor->hasAttr<DLLExportAttr>())
13413+
return true;
13414+
13415+
return RequireVectorDeletingDtor.count(RD);
13416+
}
13417+
13418+
void ASTContext::setClassNeedsVectorDeletingDestructor(
13419+
const CXXRecordDecl *RD) {
13420+
if (!getTargetInfo().emitVectorDeletingDtors(getLangOpts()))
13421+
return;
13422+
RequireVectorDeletingDtor.insert(RD);
13423+
}
13424+
1340513425
MangleNumberingContext &
1340613426
ASTContext::getManglingNumberContext(const DeclContext *DC) {
1340713427
assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C.

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,16 +1206,6 @@ void CodeGenFunction::EmitNewArrayInitializer(
12061206
EmitCXXAggrConstructorCall(Ctor, NumElements, CurPtr, CCE,
12071207
/*NewPointerIsChecked*/true,
12081208
CCE->requiresZeroInitialization());
1209-
1210-
// For MSVC vector deleting destructors support we record that for the class
1211-
// new[] was called. We try to optimize the code size and only emit vector
1212-
// deleting destructors when they are required. Vector deleting destructors
1213-
// are required for delete[] call but MSVC triggers emission of them
1214-
// whenever new[] is called for an object of the class and we do the same
1215-
// for compatibility.
1216-
if (CGM.getContext().getTargetInfo().emitVectorDeletingDtors(
1217-
CGM.getContext().getLangOpts()))
1218-
CGM.requireVectorDestructorDefinition(Ctor->getParent());
12191209
return;
12201210
}
12211211

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8323,53 +8323,3 @@ void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) {
83238323

83248324
NewBuilder->ABI->MangleCtx = std::move(ABI->MangleCtx);
83258325
}
8326-
8327-
bool CodeGenModule::classNeedsVectorDestructor(const CXXRecordDecl *RD) {
8328-
if (!Context.getTargetInfo().emitVectorDeletingDtors(Context.getLangOpts()))
8329-
return false;
8330-
CXXDestructorDecl *Dtor = RD->getDestructor();
8331-
// The compiler can't know if new[]/delete[] will be used outside of the DLL,
8332-
// so just force vector deleting destructor emission if dllexport is present.
8333-
// This matches MSVC behavior.
8334-
if (Dtor && Dtor->isVirtual() && Dtor->isDefined() &&
8335-
Dtor->hasAttr<DLLExportAttr>())
8336-
return true;
8337-
8338-
return RequireVectorDeletingDtor.count(RD);
8339-
}
8340-
8341-
void CodeGenModule::requireVectorDestructorDefinition(const CXXRecordDecl *RD) {
8342-
if (!Context.getTargetInfo().emitVectorDeletingDtors(Context.getLangOpts()))
8343-
return;
8344-
RequireVectorDeletingDtor.insert(RD);
8345-
8346-
// To reduce code size in general case we lazily emit scalar deleting
8347-
// destructor definition and an alias from vector deleting destructor to
8348-
// scalar deleting destructor. It may happen that we first emitted the scalar
8349-
// deleting destructor definition and the alias and then discovered that the
8350-
// definition of the vector deleting destructor is required. Then we need to
8351-
// remove the alias and the scalar deleting destructor and queue vector
8352-
// deleting destructor body for emission. Check if that is the case.
8353-
CXXDestructorDecl *DtorD = RD->getDestructor();
8354-
GlobalDecl ScalarDtorGD(DtorD, Dtor_Deleting);
8355-
StringRef MangledName = getMangledName(ScalarDtorGD);
8356-
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
8357-
if (Entry && !Entry->isDeclaration()) {
8358-
GlobalDecl VectorDtorGD(DtorD, Dtor_VectorDeleting);
8359-
StringRef VDName = getMangledName(VectorDtorGD);
8360-
llvm::GlobalValue *VDEntry = GetGlobalValue(VDName);
8361-
// It exists and it should be an alias.
8362-
assert(VDEntry && isa<llvm::GlobalAlias>(VDEntry));
8363-
auto *NewFn = llvm::Function::Create(
8364-
cast<llvm::FunctionType>(VDEntry->getValueType()),
8365-
llvm::Function::ExternalLinkage, VDName, &getModule());
8366-
SetFunctionAttributes(VectorDtorGD, NewFn, /*IsIncompleteFunction*/ false,
8367-
/*IsThunk*/ false);
8368-
NewFn->takeName(VDEntry);
8369-
VDEntry->replaceAllUsesWith(NewFn);
8370-
VDEntry->eraseFromParent();
8371-
Entry->replaceAllUsesWith(NewFn);
8372-
Entry->eraseFromParent();
8373-
addDeferredDeclToEmit(VectorDtorGD);
8374-
}
8375-
}

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -529,9 +529,6 @@ class CodeGenModule : public CodeGenTypeCache {
529529
/// that we don't re-emit the initializer.
530530
llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition;
531531

532-
/// To remember which types did require a vector deleting dtor.
533-
llvm::SmallPtrSet<const CXXRecordDecl *, 16> RequireVectorDeletingDtor;
534-
535532
typedef std::pair<OrderGlobalInitsOrStermFinalizers, llvm::Function *>
536533
GlobalInitData;
537534

@@ -1828,8 +1825,6 @@ class CodeGenModule : public CodeGenTypeCache {
18281825
// behavior. So projects like the Linux kernel can rely on it.
18291826
return !getLangOpts().CPlusPlus;
18301827
}
1831-
void requireVectorDestructorDefinition(const CXXRecordDecl *RD);
1832-
bool classNeedsVectorDestructor(const CXXRecordDecl *RD);
18331828

18341829
// Helper to get the alignment for a variable.
18351830
unsigned getVtableGlobalVarAlignment(const VarDecl *D = nullptr) {

clang/lib/CodeGen/MicrosoftCXXABI.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4105,7 +4105,7 @@ void MicrosoftCXXABI::emitCXXStructor(GlobalDecl GD) {
41054105
return;
41064106

41074107
if (GD.getDtorType() == Dtor_VectorDeleting &&
4108-
!CGM.classNeedsVectorDestructor(dtor->getParent())) {
4108+
!getContext().classNeedsVectorDeletingDestructor(dtor->getParent())) {
41094109
// Create GlobalDecl object with the correct type for the scalar
41104110
// deleting destructor.
41114111
GlobalDecl ScalarDtorGD(dtor, Dtor_Deleting);

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11193,6 +11193,7 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
1119311193
FindDeallocationFunctionForDestructor(Loc, RD, /*Diagnose*/ false,
1119411194
/*LookForGlobal*/ true, Name);
1119511195
Destructor->setOperatorGlobalDelete(GlobalOperatorDelete);
11196+
MarkFunctionReferenced(Loc, GlobalOperatorDelete);
1119611197
}
1119711198

1119811199
if (Context.getTargetInfo().emitVectorDeletingDtors(
@@ -11209,6 +11210,8 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
1120911210
/*LookForGlobal*/ true,
1121011211
VDeleteName);
1121111212
Destructor->setGlobalOperatorArrayDelete(GlobalArrOperatorDelete);
11213+
if (Context.classNeedsVectorDeletingDestructor(RD))
11214+
MarkFunctionReferenced(Loc, GlobalArrOperatorDelete);
1121211215
} else if (!ArrOperatorDelete) {
1121311216
ArrOperatorDelete = FindDeallocationFunctionForDestructor(
1121411217
Loc, RD, /*Diagnose*/ false,
@@ -11217,6 +11220,8 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
1121711220
assert(ArrOperatorDelete &&
1121811221
"Should've found at least global array delete");
1121911222
Destructor->setOperatorArrayDelete(ArrOperatorDelete);
11223+
if (Context.classNeedsVectorDeletingDestructor(RD))
11224+
MarkFunctionReferenced(Loc, ArrOperatorDelete);
1122011225
}
1122111226
}
1122211227
}

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,6 +2631,19 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
26312631
MarkFunctionReferenced(StartLoc, OperatorDelete);
26322632
}
26332633

2634+
// For MSVC vector deleting destructors support we record that for the class
2635+
// new[] was called. We try to optimize the code size and only emit vector
2636+
// deleting destructors when they are required. Vector deleting destructors
2637+
// are required for delete[] call but MSVC triggers emission of them
2638+
// whenever new[] is called for an object of the class and we do the same
2639+
// for compatibility.
2640+
if (const CXXConstructExpr *CCE =
2641+
dyn_cast_or_null<CXXConstructExpr>(Initializer);
2642+
CCE && ArraySize) {
2643+
Context.setClassNeedsVectorDeletingDestructor(
2644+
CCE->getConstructor()->getParent());
2645+
}
2646+
26342647
return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
26352648
IAP, UsualArrayDeleteWantsSize, PlacementArgs,
26362649
TypeIdParens, ArraySize, InitStyle, Initializer,
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// RUN: %clang_cc1 -emit-llvm -fms-extensions -fms-compatibility -fno-dllexport-inlines %s -triple=x86_64-pc-windows-msvc -o - | FileCheck --check-prefixes=X64,CHECK %s
2+
// RUN: %clang_cc1 -emit-llvm -fms-extensions -fms-compatibility -fno-dllexport-inlines %s -triple=i386-pc-windows-msvc -o - | FileCheck --check-prefixes=X86,CHECK %s
3+
4+
// Check that vector deleting destructor does not reference undefined symbols.
5+
6+
void operator delete(void*, size_t) {}
7+
void operator delete[](void*, size_t) {}
8+
9+
template <typename T> struct RefCounted {
10+
void operator delete[](void *p) { }
11+
};
12+
13+
struct __declspec(dllexport) DrawingBuffer : public RefCounted<DrawingBuffer> {
14+
DrawingBuffer();
15+
virtual ~DrawingBuffer();
16+
};
17+
18+
DrawingBuffer::DrawingBuffer() {}
19+
DrawingBuffer::~DrawingBuffer() {}
20+
21+
struct NoExport : public RefCounted<NoExport> {
22+
NoExport();
23+
virtual ~NoExport();
24+
};
25+
26+
NoExport::NoExport() {}
27+
NoExport::~NoExport() {}
28+
29+
// X64: define dso_local void @"??3@YAXPEAX_K@Z"(ptr noundef %0, i64 noundef %1)
30+
// X64: define dso_local void @"??_V@YAXPEAX_K@Z"(ptr noundef %0, i64 noundef %1)
31+
// X64: define dso_local dllexport void @"??1DrawingBuffer@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %this)
32+
33+
// X64: define weak dso_local noundef ptr @"??_EDrawingBuffer@@UEAAPEAXI@Z"
34+
// X64: call void @"??1DrawingBuffer@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
35+
// X64: call void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPEAX@Z"(ptr noundef %2) #2
36+
// X64: call void @"??_V@YAXPEAX_K@Z"(ptr noundef %2, i64 noundef 8) #3
37+
// X64: call void @"??1DrawingBuffer@@UEAA@XZ"(ptr noundef nonnull align 8 dereferenceable(8) %this1)
38+
// X64: call void @"??3@YAXPEAX_K@Z"(ptr noundef %this1, i64 noundef 8) #3
39+
40+
// X64: define linkonce_odr dso_local void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPEAX@Z"(ptr noundef %p)
41+
42+
// X86: define dso_local void @"??3@YAXPAXI@Z"(ptr noundef %0, i32 noundef %1)
43+
// X86: define dso_local void @"??_V@YAXPAXI@Z"(ptr noundef %0, i32 noundef %1)
44+
45+
// X86: define weak dso_local x86_thiscallcc noundef ptr @"??_EDrawingBuffer@@UAEPAXI@Z"
46+
// X86: call x86_thiscallcc void @"??1DrawingBuffer@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %arraydestroy.element)
47+
// X86: call void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPAX@Z"(ptr noundef %2)
48+
// X86: call void @"??_V@YAXPAXI@Z"(ptr noundef %2, i32 noundef 4)
49+
// X86 call x86_thiscallcc void @"??1DrawingBuffer@@UAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %this1)
50+
// X86: call void @"??3@YAXPAXI@Z"(ptr noundef %this1, i32 noundef 4)
51+
52+
// X86: define linkonce_odr dso_local void @"??_V?$RefCounted@UDrawingBuffer@@@@SAXPAX@Z"(ptr noundef %p)
53+
54+
// X86: define linkonce_odr dso_local x86_thiscallcc noundef ptr @"??_GNoExport@@UAEPAXI@Z"(ptr noundef nonnull align 4 dereferenceable(4) %this, i32 noundef %should_call_delete)
55+
// X64: define linkonce_odr dso_local noundef ptr @"??_GNoExport@@UEAAPEAXI@Z"(ptr noundef nonnull align 8 dereferenceable(8) %this, i32 noundef %should_call_delete)
56+
// CHECK-NOT: define {{.*}}_V{{.*}}NoExport

clang/test/DebugInfo/CXX/ms-dtor-thunks.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ struct __declspec(dllexport) S { virtual ~S(); };
55
struct __declspec(dllexport) T { virtual ~T(); };
66
struct __declspec(dllexport) U : S, T { virtual ~U(); };
77

8-
// CHECK-LABEL: define {{.*}} @"??_GS@@UAEPAXI@Z"
8+
// CHECK-LABEL: define {{.*}} @"??_ES@@UAEPAXI@Z"
99
// CHECK: call x86_thiscallcc void @"??1S@@UAE@XZ"(ptr {{[^,]*}} %this1){{.*}}!dbg !{{[0-9]+}}
1010

11-
// CHECK-LABEL: define {{.*}} @"??_GT@@UAEPAXI@Z"
11+
// CHECK-LABEL: define {{.*}} @"??_ET@@UAEPAXI@Z"
1212
// CHECK: call x86_thiscallcc void @"??1T@@UAE@XZ"(ptr {{[^,]*}} %this1){{.*}}!dbg !{{[0-9]+}}
1313

14-
// CHECK-LABEL: define {{.*}} @"??_GU@@UAEPAXI@Z"
14+
// CHECK-LABEL: define {{.*}} @"??_EU@@UAEPAXI@Z"
1515
// CHECK: call x86_thiscallcc void @"??1U@@UAE@XZ"(ptr {{[^,]*}} %this1){{.*}}!dbg !{{[0-9]+}}

0 commit comments

Comments
 (0)