Constants.cpp assertion raised

Hi!

Here is another piece of code that causes a crash (current SVN version):

typedef struct {
  unsigned char c;
} t;

const t x = { 1 };

Output:

clang: /home/michaelz/proj/fortas/source/external/llvm/lib/VMCore/Constants.cpp:377: llvm::ConstantStruct::ConstantStruct(const llvm::StructType*, const std::vector<llvm::Constant*, std::allocator<llvm::Constant*> >&): Assertion `(C->getType() == T->getElementType(I-V.begin()) || ((T->getElementType(I-V.begin())->isAbstract() || C->getType()->isAbstract()) && T->getElementType(I-V.begin())->getTypeID() == C->getType()->getTypeID())) && "Initializer for struct element doesn'tmatch struct element type!"' failed.
clang((anonymous namespace)::PrintStackTrace()+0x22)[0x84514f8]
clang((anonymous namespace)::SignalHandler(int)+0x102)[0x84517a0]
[0xffffe420]
/lib/libc.so.6(abort+0x101)[0xb7c920f1]
/lib/libc.so.6(__assert_fail+0xf0)[0xb7c89b50]
clang(llvm::ConstantStruct::ConstantStruct(llvm::StructType const*, std::vector<llvm::Constant*, std::allocator<llvm::Constant*> > const&)+0x255)[0x839106b]
clang(llvm::ConstantCreator<llvm::ConstantStruct, llvm::StructType, std::vector<llvm::Constant*, std::allocator<llvm::Constant*> > >::create(llvm::StructType const*, std::vector<llvm::Constant*, std::allocator<llvm::Constant*> > const&)+0x2b)[0x839c6f7]
clang(llvm::ValueMap<std::vector<llvm::Constant*, std::allocator<llvm::Constant*> >, llvm::StructType, llvm::ConstantStruct, true>::getOrCreate(llvm::StructType const*, std::vector<llvm::Constant*, std::allocator<llvm::Constant*> > const&)+0xe4)[0x83983a6]
clang(llvm::ConstantStruct::get(llvm::StructType const*, std::vector<llvm::Constant*, std::allocator<llvm::Constant*> > const&)+0x6b)[0x8392eeb]
clang[0x828f476]
clang[0x828fe77]
clang(clang::CodeGen::CodeGenModule::EmitGlobalInit(clang::Expr const*)+0x18)[0x828fedc]
clang(clang::CodeGen::CodeGenModule::EmitGlobalVar(clang::FileVarDecl const*)+0x18b)[0x8290069]
clang(clang::CodeGen::CodeGenModule::EmitGlobalVarDeclarator(clang::FileVarDeclconst*)+0x1e)[0x8290142]
clang(clang::CodeGen::CodeGenGlobalVar(clang::CodeGen::CodeGenModule*, clang::FileVarDecl*)+0x18)[0x828de14]
clang((anonymous namespace)::CodeGenerator::HandleTopLevelDecl(clang::Decl*)+0x71)[0x8263959]
clang(clang::ParseAST(clang::Preprocessor&, clang::ASTConsumer*, bool)+0xfe)[0x82cfe8c]
clang[0x8280a87]
clang(main+0x5e6)[0x82813e2]
/lib/libc.so.6(__libc_start_main+0xe0)[0xb7c7c050]
clang[0x825f361]
Aborted

Cheers,
Michael

This looks like the "struct initializers aren't fully implemented" issue. Consider this:

typedef struct {
  unsigned char c;
} t;

void foo() {
const t x = { 1 };
}

$ clang -ast-dump crash.c
void foo()
(CompoundStmt 0x806460 <crash.c:5:12, line:7:1>
   (DeclStmt 0x806450 <:0:0>
     0x8062f0 "t const x =
       (InitListExpr 0x806430 <crash.c:6:13, col:17> 't const':'struct <anonymous>'
         (IntegerLiteral 0x806320 <col:15> 'int' 1))")

I'd expect the IntegerLiteral to be wrapped in an ImplicitCast that converts it from int to unsigned char. Steve, can you please investigate then when you start work on struct initializers?

Thanks,

-Chris

I would actually expect this to work in the current global init code. I suspect the code isn't check for implicit conversions or some such... although that surprises me.

--Oliver

I'd expect the IntegerLiteral to be wrapped in an ImplicitCast that
converts it from int to unsigned char. Steve, can you please
investigate then when you start work on struct initializers?

Sure...

snaroff

The problem is that the implicit conversion isn't being emitted. For reference, this does codegen correctly:

typedef struct {
unsigned char c;
} t;

const t x = { (unsigned char)1 };

Note the explicit cast to char.

-Chris

Okay, in all likelihood sema is failing to merge correctly as the ILE still has type void or some such :-/

Unfortunately just setting the "correct" type on the ILe doesn't work as the ILEs can be flattened, so the following are both valid:
t array1 = {{'a'}, {'b'}, {'c'}};
t array2 = {'a', 'b', 'c'};

Anders' probably knows more as i think he added the original sema logic for ILEs (at least for global initialisers).

--Oliver