The GCC front end hits an assertion when compiling llvm/test/Regression/CFrontend/2003-01-30-UnionInit.c (named test.c in the following sample output): cc1: ../../src/gcc/llvm-expand.c:4679: llvm_expand_constant_expr: Assertion `0 && "Couldn't expand constructor in this context!"' failed. test.c:8: internal compiler error: Aborted Please submit a full bug report, with preprocessed source if appropriate. See <URL:http://llvm.cs.uiuc.edu> for instructions.
Note that this bug seems to prevent LLVM GCC from compiling on Sparc, so I'm moving the milestone. The problem seems to occur because we use the same code to initialize structures and unions. This is not correct as unions can only initialize the first union member while structures can initialize all of their struct members. This causes us to attempt to initialize the wrong union member, get type mismatches, and hit the assertion. I've hacked up a patch that seems to more or less work (but may not totally be correct or may break other tests). If it works well enough, I'll attach it.
My proposed patch fixes GCC so that it can build on Sparc again, but it produces new bugs. After further investigation, I found the following: 1. GCC can initialize any arbitrary member of a union. 2. It appears that the LLVM GCC front end creates structures with a single member for unions. That member is the largest member of the union. 3. llvm-gcc uses a member's position to determine its type based upon the LLVM created type. This works for struct's which have a 1-1 correspondance, but not for unions. I believe the second and third points are the cause of the problem. The failing union is: union foo { struct { char A, B; } X; int C; }; union foo V = { {1, 2} }; llvm-gcc converts this union to a structure with one integer member. When trying to initalize member X, it looks into this LLVM stucture for the first member, which is an int (the largest member). It then tries to initalize the int with a struct, which fails.
I belive this summary describes the problem a little more precisely: Unions in C/C++ are reduced to an LLVM structure containing the largest member. An LLVM global variable of this type cannot be initialized by any union member other than the largest member (otherwise, a type mismatch results). Casting doesn't seem to solve the problem since some types cannot be casted into others.
Unfortunately, there isn't really any way to fix this without a substantial rewrite of the initializer handling code. I was planning on doing this after 1.1... -Chris
Ugh. I looked into this more, and this is _precisely_ the case that I need to do the rewrite for. I wonder, where does this union initialization come from in the C front-end? It might be better to hack the source in the C front-end to temporarily work around this problem if possible. If you point it out, I can figure out the appropriate work-around. I changed the subject line to be a bit more amorphous, because there are other cases that don't work either, involving nested unions and other crimes against nature. -Chris
perhaps next release
*** Bug 650 has been marked as a duplicate of this bug. ***
*** Bug 156 has been marked as a duplicate of this bug. ***
When working on this bug, please make sure that all of the marked duplicates are fixed before this one is closed. -Chris
Testcase here: llvm-test/SingleSource/UnitTests/2006-01-23-UnionInit.c This is fixed by the new frontend and will be closed when it is the default. -Chris
This is fixed in llvmgcc4.