From: Richard Smith Date: Wed, 26 Mar 2014 22:48:22 +0000 (+0000) Subject: PR19254: If a thread_local data member of a class is accessed via member access X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cb77c78fdae5959b89d3c437722a56666d7fdb81;p=clang PR19254: If a thread_local data member of a class is accessed via member access syntax, don't forget to run its initializer. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@204869 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 72b84dc3e9..3d0eaa0914 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -280,8 +280,9 @@ void CGCXXABI::EmitThreadLocalInitFuncs( llvm::Function *InitFunc) { } -LValue CGCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, - const DeclRefExpr *DRE) { +LValue CGCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, + const VarDecl *VD, + QualType LValType) { ErrorUnsupportedABI(CGF, "odr-use of thread_local global"); return LValue(); } diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index ea308f0ba4..783cc59436 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -481,8 +481,9 @@ public: /// Emit a reference to a non-local thread_local variable (including /// triggering the initialization of all thread_local variables in its /// translation unit). - virtual LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, - const DeclRefExpr *DRE); + virtual LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, + const VarDecl *VD, + QualType LValType); }; // Create an instance of a C++ ABI class: diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 5ba748a88d..1bdd094873 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1691,11 +1691,16 @@ EmitBitCastOfLValueToProperType(CodeGenFunction &CGF, static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, const Expr *E, const VarDecl *VD) { + QualType T = E->getType(); + + // If it's thread_local, emit a call to its wrapper function instead. + if (VD->getTLSKind() == VarDecl::TLS_Dynamic) + return CGF.CGM.getCXXABI().EmitThreadLocalVarDeclLValue(CGF, VD, T); + llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD); llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType()); V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy); CharUnits Alignment = CGF.getContext().getDeclAlign(VD); - QualType T = E->getType(); LValue LV; if (VD->getType()->isReferenceType()) { llvm::LoadInst *LI = CGF.Builder.CreateLoad(V); @@ -1703,7 +1708,7 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, V = LI; LV = CGF.MakeNaturalAlignAddrLValue(V, T); } else { - LV = CGF.MakeAddrLValue(V, E->getType(), Alignment); + LV = CGF.MakeAddrLValue(V, T, Alignment); } setObjCGCLValueClass(CGF.getContext(), E, LV); return LV; @@ -1770,12 +1775,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (const VarDecl *VD = dyn_cast(ND)) { // Check if this is a global variable. - if (VD->hasLinkage() || VD->isStaticDataMember()) { - // If it's thread_local, emit a call to its wrapper function instead. - if (VD->getTLSKind() == VarDecl::TLS_Dynamic) - return CGM.getCXXABI().EmitThreadLocalDeclRefExpr(*this, E); + if (VD->hasLinkage() || VD->isStaticDataMember()) return EmitGlobalVarDeclLValue(*this, E, VD); - } bool isBlockVariable = VD->hasAttr(); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 7390a2113b..9a2076d95a 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -214,8 +214,8 @@ public: void EmitThreadLocalInitFuncs( llvm::ArrayRef > Decls, llvm::Function *InitFunc) override; - LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, - const DeclRefExpr *DRE) override; + LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, + QualType LValType) override; bool NeedsVTTParameter(GlobalDecl GD) override; }; @@ -1647,9 +1647,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( } } -LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, - const DeclRefExpr *DRE) { - const VarDecl *VD = cast(DRE->getDecl()); +LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, + const VarDecl *VD, + QualType LValType) { QualType T = VD->getType(); llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T); llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty); @@ -1660,10 +1660,9 @@ LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF, LValue LV; if (VD->getType()->isReferenceType()) - LV = CGF.MakeNaturalAlignAddrLValue(Val, T); + LV = CGF.MakeNaturalAlignAddrLValue(Val, LValType); else - LV = CGF.MakeAddrLValue(Val, DRE->getType(), - CGF.getContext().getDeclAlign(VD)); + LV = CGF.MakeAddrLValue(Val, LValType, CGF.getContext().getDeclAlign(VD)); // FIXME: need setObjCGCLValueClass? return LV; } diff --git a/test/CodeGenCXX/cxx11-thread-local.cpp b/test/CodeGenCXX/cxx11-thread-local.cpp index 509562dd8f..86734cd79c 100644 --- a/test/CodeGenCXX/cxx11-thread-local.cpp +++ b/test/CodeGenCXX/cxx11-thread-local.cpp @@ -135,6 +135,16 @@ int PR15991() { return l(); } +struct PR19254 { + static thread_local int n; + int f(); +}; +// CHECK: define {{.*}} @_ZN7PR192541fEv( +int PR19254::f() { + // CHECK: call void @_ZTHN7PR192541nE( + return this->n; +} + // CHECK: define {{.*}} @[[V_M_INIT:.*]]() // CHECK: load i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*) // CHECK: %[[V_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0