[PATCH] Flexible array initializers may be strings

for example:

struct a {
  int b;
  char v[];
};

struct a foo = { .b = 0, .v = "bar" };

is perfectly sensible and correct (and accepted by gcc).

Signed-off-by: Pierre Habouzit <madcoder@debian.org>

For the record, clang accepts the following code:

-------8<-----------
#include <stdio.h>

struct a {
  int i;
  char v[];
};

int main(void) {
  struct a foo = { .i = 0, .v = "foo" };
  struct a bar = { .i = 0, .v = { 'b', 'a', 'r', '\0' } };

  printf("%p %s\n", foo.v, foo.v);
  printf("%p %s\n", bar.v, bar.v);
  return 0;
}
-------8<-----------

whereas gcc rejects it with the error:
  error: non-static initialization of a flexible array member

Clang doesn't complain, but generates invalid code though when foo and bar
aren't static:

$ clang -o a a.c && ./a
0x7fff1eccc32c
0x7fff1eccc324 ÿ

Reading the relevant parts of the bitcode indeed shows what is wrong:
there is a correct internal constant for main.foo, but the variable
foo storage is allocated using sizeof(struct a) instead of
sizeof(main.foo), and the memcpy also uses sizeof(struct a) which is
4 instead of sizeof(main.foo).

@main.foo = internal constant %0 { i32 0, [4 x i8] c"foo\00" }, align 4
%foo = alloca %struct.a, align 4
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %tmp, i8* bitcast (%0* @main.foo to i8*), i64 4, i32 4, i1 false)

Sadly fixing that exceeds my current clang hacking skills. Do you
want me to report a bug for that ?

I made it http://llvm.org/bugs/show_bug.cgi?id=8217

- if (!hadError && !isa<InitListExpr>(DIE->getInit())) {
+ if (!hadError && !isa<InitListExpr>(DIE->getInit()) && !isa<StringLiteral>(DIE->getInit())) {

I noticed after that that there is an IsStringInit function, so I tried
the patch with
    !IsStringInit(DIE->getInit(), DIE->getType, SemaRef.Context)
which handles more cases, but for some reason it doesn't work on my
use case anymore, and I've not been able to understand why.

Thanks! Applied in r116165, sorry for the delay.

-Chris

Thanks, fixed in r116166!

-Chris