#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"
class SelectorTable;
class TargetInfo;
class CXXABI;
+ class MangleNumberingContext;
// Decls
class MangleContext;
class ObjCIvarDecl;
/// \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<const DeclContext *, MangleNumberingContext>
+ llvm::DenseMap<const DeclContext *, MangleNumberingContext *>
MangleNumberingContexts;
/// \brief Side-table of mangling numbers for declarations which rarely
/// 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);
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 &) {
class MangleNumberingContext
: public RefCountedBase<MangleNumberingContext> {
llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
- llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers;
llvm::DenseMap<IdentifierInfo*, unsigned> 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);
/// \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.
/// \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;
#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"
AEnd = DeclAttrs.end();
A != AEnd; ++A)
A->second->~AttrVec();
+
+ for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator
+ I = MangleNumberingContexts.begin(),
+ E = MangleNumberingContexts.end();
+ I != E; ++I)
+ delete I->second;
}
void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
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) {
class ASTContext;
class MemberPointerType;
+class MangleNumberingContext;
/// Implements C++ ABI-specific semantic analysis functions.
class CXXABI {
/// 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.
#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"
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<IdentifierInfo*, unsigned> 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;
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
return Layout.getNonVirtualSize() == PointerSize;
}
+
+ virtual MangleNumberingContext *createMangleNumberingContext() const {
+ return new ItaniumNumberingContext();
+ }
};
class ARMCXXABI : public ItaniumCXXABI {
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 &);
/// 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) {
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
CXXNameMangler Mangler(*this, Out);
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) {
// <special-name> ::= TH <object name>
return ++ManglingNumbers[Ty];
}
-unsigned
-MangleNumberingContext::getManglingNumber(const VarDecl *VD) {
- return ++VarManglingNumbers[VD->getIdentifier()];
-}
-
unsigned
MangleNumberingContext::getManglingNumber(const TagDecl *TD) {
return ++TagManglingNumbers[TD->getIdentifier()];
#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"
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:
return Layout.getNonVirtualSize() == PointerSize ||
Layout.getNonVirtualSize() == PointerSize * 2;
}
+
+ MangleNumberingContext *createMangleNumberingContext() const {
+ return new MicrosoftNumberingContext();
+ }
};
}
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; }
}
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);
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);
};
}
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) {
+ // <guard-name> ::= ?_B <postfix> @51
+ // ::= ?$S <guard-num> @ <postfix> @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();
+ // <operator-name> ::= ?_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) {
+ // <destructor-name> ::= ?__F <postfix> 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);
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,
/// - 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.
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);
SmallString<256> guardName;
{
llvm::raw_svector_ostream out(guardName);
- getMangleContext().mangleItaniumGuardVariable(&D, out);
+ getMangleContext().mangleStaticGuardVariable(&D, out);
out.flush();
}
private:
/// VBTables - All the vbtables which have been referenced.
llvm::DenseMap<const CXXRecordDecl *, VBTableVector> 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<const DeclContext *, GuardInfo> GuardVariableMap;
};
}
}
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.
}
static void HandleTagNumbering(Sema &S, const TagDecl *Tag) {
+ if (!S.Context.getLangOpts().CPlusPlus)
+ return;
+
if (isa<CXXRecordDecl>(Tag->getParent())) {
// If this tag is the direct child of a class, number it if
// it is anonymous.
isIncompleteDeclExternC(*this, NewVD))
RegisterLocallyScopedExternCDecl(NewVD, S);
- if (NewVD->isStaticLocal()) {
+ if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
Decl *ManglingContextDecl;
if (MangleNumberingContext *MCtx =
getCurrentMangleNumberContext(NewVD->getDeclContext(),
//===----------------------------------------------------------------------===//
#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"
// -- 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,
// 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]{{$}}
// 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:
template<typename T> A B<T>::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<int>::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