Skip to content

Commit 222305d

Browse files
committed
PR51079: Treat thread_local variables with an incomplete class type as
being not trivially destructible when determining if we can skip calling their thread wrapper function.
1 parent 6448925 commit 222305d

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,19 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
334334
ArrayRef<llvm::Function *> CXXThreadLocalInits,
335335
ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
336336

337+
bool mayNeedDestruction(const VarDecl *VD) const {
338+
if (VD->needsDestruction(getContext()))
339+
return true;
340+
341+
// If the variable has an incomplete class type (or array thereof), it
342+
// might need destruction.
343+
const Type *T = VD->getType()->getBaseElementTypeUnsafe();
344+
if (T->getAs<RecordType>() && T->isIncompleteType())
345+
return true;
346+
347+
return false;
348+
}
349+
337350
/// Determine whether we will definitely emit this variable with a constant
338351
/// initializer, either because the language semantics demand it or because
339352
/// we know that the initializer is a constant.
@@ -364,7 +377,7 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
364377
// If we have the only definition, we don't need a thread wrapper if we
365378
// will emit the value as a constant.
366379
if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD)))
367-
return !VD->needsDestruction(getContext()) && InitDecl->evaluateValue();
380+
return !mayNeedDestruction(VD) && InitDecl->evaluateValue();
368381

369382
// Otherwise, we need a thread wrapper unless we know that every
370383
// translation unit will emit the value as a constant. We rely on the
@@ -376,7 +389,7 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
376389

377390
bool usesThreadWrapperFunction(const VarDecl *VD) const override {
378391
return !isEmittedWithConstantInitializer(VD) ||
379-
VD->needsDestruction(getContext());
392+
mayNeedDestruction(VD);
380393
}
381394
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
382395
QualType LValType) override;
@@ -2963,7 +2976,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
29632976
// also when the symbol is weak.
29642977
if (CGM.getTriple().isOSAIX() && VD->hasDefinition() &&
29652978
isEmittedWithConstantInitializer(VD, true) &&
2966-
!VD->needsDestruction(getContext())) {
2979+
!mayNeedDestruction(VD)) {
29672980
// Init should be null. If it were non-null, then the logic above would
29682981
// either be defining the function to be an alias or declaring the
29692982
// function with the expectation that the definition of the variable

clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ int get_c() { return c; }
5757

5858
thread_local int c = 0;
5959

60+
// PR51079: We must assume an incomplete class type might have non-trivial
61+
// destruction, and so speculatively call the thread wrapper.
62+
63+
// CHECK-LABEL: define {{.*}} @_Z6get_e3v(
64+
// CHECK: call {{.*}}* @_ZTW2e3()
65+
// CHECK-LABEL: }
66+
extern thread_local constinit struct DestructedFwdDecl e3;
67+
DestructedFwdDecl &get_e3() { return e3; }
68+
6069
int d_init();
6170

6271
// CHECK: define {{.*}}[[D_INIT:@__cxx_global_var_init[^(]*]](
@@ -84,3 +93,11 @@ thread_local constinit int f = 4;
8493
// CHECK-LABEL: define {{.*}}__tls_init
8594
// CHECK: call {{.*}} [[D_INIT]]
8695
// CHECK: call {{.*}} [[E2_INIT]]
96+
97+
// Because the call wrapper may be called speculatively (and simply because
98+
// it's required by the ABI), it must always be emitted for an external linkage
99+
// variable, even if the variable has constant initialization and constant
100+
// destruction.
101+
struct NotDestructed { int n = 0; };
102+
thread_local constinit NotDestructed nd;
103+
// CHECK-LABEL: define {{.*}} @_ZTW2nd

0 commit comments

Comments
 (0)