From 942f9fe11d3a9583eef6bc4ca2549b1f0d1694da Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 10 Sep 2013 20:14:30 +0000 Subject: [PATCH] [ms-cxxabi] Implement guard variables for static initialization Static locals requiring initialization are not thread safe on Windows. Unfortunately, it's possible to create static locals that are actually externally visible with inline functions and templates. As a result, we have to implement an initialization guard scheme that is compatible with TUs built by MSVC, which makes thread safety prohibitively difficult. MSVC's scheme is that every function that requires a guard gets an i32 bitfield. Each static local is assigned a bit that indicates if it has been initialized, up to 32 bits, at which point a new bitfield is created. MSVC rejects inline functions with more than 32 static locals, and the externally visible mangling (?_B) only allows for one guard variable per function. On Eli's recommendation, I used MangleNumberingContext to track which bit each static corresponds to. Implements PR16888. Reviewers: rjmccall, eli.friedman Differential Revision: http://llvm-reviews.chandlerc.com/D1416 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190427 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 6 +- include/clang/AST/Mangle.h | 10 +- include/clang/AST/MangleNumberingContext.h | 5 +- include/clang/Sema/Sema.h | 7 +- lib/AST/ASTContext.cpp | 17 ++- lib/AST/CXXABI.h | 8 +- lib/AST/ItaniumCXXABI.cpp | 18 +++ lib/AST/ItaniumMangle.cpp | 18 ++- lib/AST/MangleNumberingContext.cpp | 5 - lib/AST/MicrosoftCXXABI.cpp | 21 ++++ lib/AST/MicrosoftMangle.cpp | 41 ++++++- lib/CodeGen/CGCXXABI.cpp | 7 -- lib/CodeGen/CGCXXABI.h | 3 +- lib/CodeGen/CGDeclCXX.cpp | 8 +- lib/CodeGen/ItaniumCXXABI.cpp | 2 +- lib/CodeGen/MicrosoftCXXABI.cpp | 93 ++++++++++++++- lib/Sema/SemaDecl.cpp | 5 +- lib/Sema/SemaLambda.cpp | 12 +- .../debug-info-global-ctor-dtor.cpp | 2 +- .../microsoft-abi-static-initializers.cpp | 111 ++++++++++++++++-- 20 files changed, 342 insertions(+), 57 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 377282ff65..107b5f1fc0 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -19,7 +19,6 @@ #include "clang/AST/CanonicalType.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/Decl.h" -#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/RawCommentList.h" @@ -59,6 +58,7 @@ namespace clang { class SelectorTable; class TargetInfo; class CXXABI; + class MangleNumberingContext; // Decls class MangleContext; class ObjCIvarDecl; @@ -353,7 +353,7 @@ private: /// \brief Mapping from each declaration context to its corresponding /// mangling numbering context (used for constructs like lambdas which /// need to be consistently numbered for the mangler). - llvm::DenseMap + llvm::DenseMap MangleNumberingContexts; /// \brief Side-table of mangling numbers for declarations which rarely @@ -2119,6 +2119,8 @@ public: /// DeclContext. MangleNumberingContext &getManglingNumberContext(const DeclContext *DC); + MangleNumberingContext *createMangleNumberingContext() const; + /// \brief Used by ParmVarDecl to store on the side the /// index of the parameter when it exceeds the size of the normal bitfield. void setParameterIndex(const ParmVarDecl *D, unsigned index); diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h index c13cd257d9..f6aa2fc976 100644 --- a/include/clang/AST/Mangle.h +++ b/include/clang/AST/Mangle.h @@ -139,11 +139,11 @@ public: void mangleObjCMethodName(const ObjCMethodDecl *MD, raw_ostream &); - // This is pretty lame. - virtual void mangleItaniumGuardVariable(const VarDecl *D, - raw_ostream &) { - llvm_unreachable("Target does not support mangling guard variables"); - } + virtual void mangleStaticGuardVariable(const VarDecl *D, + raw_ostream &Out) = 0; + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) = 0; + // FIXME: Revisit this once we know what we need to do for MSVC compatibility. virtual void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) { diff --git a/include/clang/AST/MangleNumberingContext.h b/include/clang/AST/MangleNumberingContext.h index 4f81e0c554..5a227f201f 100644 --- a/include/clang/AST/MangleNumberingContext.h +++ b/include/clang/AST/MangleNumberingContext.h @@ -33,10 +33,11 @@ class VarDecl; class MangleNumberingContext : public RefCountedBase { llvm::DenseMap ManglingNumbers; - llvm::DenseMap VarManglingNumbers; llvm::DenseMap TagManglingNumbers; public: + virtual ~MangleNumberingContext() {} + /// \brief Retrieve the mangling number of a new lambda expression with the /// given call operator within this context. unsigned getManglingNumber(const CXXMethodDecl *CallOperator); @@ -47,7 +48,7 @@ public: /// \brief Retrieve the mangling number of a static local variable within /// this context. - unsigned getManglingNumber(const VarDecl *VD); + virtual unsigned getManglingNumber(const VarDecl *VD) = 0; /// \brief Retrieve the mangling number of a static local variable within /// this context. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 885e7325ca..bcae1037ad 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -703,12 +703,7 @@ public: /// \brief Retrieve the mangling numbering context, used to consistently /// number constructs like lambdas for mangling. - MangleNumberingContext &getMangleNumberingContext() { - assert(ManglingContextDecl && "Need to have a context declaration"); - if (!MangleNumbering) - MangleNumbering = new MangleNumberingContext; - return *MangleNumbering; - } + MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx); bool isUnevaluated() const { return Context == Unevaluated || Context == UnevaluatedAbstract; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 85ac734a45..4ab987d844 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -25,6 +25,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Mangle.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" @@ -766,6 +767,12 @@ ASTContext::~ASTContext() { AEnd = DeclAttrs.end(); A != AEnd; ++A) A->second->~AttrVec(); + + for (llvm::DenseMap::iterator + I = MangleNumberingContexts.begin(), + E = MangleNumberingContexts.end(); + I != E; ++I) + delete I->second; } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { @@ -8037,7 +8044,15 @@ unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const { MangleNumberingContext & ASTContext::getManglingNumberContext(const DeclContext *DC) { - return MangleNumberingContexts[DC]; + assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C. + MangleNumberingContext *&MCtx = MangleNumberingContexts[DC]; + if (!MCtx) + MCtx = createMangleNumberingContext(); + return *MCtx; +} + +MangleNumberingContext *ASTContext::createMangleNumberingContext() const { + return ABI->createMangleNumberingContext(); } void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 6d67d9a12b..89203f18ca 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -21,6 +21,7 @@ namespace clang { class ASTContext; class MemberPointerType; +class MangleNumberingContext; /// Implements C++ ABI-specific semantic analysis functions. class CXXABI { @@ -34,9 +35,12 @@ public: /// Returns the default calling convention for C++ methods. virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0; - // Returns whether the given class is nearly empty, with just virtual pointers - // and no data except possibly virtual bases. + /// Returns whether the given class is nearly empty, with just virtual + /// pointers and no data except possibly virtual bases. virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0; + + /// Returns a new mangling number context for this C++ ABI. + virtual MangleNumberingContext *createMangleNumberingContext() const = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index 894eb3bff5..578466028c 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -20,6 +20,7 @@ #include "CXXABI.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -27,6 +28,19 @@ using namespace clang; namespace { + +/// \brief Keeps track of the mangled names of lambda expressions and block +/// literals within a particular context. +class ItaniumNumberingContext : public MangleNumberingContext { + llvm::DenseMap VarManglingNumbers; + +public: + /// Variable decls are numbered by identifier. + virtual unsigned getManglingNumber(const VarDecl *VD) { + return ++VarManglingNumbers[VD->getIdentifier()]; + } +}; + class ItaniumCXXABI : public CXXABI { protected: ASTContext &Context; @@ -61,6 +75,10 @@ public: Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize; } + + virtual MangleNumberingContext *createMangleNumberingContext() const { + return new ItaniumNumberingContext(); + } }; class ARMCXXABI : public ItaniumCXXABI { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index c3121c0b53..1d8a311c61 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -152,7 +152,8 @@ public: void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &); + void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &); + void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out); void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &); void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &); @@ -3691,8 +3692,8 @@ ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, /// mangleGuardVariable - Returns the mangled name for a guard variable /// for the passed in VarDecl. -void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, - raw_ostream &Out) { +void ItaniumMangleContext::mangleStaticGuardVariable(const VarDecl *D, + raw_ostream &Out) { // ::= GV # Guard variable for one-time // # initialization CXXNameMangler Mangler(*this, Out); @@ -3700,6 +3701,17 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, Mangler.mangleName(D); } +void ItaniumMangleContext::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // Prefix the mangling of D with __dtor_. + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "__dtor_"; + if (shouldMangleDeclName(D)) + Mangler.mangle(D); + else + Mangler.getStream() << D->getName(); +} + void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &Out) { // ::= TH diff --git a/lib/AST/MangleNumberingContext.cpp b/lib/AST/MangleNumberingContext.cpp index 4e9006ec24..91ef0e2240 100644 --- a/lib/AST/MangleNumberingContext.cpp +++ b/lib/AST/MangleNumberingContext.cpp @@ -37,11 +37,6 @@ MangleNumberingContext::getManglingNumber(const BlockDecl *BD) { return ++ManglingNumbers[Ty]; } -unsigned -MangleNumberingContext::getManglingNumber(const VarDecl *VD) { - return ++VarManglingNumbers[VD->getIdentifier()]; -} - unsigned MangleNumberingContext::getManglingNumber(const TagDecl *TD) { return ++TagManglingNumbers[TD->getIdentifier()]; diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index fd932f7330..4a93ea1f41 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -23,6 +24,22 @@ using namespace clang; namespace { + +/// \brief Numbers things which need to correspond across multiple TUs. +/// Typically these are things like static locals, lambdas, or blocks. +class MicrosoftNumberingContext : public MangleNumberingContext { + unsigned NumStaticLocals; + +public: + MicrosoftNumberingContext() : NumStaticLocals(0) { } + + /// Static locals are numbered by source order. + virtual unsigned getManglingNumber(const VarDecl *VD) { + assert(VD->isStaticLocal()); + return ++NumStaticLocals; + } +}; + class MicrosoftCXXABI : public CXXABI { ASTContext &Context; public: @@ -51,6 +68,10 @@ public: return Layout.getNonVirtualSize() == PointerSize || Layout.getNonVirtualSize() == PointerSize * 2; } + + MangleNumberingContext *createMangleNumberingContext() const { + return new MicrosoftNumberingContext(); + } }; } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 78fa543979..7e3d6c2139 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -92,6 +92,7 @@ public: QualifierMangleMode QMM = QMM_Mangle); void mangleFunctionType(const FunctionType *T, const FunctionDecl *D, bool IsStructor, bool IsInstMethod); + void manglePostfix(const DeclContext *DC, bool NoFunction = false); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -100,7 +101,6 @@ private: } void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); void mangleSourceName(const IdentifierInfo *II); - void manglePostfix(const DeclContext *DC, bool NoFunction=false); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleCXXDtorType(CXXDtorType T); void mangleQualifiers(Qualifiers Quals, bool IsMember); @@ -168,8 +168,10 @@ public: raw_ostream &); virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &); - virtual void mangleReferenceTemporary(const clang::VarDecl *, - raw_ostream &); + virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &); + virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out); + virtual void mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out); }; } @@ -1912,13 +1914,44 @@ void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, MicrosoftCXXNameMangler mangler(*this, Out, D, Type); mangler.mangle(D); } -void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD, +void MicrosoftMangleContext::mangleReferenceTemporary(const VarDecl *VD, raw_ostream &) { unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this reference temporary yet"); getDiags().Report(VD->getLocation(), DiagID); } +void MicrosoftMangleContext::mangleStaticGuardVariable(const VarDecl *VD, + raw_ostream &Out) { + // ::= ?_B @51 + // ::= ?$S @ @4IA + + // The first mangling is what MSVC uses to guard static locals in inline + // functions. It uses a different mangling in external functions to support + // guarding more than 32 variables. MSVC rejects inline functions with more + // than 32 static locals. We don't fully implement the second mangling + // because those guards are not externally visible, and instead use LLVM's + // default renaming when creating a new guard variable. + MicrosoftCXXNameMangler Mangler(*this, Out); + + bool Visible = VD->isExternallyVisible(); + // ::= ?_B # local static guard + Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@"); + Mangler.manglePostfix(VD->getDeclContext()); + Mangler.getStream() << (Visible ? "@51" : "@4IA"); +} + +void MicrosoftMangleContext::mangleDynamicAtExitDestructor(const VarDecl *D, + raw_ostream &Out) { + // ::= ?__F YAXXZ + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "\01??__F"; + Mangler.mangleName(D); + // This is the mangling of the function type of the stub, which is a global, + // non-variadic, cdecl function that returns void and takes no args. + Mangler.getStream() << "YAXXZ"; +} + MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, DiagnosticsEngine &Diags) { return new MicrosoftMangleContext(Context, Diags); diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index fe779800ac..53e7e636ab 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -212,13 +212,6 @@ llvm::Value *CGCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, return llvm::ConstantInt::get(CGF.SizeTy, 0); } -void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, - const VarDecl &D, - llvm::GlobalVariable *GV, - bool PerformInit) { - ErrorUnsupportedABI(CGF, "static local variable initialization"); -} - void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D, llvm::Constant *dtor, diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 5baedfba1a..37f678f4b5 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -413,7 +413,8 @@ public: /// - a static local variable /// - a static data member of a class template instantiation virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr, bool PerformInit); + llvm::GlobalVariable *DeclPtr, + bool PerformInit) = 0; /// Emit code to force the execution of a destructor during global /// teardown. The default implementation of this uses atexit. diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 868820a081..2417873858 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -166,9 +166,13 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM, const VarDecl &VD, llvm::Constant *addr) { // Get the destructor function type, void(*)(void). llvm::FunctionType *ty = llvm::FunctionType::get(CGM.VoidTy, false); + SmallString<256> FnName; + { + llvm::raw_svector_ostream Out(FnName); + CGM.getCXXABI().getMangleContext().mangleDynamicAtExitDestructor(&VD, Out); + } llvm::Function *fn = - CreateGlobalInitOrDestructFunction(CGM, ty, - Twine("__dtor_", addr->getName())); + CreateGlobalInitOrDestructFunction(CGM, ty, FnName.str()); CodeGenFunction CGF(CGM); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 980face217..b08e9b7462 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -1142,7 +1142,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, SmallString<256> guardName; { llvm::raw_svector_ostream out(guardName); - getMangleContext().mangleItaniumGuardVariable(&D, out); + getMangleContext().mangleStaticGuardVariable(&D, out); out.flush(); } diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 837a536631..e5d7c49a64 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -305,6 +305,18 @@ public: private: /// VBTables - All the vbtables which have been referenced. llvm::DenseMap VBTablesMap; + + /// Info on the global variable used to guard initialization of static locals. + /// The BitIndex field is only used for externally invisible declarations. + struct GuardInfo { + GuardInfo() : Guard(0), BitIndex(0) {} + llvm::GlobalVariable *Guard; + unsigned BitIndex; + }; + + /// Map from DeclContext to the current guard variable. We assume that the + /// AST is visited in source code order. + llvm::DenseMap GuardVariableMap; }; } @@ -727,17 +739,86 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, } void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *DeclPtr, + llvm::GlobalVariable *GV, bool PerformInit) { - // FIXME: this code was only tested for global initialization. - // Not sure whether we want thread-safe static local variables as VS - // doesn't make them thread-safe. + // MSVC always uses an i32 bitfield to guard initialization, which is *not* + // threadsafe. Since the user may be linking in inline functions compiled by + // cl.exe, there's no reason to provide a false sense of security by using + // critical sections here. if (D.getTLSKind()) CGM.ErrorUnsupported(&D, "dynamic TLS initialization"); - // Emit the initializer and add a global destructor if appropriate. - CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); + CGBuilderTy &Builder = CGF.Builder; + llvm::IntegerType *GuardTy = CGF.Int32Ty; + llvm::ConstantInt *Zero = llvm::ConstantInt::get(GuardTy, 0); + + // Get the guard variable for this function if we have one already. + GuardInfo &GI = GuardVariableMap[D.getDeclContext()]; + + unsigned BitIndex; + if (D.isExternallyVisible()) { + // Externally visible variables have to be numbered in Sema to properly + // handle unreachable VarDecls. + BitIndex = getContext().getManglingNumber(&D); + assert(BitIndex > 0); + BitIndex--; + } else { + // Non-externally visible variables are numbered here in CodeGen. + BitIndex = GI.BitIndex++; + } + + if (BitIndex >= 32) { + if (D.isExternallyVisible()) + ErrorUnsupportedABI(CGF, "more than 32 guarded initializations"); + BitIndex %= 32; + GI.Guard = 0; + } + + // Lazily create the i32 bitfield for this function. + if (!GI.Guard) { + // Mangle the name for the guard. + SmallString<256> GuardName; + { + llvm::raw_svector_ostream Out(GuardName); + getMangleContext().mangleStaticGuardVariable(&D, Out); + Out.flush(); + } + + // Create the guard variable with a zero-initializer. Just absorb linkage + // and visibility from the guarded variable. + GI.Guard = new llvm::GlobalVariable(CGM.getModule(), GuardTy, false, + GV->getLinkage(), Zero, GuardName.str()); + GI.Guard->setVisibility(GV->getVisibility()); + } else { + assert(GI.Guard->getLinkage() == GV->getLinkage() && + "static local from the same function had different linkage"); + } + + // Pseudo code for the test: + // if (!(GuardVar & MyGuardBit)) { + // GuardVar |= MyGuardBit; + // ... initialize the object ...; + // } + + // Test our bit from the guard variable. + llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1U << BitIndex); + llvm::LoadInst *LI = Builder.CreateLoad(GI.Guard); + llvm::Value *IsInitialized = + Builder.CreateICmpNE(Builder.CreateAnd(LI, Bit), Zero); + llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init"); + llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); + Builder.CreateCondBr(IsInitialized, EndBlock, InitBlock); + + // Set our bit in the guard variable and emit the initializer and add a global + // destructor if appropriate. + CGF.EmitBlock(InitBlock); + Builder.CreateStore(Builder.CreateOr(LI, Bit), GI.Guard); + CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit); + Builder.CreateBr(EndBlock); + + // Continue. + CGF.EmitBlock(EndBlock); } // Member pointer helpers. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 36105e7117..5dbfa105e1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3083,6 +3083,9 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } static void HandleTagNumbering(Sema &S, const TagDecl *Tag) { + if (!S.Context.getLangOpts().CPlusPlus) + return; + if (isa(Tag->getParent())) { // If this tag is the direct child of a class, number it if // it is anonymous. @@ -5356,7 +5359,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, isIncompleteDeclExternC(*this, NewVD)) RegisterLocallyScopedExternCDecl(NewVD, S); - if (NewVD->isStaticLocal()) { + if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) { Decl *ManglingContextDecl; if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(NewVD->getDeclContext(), diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 3a796ad902..761feffc26 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/DeclSpec.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" @@ -114,12 +115,21 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC, // -- the in-class initializers of class members case DefaultArgument: // -- default arguments appearing in class definitions - return &ExprEvalContexts.back().getMangleNumberingContext(); + return &ExprEvalContexts.back().getMangleNumberingContext(Context); } llvm_unreachable("unexpected context"); } +MangleNumberingContext & +Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext( + ASTContext &Ctx) { + assert(ManglingContextDecl && "Need to have a context declaration"); + if (!MangleNumbering) + MangleNumbering = Ctx.createMangleNumberingContext(); + return *MangleNumbering; +} + CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, diff --git a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp index 5664476160..afa77077a2 100644 --- a/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp +++ b/test/CodeGenCXX/debug-info-global-ctor-dtor.cpp @@ -20,7 +20,7 @@ void foo() { // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 12] [local] [def] [__dtor_glob] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_var_init1] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__cxx_global_array_dtor] -// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_] +// CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 13] [local] [def] [__dtor_array] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line 16] [local] [def] [__dtor__ZZ3foovE4stat] // CHECK-NOKEXT: [ DW_TAG_subprogram ] [line {{.*}}] [local] [def]{{$}} diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp index 56536b1a57..6c4e9e72f4 100644 --- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp +++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -5,19 +5,81 @@ // CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] struct S { - S() {} - ~S() {} -} s; + S(); + ~S(); +}; + +S s; // CHECK: define internal void [[INIT_s:@.*global_var.*]] [[NUW:#[0-9]+]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A") +// CHECK: call i32 @atexit(void ()* @"\01??__Fs@@YAXXZ") // CHECK: ret void -// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() [[NUW]] { +// CHECK: define internal void @"\01??__Fs@@YAXXZ"() [[NUW]] { // CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ" // CHECK: ret void +void StaticLocal() { + static S TheS; +} +// CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: ret + +void MultipleStatics() { + static S S1; + static S S2; + static S S3; + static S S4; + static S S5; + static S S6; + static S S7; + static S S8; + static S S9; + static S S10; + static S S11; + static S S12; + static S S13; + static S S14; + static S S15; + static S S16; + static S S17; + static S S18; + static S S19; + static S S20; + static S S21; + static S S22; + static S S23; + static S S24; + static S S25; + static S S26; + static S S27; + static S S28; + static S S29; + static S S30; + static S S31; + static S S32; + static S S33; + static S S34; + static S S35; +} +// CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: and i32 {{.*}}, 8 +// CHECK: and i32 {{.*}}, 16 +// ... +// CHECK: and i32 {{.*}}, -2147483648 +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA1" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: ret + // Force WeakODRLinkage by using templates class A { public: @@ -33,20 +95,55 @@ class B { template A B::foo; +inline S &UnreachableStatic() { + if (0) { + static S s; // bit 1 + return s; + } + static S s; // bit 2 + return s; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?UnreachableStatic@@YAAAUS@@XZ"() +// CHECK: and i32 {{.*}}, 2 +// CHECK: or i32 {{.*}}, 2 +// CHECK: ret + +inline S &getS() { + static S TheS; + return TheS; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?getS@@YAAAUS@@XZ" +// CHECK: load i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: and i32 {{.*}}, 1 +// CHECK: icmp ne i32 {{.*}}, 0 +// CHECK: br i1 +// init: +// CHECK: or i32 {{.*}}, 1 +// CHECK: store i32 {{.*}}, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"(%struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A") +// CHECK: call i32 @atexit(void ()* @"\01??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ") +// CHECK: br label +// init.end: +// CHECK: ret %struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A" + void force_usage() { + UnreachableStatic(); + getS(); (void)B::foo; // (void) - force usage } // CHECK: define internal void [[INIT_foo]]() [[NUW]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]]) +// CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B@H@@YAXXZ") // CHECK: ret void // CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" // CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ" -// CHECK: define internal void [[FOO_DTOR]] +// CHECK: define internal void @"\01??__Ffoo@?$B@H@@YAXXZ" // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo // CHECK: ret void -- 2.50.1