CodeGen support for function-local static thread_local variables with
non-constant constructors or non-trivial destructors. Plus bugfixes for
thread_local references bound to temporaries (the temporaries themselves are
lifetime-extended to become thread_local), and the corresponding case for
std::initializer_list.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179496 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 0c0a76f..3bf6480 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -220,8 +220,12 @@
}
void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
+ const VarDecl &D,
llvm::Constant *dtor,
llvm::Constant *addr) {
+ if (D.getTLSKind())
+ CGM.ErrorUnsupported(&D, "non-trivial TLS destruction");
+
// The default behavior is to use atexit.
CGF.registerGlobalDtorWithAtExit(dtor, addr);
}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 702e59b..1f46f12 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -330,8 +330,8 @@
///
/// \param dtor - a function taking a single pointer argument
/// \param addr - a pointer to pass to the destructor function.
- virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
- llvm::Constant *addr);
+ virtual void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *dtor, llvm::Constant *addr);
};
// Create an instance of a C++ ABI class:
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 609f6aa..fd766bf 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -80,6 +80,7 @@
case QualType::DK_objc_strong_lifetime:
case QualType::DK_objc_weak_lifetime:
// We don't care about releasing objects during process teardown.
+ assert(!D.getTLSKind() && "should have rejected this");
return;
}
@@ -105,7 +106,7 @@
argument = llvm::Constant::getNullValue(CGF.Int8PtrTy);
}
- CGM.getCXXABI().registerGlobalDtor(CGF, function, argument);
+ CGM.getCXXABI().registerGlobalDtor(CGF, D, function, argument);
}
/// Emit code to cause the variable at the given address to be considered as
@@ -218,9 +219,6 @@
"this initialization requires a guard variable, which "
"the kernel does not support");
- if (D.getTLSKind())
- CGM.ErrorUnsupported(D.getInit(), "dynamic TLS initialization");
-
CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit);
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index c515508..1c06b7d 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -184,12 +184,16 @@
llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type);
// Create the reference temporary.
- llvm::GlobalValue *RefTemp =
+ llvm::GlobalVariable *RefTemp =
new llvm::GlobalVariable(CGF.CGM.getModule(),
RefTempTy, /*isConstant=*/false,
llvm::GlobalValue::InternalLinkage,
llvm::Constant::getNullValue(RefTempTy),
Name.str());
+ // If we're binding to a thread_local variable, the temporary is also
+ // thread local.
+ if (VD->getTLSKind())
+ CGF.CGM.setTLSMode(RefTemp, *VD);
return RefTemp;
}
}
@@ -434,12 +438,15 @@
CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
}
- CGM.getCXXABI().registerGlobalDtor(*this, CleanupFn, CleanupArg);
+ CGM.getCXXABI().registerGlobalDtor(*this, *VD, CleanupFn, CleanupArg);
} else if (ReferenceInitializerList) {
+ // FIXME: This is wrong. We need to register a global destructor to clean
+ // up the initializer_list object, rather than adding it as a local
+ // cleanup.
EmitStdInitializerListCleanup(ReferenceTemporary,
ReferenceInitializerList);
} else {
- assert(!ObjCARCReferenceLifetimeType.isNull());
+ assert(!ObjCARCReferenceLifetimeType.isNull() && !VD->getTLSKind());
// Note: We intentionally do not register a global "destructor" to
// release the object.
}
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 20532d6..f8627b2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1627,6 +1627,7 @@
D->getLocStart(), D->getLocation(),
name, arrayType, sourceInfo,
SC_Static);
+ backingArray->setTLSKind(D->getTLSKind());
// Now clone the InitListExpr to initialize the array instead.
// Incredible hack: we want to use the existing InitListExpr here, so we need
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index e25d422..25cd5f5 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -130,8 +130,8 @@
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr, bool PerformInit);
- void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
- llvm::Constant *addr);
+ void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *dtor, llvm::Constant *addr);
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -1042,10 +1042,10 @@
bool shouldPerformInit) {
CGBuilderTy &Builder = CGF.Builder;
- // We only need to use thread-safe statics for local variables;
+ // We only need to use thread-safe statics for local non-TLS variables;
// global initialization is always single-threaded.
- bool threadsafe =
- (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
+ bool threadsafe = getContext().getLangOpts().ThreadsafeStatics &&
+ D.isLocalVarDecl() && !D.getTLSKind();
// If we have a global variable with internal linkage and thread-safe statics
// are disabled, we can just let the guard variable be of type i8.
@@ -1080,6 +1080,8 @@
llvm::ConstantInt::get(guardTy, 0),
guardName.str());
guard->setVisibility(var->getVisibility());
+ // If the variable is thread-local, so is its guard variable.
+ guard->setThreadLocalMode(var->getThreadLocalMode());
CGM.setStaticLocalDeclGuardAddress(&D, guard);
}
@@ -1180,7 +1182,10 @@
/// Register a global destructor using __cxa_atexit.
static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
llvm::Constant *dtor,
- llvm::Constant *addr) {
+ llvm::Constant *addr,
+ bool TLS) {
+ const char *Name = TLS ? "__cxa_thread_atexit" : "__cxa_atexit";
+
// We're assuming that the destructor function is something we can
// reasonably call with the default CC. Go ahead and cast it to the
// right prototype.
@@ -1193,8 +1198,7 @@
llvm::FunctionType::get(CGF.IntTy, paramTys, false);
// Fetch the actual function.
- llvm::Constant *atexit =
- CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit");
+ llvm::Constant *atexit = CGF.CGM.CreateRuntimeFunction(atexitTy, Name);
if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit))
fn->setDoesNotThrow();
@@ -1212,12 +1216,15 @@
/// Register a global destructor as best as we know how.
void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
+ const VarDecl &D,
llvm::Constant *dtor,
llvm::Constant *addr) {
// Use __cxa_atexit if available.
- if (CGM.getCodeGenOpts().CXAAtExit) {
- return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr);
- }
+ if (CGM.getCodeGenOpts().CXAAtExit)
+ return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind());
+
+ if (D.getTLSKind())
+ CGM.ErrorUnsupported(&D, "non-trivial TLS destruction");
// In Apple kexts, we want to add a global destructor entry.
// FIXME: shouldn't this be guarded by some variable?
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 2c7f89a..a0e4f4d 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -392,6 +392,9 @@
// Not sure whether we want thread-safe static local variables as VS
// doesn't make them thread-safe.
+ if (D.getTLSKind())
+ CGM.ErrorUnsupported(&D, "dynamic TLS initialization");
+
// Emit the initializer and add a global destructor if appropriate.
CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
}