Consider this example:
struct header { unsigned a : 1; unsigned b : 1; }; struct parse_t { unsigned bits0 : 1; unsigned bits2 : 2; // <-- header unsigned bits4 : 4; }; int parse(parse_t *p) { unsigned copy = p->bits2; clang_analyzer_dump(copy); // expected-warning@-1 {{reg_$1<unsigned int SymRegion{reg_$0<struct Bug_55934::parse_t * p>}.bits2>}} header *bits = (header *)© clang_analyzer_dump(bits->b); // <--- Was UndefinedVal previously. // expected-warning@-1 {{derived_$2{reg_$1<unsigned int SymRegion{reg_$0<struct Bug_55934::parse_t * p>}.bits2>,Element{copy,0 S64b,struct Bug_55934::header}.b}}} return bits->b; // no-warning: it's not UndefinedVal }
bits->b should have the same content as the second bit of p->bits2
(assuming that the bitfields are in spelling order).
The Store has the correct bindings. The problem is with the load of bits->b.
It will eventually reach RegionStoreManager::getBindingForField() with
Element{copy,0 S64b,struct header}.b, which is a FieldRegion.
It did not find any direct bindings, so the getBindingForFieldOrElementCommon()
gets called. That won't find any bindings, but it sees that the variable
is on the stack, thus it must be an uninitialized local variable;
thus it returns UndefinedVal.
Instead of doing this, it should have created a derived symbol
representing the slice of the region corresponding to the member.
So, if the value of copy is reg1, then the value of bits->b should
be derived{reg1, elem{copy,0, header}.b}.
Actually, the getBindingForElement() already does exactly this for reinterpret-casts, so I decided to hoist that and reuse the logic.
Fixes #55934
BTW I'm not sure why this check is here. I would expect this to work eve without this.
OOh, I think I know why. getTypeSizeInChars can only be called on scalars?