diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 998795d585..befebbecbd 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -172,7 +172,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, void CGCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::Constant *GV, + llvm::GlobalVariable *GV, bool PerformInit) { ErrorUnsupportedABI(CGF, "static local variable initialization"); } diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index e357d8280c..4e045f5f32 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -246,9 +246,8 @@ public: /// The variable may be: /// - a static local variable /// - a static data member of a class template instantiation - /// In either case, it will be a (possibly casted) llvm::GlobalVariable. virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::Constant *addr, bool PerformInit); + llvm::GlobalVariable *DeclPtr, bool PerformInit); }; diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 7cd02d8d86..970f0b2389 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -169,24 +169,7 @@ static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, return ContextName + Separator + D.getNameAsString(); } -/// We wanted to make a variable of one type, but the variable already -/// exists with another. Is that type good enough? -/// -/// The problem we're working around here is that giving a global -/// variable an initializer can require changing its type in some -/// convoluted circumstances. -static bool isExistingVarAdequate(CodeGenModule &CGM, - llvm::Type *existing, llvm::Type *desired) { - // Equality makes for a good fast path. - if (existing == desired) return true; - - // Otherwise, just require them to have the same size. - return (CGM.getTargetData().getTypeStoreSize(existing) - == CGM.getTargetData().getTypeStoreSize(desired)); -} - - -llvm::Constant * +llvm::GlobalVariable * CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, const char *Separator, llvm::GlobalValue::LinkageTypes Linkage) { @@ -201,37 +184,12 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, Name = GetStaticDeclName(*this, D, Separator); llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); - unsigned addrspace = CGM.getContext().getTargetAddressSpace(Ty); - - // In C++, there are strange possibilities here involving the - // double-emission of constructors and destructors. - if (CGM.getLangOpts().CPlusPlus) { - llvm::GlobalValue *value = CGM.getModule().getNamedValue(Name); - if (value && isa(value)) { - // Check that the type is compatible with the type we want. The - // simple equality check isn't good enough because initializers - // can force the changing of a type (e.g. with unions). - if (value->getType()->getAddressSpace() == addrspace && - isExistingVarAdequate(CGM, value->getType()->getElementType(), LTy)) - return llvm::ConstantExpr::getBitCast(value, - LTy->getPointerTo(addrspace)); - } - - if (value) { - CGM.Error(D.getLocation(), - "problem emitting static variable '" + Name + - "': already present as different kind of symbol"); - - // Fall through and implicitly give it a uniqued name. - } - } - llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), LTy, Ty.isConstant(getContext()), Linkage, CGM.EmitNullConstant(D.getType()), Name, 0, D.isThreadSpecified(), - addrspace); + CGM.getContext().getTargetAddressSpace(Ty)); GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); if (Linkage != llvm::GlobalValue::InternalLinkage) GV->setVisibility(CurFn->getVisibility()); @@ -246,85 +204,80 @@ static bool hasNontrivialDestruction(QualType T) { return RD && !RD->hasTrivialDestructor(); } -/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to -/// the global variable that has already been created for it. If -/// the initializer has a different type than GV does, this may -/// force the underlying variable to change. Otherwise it just -/// returns it. -/// -/// The argument must be a (potentially casted) global variable, -/// and the result will be one, too. -llvm::Constant * +/// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the +/// global variable that has already been created for it. If the initializer +/// has a different type than GV does, this may free GV and return a different +/// one. Otherwise it just returns GV. +llvm::GlobalVariable * CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, - llvm::Constant *addr) { - llvm::Constant *init = CGM.EmitConstantInit(D, this); - - llvm::GlobalVariable *var = - cast(addr->stripPointerCasts()); + llvm::GlobalVariable *GV) { + llvm::Constant *Init = CGM.EmitConstantInit(D, this); // If constant emission failed, then this should be a C++ static // initializer. - if (!init) { + if (!Init) { if (!getContext().getLangOpts().CPlusPlus) CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); else if (Builder.GetInsertBlock()) { // Since we have a static initializer, this global variable can't // be constant. - var->setConstant(false); + GV->setConstant(false); - EmitCXXGuardedInit(D, addr, /*PerformInit*/true); + EmitCXXGuardedInit(D, GV, /*PerformInit*/true); } - return addr; + return GV; } // The initializer may differ in type from the global. Rewrite // the global to match the initializer. (We have to do this // because some types, like unions, can't be completely represented // in the LLVM type system.) - if (var->getType()->getElementType() != init->getType()) { - llvm::GlobalVariable *newVar - = new llvm::GlobalVariable(CGM.getModule(), init->getType(), - var->isConstant(), - var->getLinkage(), init, "", - /*InsertBefore*/ var, - D.isThreadSpecified(), - var->getType()->getAddressSpace()); - newVar->setVisibility(var->getVisibility()); + if (GV->getType()->getElementType() != Init->getType()) { + llvm::GlobalVariable *OldGV = GV; + + GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + OldGV->isConstant(), + OldGV->getLinkage(), Init, "", + /*InsertBefore*/ OldGV, + D.isThreadSpecified(), + CGM.getContext().getTargetAddressSpace(D.getType())); + GV->setVisibility(OldGV->getVisibility()); // Steal the name of the old global - newVar->takeName(var); + GV->takeName(OldGV); // Replace all uses of the old global with the new global - addr = llvm::ConstantExpr::getBitCast(newVar, addr->getType()); - var->replaceAllUsesWith(addr); + llvm::Constant *NewPtrForOldDecl = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtrForOldDecl); // Erase the old global, since it is no longer used. - var->eraseFromParent(); - var = newVar; + OldGV->eraseFromParent(); } - var->setConstant(CGM.isTypeConstant(D.getType(), true)); - var->setInitializer(init); + GV->setConstant(CGM.isTypeConstant(D.getType(), true)); + GV->setInitializer(Init); if (hasNontrivialDestruction(D.getType())) { // We have a constant initializer, but a nontrivial destructor. We still // need to perform a guarded "initialization" in order to register the // destructor. - EmitCXXGuardedInit(D, addr, /*PerformInit*/false); + EmitCXXGuardedInit(D, GV, /*PerformInit*/false); } - return addr; + return GV; } void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage) { + llvm::Value *&DMEntry = LocalDeclMap[&D]; + assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - llvm::Constant *addr = CreateStaticVarDecl(D, ".", Linkage); + llvm::GlobalVariable *GV = CreateStaticVarDecl(D, ".", Linkage); // Store into LocalDeclMap before generating initializer to handle // circular references. - assert(!LocalDeclMap.count(&D) && "Decl already exists in localdeclmap!"); - LocalDeclMap[&D] = addr; + DMEntry = GV; // We can't have a VLA here, but we can have a pointer to a VLA, // even though that doesn't really make any sense. @@ -334,34 +287,40 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // Local static block variables must be treated as globals as they may be // referenced in their RHS initializer block-literal expresion. - CGM.setStaticLocalDeclAddress(&D, addr); + CGM.setStaticLocalDeclAddress(&D, GV); // If this value has an initializer, emit it. - // This can leave us with a casted pointer. if (D.getInit()) - addr = AddInitializerToStaticVarDecl(D, addr); + GV = AddInitializerToStaticVarDecl(D, GV); - llvm::GlobalVariable *var = - cast(addr->stripPointerCasts()); - var->setAlignment(getContext().getDeclAlign(&D).getQuantity()); + GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); if (D.hasAttr()) - CGM.AddGlobalAnnotations(&D, var); + CGM.AddGlobalAnnotations(&D, GV); if (const SectionAttr *SA = D.getAttr()) - var->setSection(SA->getName()); + GV->setSection(SA->getName()); if (D.hasAttr()) - CGM.AddUsedGlobal(var); + CGM.AddUsedGlobal(GV); - LocalDeclMap[&D] = addr; - CGM.setStaticLocalDeclAddress(&D, addr); + // We may have to cast the constant because of the initializer + // mismatch above. + // + // FIXME: It is really dangerous to store this in the map; if anyone + // RAUW's the GV uses of this constant will be invalid. + llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType()); + llvm::Type *LPtrTy = + LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType())); + llvm::Constant *CastedVal = llvm::ConstantExpr::getBitCast(GV, LPtrTy); + DMEntry = CastedVal; + CGM.setStaticLocalDeclAddress(&D, CastedVal); // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); if (DI) { DI->setLocation(D.getLocation()); - DI->EmitGlobalVariable(var, &D); + DI->EmitGlobalVariable(static_cast(GV), &D); } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 06ae035295..dc52b11279 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -179,7 +179,7 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, } void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, - llvm::Constant *addr, + llvm::GlobalVariable *DeclPtr, bool PerformInit) { // If we've been asked to forbid guard variables, emit an error now. // This diagnostic is hard-coded for Darwin's use case; we can find @@ -189,7 +189,7 @@ void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, "this initialization requires a guard variable, which " "the kernel does not support"); - CGM.getCXXABI().EmitGuardedInit(*this, D, addr, PerformInit); + CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr, PerformInit); } static llvm::Function * diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 02346cf026..85cbd143d8 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2392,17 +2392,17 @@ public: /// CreateStaticVarDecl - Create a zero-initialized LLVM global for /// a static local variable. - llvm::Constant *CreateStaticVarDecl(const VarDecl &D, - const char *Separator, - llvm::GlobalValue::LinkageTypes Linkage); + llvm::GlobalVariable *CreateStaticVarDecl(const VarDecl &D, + const char *Separator, + llvm::GlobalValue::LinkageTypes Linkage); - /// AddInitializerToStaticVarDecl - Add the initializer for 'D' to - /// the global variable that has already been created for it. If - /// the initializer has a different type than GV does, this may - /// force the underlying variable to change. Otherwise it just - /// returns it. - llvm::Constant * - AddInitializerToStaticVarDecl(const VarDecl &D, llvm::Constant *GV); + /// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the + /// global variable that has already been created for it. If the initializer + /// has a different type than GV does, this may free GV and return a different + /// one. Otherwise it just returns GV. + llvm::GlobalVariable * + AddInitializerToStaticVarDecl(const VarDecl &D, + llvm::GlobalVariable *GV); /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ @@ -2420,7 +2420,7 @@ public: /// possible to prove that an initialization will be done exactly /// once, e.g. with a static local variable or a static data member /// of a class template. - void EmitCXXGuardedInit(const VarDecl &D, llvm::Constant *addr, + void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr, bool PerformInit); /// GenerateCXXGlobalInitFunc - Generates code for initializing global diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 4170c7bc30..c9f1066032 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -197,9 +197,8 @@ bool CodeGenModule::isTargetDarwin() const { return getContext().getTargetInfo().getTriple().isOSDarwin(); } -void CodeGenModule::Error(SourceLocation loc, const Twine &error) { - unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, - error.str()); +void CodeGenModule::Error(SourceLocation loc, StringRef error) { + unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, error); getDiags().Report(Context.getFullLoc(loc), diagID); } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 79247c6d47..5719afb612 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -733,7 +733,7 @@ public: llvm::Constant *EmitNullConstantForBase(const CXXRecordDecl *Record); /// Error - Emit a general error that something can't be done. - void Error(SourceLocation loc, const Twine &error); + void Error(SourceLocation loc, StringRef error); /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index ce16c86b8d..6fcf83d5ac 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -123,7 +123,7 @@ public: llvm::Value *&AllocPtr, CharUnits &CookieSize); void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::Constant *addr, bool PerformInit); + llvm::GlobalVariable *DeclPtr, bool PerformInit); }; class ARMCXXABI : public ItaniumCXXABI { @@ -1051,7 +1051,7 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM, namespace { struct CallGuardAbort : EHScopeStack::Cleanup { llvm::GlobalVariable *Guard; - CallGuardAbort(llvm::GlobalVariable *guard) : Guard(guard) {} + CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {} void Emit(CodeGenFunction &CGF, Flags flags) { CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard) @@ -1064,7 +1064,7 @@ namespace { /// just special-case it at particular places. void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::Constant *varAddr, + llvm::GlobalVariable *GV, bool PerformInit) { CGBuilderTy &Builder = CGF.Builder; @@ -1073,60 +1073,35 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, bool threadsafe = (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl()); - llvm::IntegerType *guardTy; - - // Find the underlying global variable for linkage purposes. - // This may not have the right type for actual evaluation purposes. - llvm::GlobalVariable *var = - cast(varAddr->stripPointerCasts()); + llvm::IntegerType *GuardTy; // 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. - bool useInt8GuardVariable = !threadsafe && var->hasInternalLinkage(); + bool useInt8GuardVariable = !threadsafe && GV->hasInternalLinkage(); if (useInt8GuardVariable) { - guardTy = CGF.Int8Ty; + GuardTy = CGF.Int8Ty; } else { // Guard variables are 64 bits in the generic ABI and 32 bits on ARM. - guardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty); + GuardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty); } - llvm::PointerType *guardPtrTy = guardTy->getPointerTo(); + llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo(); // Create the guard variable. - SmallString<256> guardName; - { - llvm::raw_svector_ostream out(guardName); - getMangleContext().mangleItaniumGuardVariable(&D, out); - out.flush(); - } + SmallString<256> GuardVName; + llvm::raw_svector_ostream Out(GuardVName); + getMangleContext().mangleItaniumGuardVariable(&D, Out); + Out.flush(); - // There are strange possibilities here involving the - // double-emission of constructors and destructors. - llvm::GlobalVariable *guard = 0; - if (llvm::GlobalValue *existingGuard - = CGM.getModule().getNamedValue(guardName.str())) { - if (isa(existingGuard) && - existingGuard->getType() == guardPtrTy) { - guard = cast(existingGuard); // okay - } else { - CGM.Error(D.getLocation(), "problem emitting static variable '" - + guardName.str() + - "': already present as different kind of symbol"); + // Just absorb linkage and visibility from the variable. + llvm::GlobalVariable *GuardVariable = + new llvm::GlobalVariable(CGM.getModule(), GuardTy, + false, GV->getLinkage(), + llvm::ConstantInt::get(GuardTy, 0), + GuardVName.str()); + GuardVariable->setVisibility(GV->getVisibility()); - // Fall through and implicitly give it a uniqued name. - } - } - - if (!guard) { - // Just absorb linkage and visibility from the variable. - guard = new llvm::GlobalVariable(CGM.getModule(), guardTy, - false, var->getLinkage(), - llvm::ConstantInt::get(guardTy, 0), - guardName.str()); - guard->setVisibility(var->getVisibility()); - } - // Test whether the variable has completed initialization. - llvm::Value *isInitialized; + llvm::Value *IsInitialized; // ARM C++ ABI 3.2.3.1: // To support the potential use of initialization guard variables @@ -1140,9 +1115,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // ... // } if (IsARM && !useInt8GuardVariable) { - llvm::Value *V = Builder.CreateLoad(guard); + llvm::Value *V = Builder.CreateLoad(GuardVariable); V = Builder.CreateAnd(V, Builder.getInt32(1)); - isInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); + IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); // Itanium C++ ABI 3.3.2: // The following is pseudo-code showing how these functions can be used: @@ -1160,9 +1135,10 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // } } else { // Load the first byte of the guard variable. - llvm::LoadInst *load = - Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy)); - load->setAlignment(1); + llvm::Type *PtrTy = Builder.getInt8PtrTy(); + llvm::LoadInst *LI = + Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy)); + LI->setAlignment(1); // Itanium ABI: // An implementation supporting thread-safety on multiprocessor @@ -1171,16 +1147,16 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // // In LLVM, we do this by marking the load Acquire. if (threadsafe) - load->setAtomic(llvm::Acquire); + LI->setAtomic(llvm::Acquire); - isInitialized = Builder.CreateIsNull(load, "guard.uninitialized"); + IsInitialized = Builder.CreateIsNull(LI, "guard.uninitialized"); } llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); // Check if the first byte of the guard variable is zero. - Builder.CreateCondBr(isInitialized, InitCheckBlock, EndBlock); + Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock); CGF.EmitBlock(InitCheckBlock); @@ -1188,7 +1164,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, if (threadsafe) { // Call __cxa_guard_acquire. llvm::Value *V - = Builder.CreateCall(getGuardAcquireFn(CGM, guardPtrTy), guard); + = Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable); llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init"); @@ -1196,22 +1172,22 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, InitBlock, EndBlock); // Call __cxa_guard_abort along the exceptional edge. - CGF.EHStack.pushCleanup(EHCleanup, guard); + CGF.EHStack.pushCleanup(EHCleanup, GuardVariable); CGF.EmitBlock(InitBlock); } // Emit the initializer and add a global destructor if appropriate. - CGF.EmitCXXGlobalVarDeclInit(D, varAddr, PerformInit); + CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit); if (threadsafe) { // Pop the guard-abort cleanup if we pushed one. CGF.PopCleanupBlock(); // Call __cxa_guard_release. This cannot throw. - Builder.CreateCall(getGuardReleaseFn(CGM, guardPtrTy), guard); + Builder.CreateCall(getGuardReleaseFn(CGM, GuardPtrTy), GuardVariable); } else { - Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard); + Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable); } CGF.EmitBlock(EndBlock); diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp index 7e840f5622..a96cb7ac8e 100644 --- a/test/CodeGenCXX/static-init.cpp +++ b/test/CodeGenCXX/static-init.cpp @@ -3,7 +3,6 @@ // CHECK: @_ZZ1hvE1i = internal global i32 0, align 4 // CHECK: @base_req = global [4 x i8] c"foo\00", align 1 -// CHECK: @_ZZN5test31BC1EvE1u = internal global { i8, [3 x i8] } { i8 97, [3 x i8] undef }, align 4 // CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16 // CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0 // CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0 @@ -80,73 +79,3 @@ namespace union_static_local { c::main(); } } - -// rdar://problem/11091093 -// Static variables should be consistent across constructor -// or destructor variants. -namespace test2 { - struct A { - A(); - ~A(); - }; - - struct B : virtual A { - B(); - ~B(); - }; - - // If we ever implement this as a delegate ctor call, just change - // this to take variadic arguments or something. - extern int foo(); - B::B() { - static int x = foo(); - } - // CHECK: define void @_ZN5test21BC1Ev - // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, - // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) - // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() - // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x, - // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x) - - // CHECK: define void @_ZN5test21BC2Ev - // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, - // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) - // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() - // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x, - // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x) - - // This is just for completeness, because we actually emit this - // using a delegate dtor call. - B::~B() { - static int y = foo(); - } - // CHECK: define void @_ZN5test21BD1Ev( - // CHECK: call void @_ZN5test21BD2Ev( - - // CHECK: define void @_ZN5test21BD2Ev( - // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BD1EvE1y to i8*) acquire, - // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BD1EvE1y) - // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() - // CHECK: store i32 [[T0]], i32* @_ZZN5test21BD1EvE1y, - // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BD1EvE1y) -} - -// This shouldn't error out. -namespace test3 { - struct A { - A(); - ~A(); - }; - - struct B : virtual A { - B(); - ~B(); - }; - - B::B() { - union U { char x; int i; }; - static U u = { 'a' }; - } - // CHECK: define void @_ZN5test31BC1Ev( - // CHECK: define void @_ZN5test31BC2Ev( -}