From: Daniel Dunbar Date: Thu, 19 Feb 2009 05:36:41 +0000 (+0000) Subject: Emission of global variable initialializer was broken in rare X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=232350d4faf46ec38d5ff60e11505f9c4fa9535b;p=clang Emission of global variable initialializer was broken in rare situation where a tentative decl was emitted *after* the actual initialization. This occurs in some rare situations with static decls. - PR3613. - I'm not particularly happy with this fix, but I don't see a simpler or more elegant solution yet. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65018 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index ca6ba14f85..17662ef340 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -444,7 +444,7 @@ void CodeGenModule::EmitDeferred() { // FIXME: This is missing some important cases. For example, we // need to check for uses in an alias. if (!GlobalDeclMap.count(getMangledName(D))) { - i++; + ++i; continue; } @@ -623,6 +623,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { Init = llvm::Constant::getNullValue(InitTy); } else { Init = EmitConstantExpr(D->getInit()); + if (!Init) + ErrorUnsupported(D, "static initializer"); } const llvm::Type* InitType = Init->getType(); @@ -634,6 +636,26 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::GlobalValue::ExternalLinkage, 0, getMangledName(D), &getModule(), 0, ASTTy.getAddressSpace()); + + } else if (GV->hasInitializer() && !GV->getInitializer()->isNullValue()) { + // If we already have this global and it has an initializer, then + // we are in the rare situation where we emitted the defining + // declaration of the global and are now being asked to emit a + // definition which would be common. This occurs, for example, in + // the following situation because statics can be emitted out of + // order: + // + // static int x; + // static int *y = &x; + // static int x = 10; + // int **z = &y; + // + // Bail here so we don't blow away the definition. Note that if we + // can't distinguish here if we emitted a definition with a null + // initializer, but this case is safe. + assert(!D->getInit() && "Emitting multiple definitions of a decl!"); + return; + } else if (GV->getType() != llvm::PointerType::get(InitType, ASTTy.getAddressSpace())) { // We have a definition after a prototype with the wrong type. diff --git a/test/CodeGen/PR3613-static-decl.c b/test/CodeGen/PR3613-static-decl.c new file mode 100644 index 0000000000..6dcaa183d3 --- /dev/null +++ b/test/CodeGen/PR3613-static-decl.c @@ -0,0 +1,16 @@ +// RUN: clang -triple i386-unknown-unknown -emit-llvm -o %t %s && +// RUN: grep '@g0 = internal global .struct.s0 <{ i32 3 }>' %t | count 1 + +struct s0 { + int a; +}; + +static struct s0 g0; + +static int f0(void) { + return g0.a; +} + +static struct s0 g0 = {3}; + +void *g1 = f0;