This bug surfaced after https://github.com/llvm/llvm-project/pull/105865 (currently reverted, but blocked on this to be relanded). Because Clang doesn't emit `DW_TAG_member`s for unnamed bitfields, LLDB has to make an educated guess about whether they existed in the source. It does so by checking whether there is a gap between where the last field ended and the currently parsed field starts. In the example test case, the empty field `padding` was folded into the storage of `data`. Because the `bit_offset` of `padding` is `0x0` and its `DW_AT_byte_size` is `0x1`, LLDB thinks the field ends at `0x1` (not quite because we first round the size to a word size, but this is an implementation detail), erroneously deducing that there's a gap between `flag` and `padding`. This patch adds the notion of "effective field end", which accounts for fields that share storage. It is set to the end of the storage that the two fields occupy. Then we use this to check for gaps in the unnamed bitfield creation logic.
111 lines
3.2 KiB
C++
111 lines
3.2 KiB
C++
// RUN: %clang --target=x86_64-apple-macosx -c -gdwarf -o %t %s
|
|
// RUN: %lldb %t \
|
|
// RUN: -o "target var global" \
|
|
// RUN: -o "target var global2" \
|
|
// RUN: -o "target var global3" \
|
|
// RUN: -o "target var global4" \
|
|
// RUN: -o "target var global5" \
|
|
// RUN: -o "image dump ast" \
|
|
// RUN: -o exit | FileCheck %s
|
|
|
|
// CHECK: (lldb) image dump ast
|
|
// CHECK: CXXRecordDecl {{.*}} struct Foo definition
|
|
// CHECK: |-FieldDecl {{.*}} data 'char[5]'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} padding 'Empty'
|
|
// CHECK-NEXT: `-FieldDecl {{.*}} flag 'unsigned long'
|
|
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
|
|
|
struct Empty {};
|
|
struct Empty2 {};
|
|
struct Empty3 {};
|
|
|
|
struct Foo {
|
|
char data[5];
|
|
[[no_unique_address]] Empty padding;
|
|
unsigned long flag : 1;
|
|
};
|
|
|
|
Foo global;
|
|
|
|
// CHECK: CXXRecordDecl {{.*}} struct ConsecutiveOverlap definition
|
|
// CHECK: |-FieldDecl {{.*}} data 'char[5]'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p1 'Empty'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p2 'Empty2'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p3 'Empty3'
|
|
// CHECK-NEXT: `-FieldDecl {{.*}} flag 'unsigned long'
|
|
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
|
|
|
struct ConsecutiveOverlap {
|
|
char data[5];
|
|
[[no_unique_address]] Empty p1;
|
|
[[no_unique_address]] Empty2 p2;
|
|
[[no_unique_address]] Empty3 p3;
|
|
unsigned long flag : 1;
|
|
};
|
|
|
|
ConsecutiveOverlap global2;
|
|
|
|
// FIXME: we fail to deduce the unnamed bitfields here.
|
|
//
|
|
// CHECK: CXXRecordDecl {{.*}} struct MultipleAtOffsetZero definition
|
|
// CHECK: |-FieldDecl {{.*}} data 'char[5]'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p1 'Empty'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} f1 'unsigned long'
|
|
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p2 'Empty2'
|
|
// CHECK-NEXT: `-FieldDecl {{.*}} f2 'unsigned long'
|
|
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
|
|
|
struct MultipleAtOffsetZero {
|
|
char data[5];
|
|
[[no_unique_address]] Empty p1;
|
|
int : 4;
|
|
unsigned long f1 : 1;
|
|
[[no_unique_address]] Empty2 p2;
|
|
int : 4;
|
|
unsigned long f2 : 1;
|
|
};
|
|
|
|
MultipleAtOffsetZero global3;
|
|
|
|
// FIXME: we fail to deduce the unnamed bitfields here.
|
|
//
|
|
// CHECK: CXXRecordDecl {{.*}} struct MultipleEmpty definition
|
|
// CHECK: |-FieldDecl {{.*}} data 'char[5]'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p1 'Empty'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} f1 'unsigned long'
|
|
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 1
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p2 'Empty'
|
|
// CHECK-NEXT: `-FieldDecl {{.*}} f2 'unsigned long'
|
|
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
|
|
|
struct MultipleEmpty {
|
|
char data[5];
|
|
[[no_unique_address]] Empty p1;
|
|
int : 4;
|
|
unsigned long f1 : 1;
|
|
[[no_unique_address]] Empty p2;
|
|
int : 4;
|
|
unsigned long f2 : 1;
|
|
};
|
|
|
|
MultipleEmpty global4;
|
|
|
|
// CHECK: CXXRecordDecl {{.*}} struct FieldBitfieldOverlap definition
|
|
// CHECK: |-FieldDecl {{.*}} a 'int'
|
|
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 3
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} p1 'Empty'
|
|
// CHECK-NEXT: |-FieldDecl {{.*}} b 'int'
|
|
// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 6
|
|
// CHECK-NEXT: `-FieldDecl {{.*}} c 'int'
|
|
// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
|
|
|
|
struct FieldBitfieldOverlap {
|
|
int a : 3;
|
|
[[no_unique_address]] Empty p1;
|
|
int b : 6;
|
|
int c : 1;
|
|
};
|
|
|
|
FieldBitfieldOverlap global5;
|