]> granicus.if.org Git - clang/commitdiff
Emission of global variable initialializer was broken in rare
authorDaniel Dunbar <daniel@zuster.org>
Thu, 19 Feb 2009 05:36:41 +0000 (05:36 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Thu, 19 Feb 2009 05:36:41 +0000 (05:36 +0000)
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

lib/CodeGen/CodeGenModule.cpp
test/CodeGen/PR3613-static-decl.c [new file with mode: 0644]

index ca6ba14f85557602155f20fb286ca1bbf981afca..17662ef340e422dbaa961158b688e21855beedc1 100644 (file)
@@ -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 (file)
index 0000000..6dcaa18
--- /dev/null
@@ -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;