On Jan 24, 2008 8:09 PM, Sanghyeon Seo <[EMAIL PROTECTED]> wrote:
> This test program crashes in CodeGen.
> struct s { short a; int b; } x = {1, 1};
>
> "struct s" converts to LLVM type {i16, i8, i8, i32}, padded with i8.
> CodeGen attempts llvm::ConstantStruct::get({i16, i8, i8, i32}, {1, 1})
> and crashes, since the type has 4 elements but initializer has only 2.

Here's a fix.  It doesn't completely implement struct initializer
codegen, but it's enough to codegen all fully braced initializers that
don't initialize bitfields.

-Eli
Index: CodeGen/CodeGenModule.cpp
===================================================================
--- CodeGen/CodeGenModule.cpp   (revision 46353)
+++ CodeGen/CodeGenModule.cpp   (working copy)
@@ -293,13 +293,6 @@
 /// struct typed variables.
 static llvm::Constant *GenerateAggregateInit(const InitListExpr *ILE, 
                                              CodeGenModule &CGM) {
-  if (ILE->getType()->isVoidType()) {
-    // FIXME: Remove this when sema of initializers is finished (and the code
-    // below).
-    CGM.WarnUnsupported(ILE, "initializer");
-    return 0;
-  }
-  
   assert((ILE->getType()->isArrayType() || ILE->getType()->isStructureType() ||
           ILE->getType()->isVectorType()) &&
          "Bad type for init list!");
@@ -311,38 +304,76 @@
   const llvm::CompositeType *CType = 
     cast<llvm::CompositeType>(Types.ConvertType(ILE->getType()));
   assert(CType);
-  std::vector<llvm::Constant*> Elts;    
-    
+
+  if (ILE->getType()->isStructureType()) {
+    const llvm::StructType *SType = cast<llvm::StructType>(CType);
+    const RecordDecl* structDecl = 
ILE->getType()->getAsRecordType()->getDecl();
+    // The number of declarations in the C struct
+    unsigned numMembers = structDecl->getNumMembers() -
+                          structDecl->hasFlexibleArrayMember();
+    // The number of members in the raw LLVM struct.
+    unsigned numLLVMElements = SType->getNumElements();
+    // At the end of the following two loops, Elts will contain
+    // initializers for all the members of the LLVM struct.
+    std::vector<llvm::Constant*> Elts(numLLVMElements);
+    for (unsigned curMember = 0, curInit = 0; curMember < numMembers; 
++curMember) {
+      if (curInit >= ILE->getNumInits()) {
+        // No more initializers; the rest of the struct is filled
+        // with null below.
+        break;
+      }
+      const FieldDecl *curField = structDecl->getMember(curMember);
+      if (!curField->getIdentifier()) {
+        // Initializers can't initialize unnamed fields, e.g. "int : 20;"
+        continue;
+      }
+      const Expr* expr = ILE->getInit(curInit);
+      ++curInit;
+      // FIXME: This doesn't work properly for initializers
+      // that aren't fully braced.
+      llvm::Constant* fieldValue = GenerateConstantExpr(expr, CGM);
+      assert(!curField->isBitField() && "Cannot initialize bitfields yet");
+      // Fill in the appropriate field in the LLVM struct. 
+      // Types.getLLVMFieldNo(curField) is often equal to curMember,
+      // but padding and bitfields mess that up, so it's simpler
+      // to just grab the right field.
+      Elts[Types.getLLVMFieldNo(curField)] = fieldValue;
+    }
+    for (unsigned i = 0; i < Elts.size(); i++) {
+      if (Elts[i] == 0) {
+        // Fill in all the uninitialized members with null
+        // In theory, we could fill in padding fields with undef,
+        // but it would be more complicated.
+        Elts[i] = llvm::Constant::getNullValue(SType->getElementType(i));
+      }
+    }
+    return llvm::ConstantStruct::get(SType, Elts);
+  }
+
+  std::vector<llvm::Constant*> Elts;
   // Initialising an array requires us to automatically initialise any 
   // elements that have not been initialised explicitly
   const llvm::ArrayType *AType = 0; 
   const llvm::Type *AElemTy = 0;
   unsigned NumArrayElements = 0;
-  
+
   // If this is an array, we may have to truncate the initializer
   if ((AType = dyn_cast<llvm::ArrayType>(CType))) {
     NumArrayElements = AType->getNumElements();
     AElemTy = AType->getElementType();
     NumInitableElts = std::min(NumInitableElts, NumArrayElements);
   }
-    
+
   // Copy initializer elements.
   unsigned i = 0;
   for (i = 0; i < NumInitableElts; ++i) {
     llvm::Constant *C = GenerateConstantExpr(ILE->getInit(i), CGM);
-    // FIXME: Remove this when sema of initializers is finished (and the code
-    // above).
-    if (C == 0 && ILE->getInit(i)->getType()->isVoidType()) {
-      if (ILE->getType()->isVoidType()) return 0;
-      return llvm::UndefValue::get(CType);
-    }
     assert (C && "Failed to create initialiser expression");
     Elts.push_back(C);
   }
 
-  if (ILE->getType()->isStructureType())
-    return llvm::ConstantStruct::get(cast<llvm::StructType>(CType), Elts);
-
+  // FIXME: What about a vector initializer that doesn't have
+  // enough elements?
   if (ILE->getType()->isVectorType())
     return llvm::ConstantVector::get(cast<llvm::VectorType>(CType), Elts);
 
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

Reply via email to