When you run an expression and the result has a dynamic type that is
different from the expression's static result type, we print the result
variable using the dynamic type, but at present when you use the result
variable in an expression later on, we only give you access to the
static type. For instance:
```
(lldb) expr MakeADerivedReportABase()
(Derived *) $0 = 0x00000001007e93e0
(lldb) expr $0->method_from_derived()
^
error: no member named 'method_from_derived' in 'Base'
(lldb)
```
The static return type of that function is `Base *`, but we printed that
the result was a `Derived *` and then only used the `Base *` part of it
in subsequent expressions. That's not very helpful, and forces you to
guess and then cast the result types to their dynamic type in order to
be able to access the full type you were returned, which is
inconvenient.
This patch makes lldb retain the dynamic type of the result variable
(and ditto for persistent result variables).
It also adds more testing of expression result variables with various
types of dynamic values, to ensure we can access both the ivars and
methods of the type we print the result as.
56 lines
1.7 KiB
C++
56 lines
1.7 KiB
C++
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
struct Base {
|
|
virtual ~Base() = default;
|
|
int base_int = 100;
|
|
Base *return_me() { return this; }
|
|
};
|
|
|
|
struct Base_1 : public VIRTUAL Base {
|
|
virtual ~Base_1() = default;
|
|
int base_1_arr[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};
|
|
Base *return_base_1() { return return_me(); }
|
|
};
|
|
|
|
struct Base_2 : public VIRTUAL Base {
|
|
virtual ~Base_2() = default;
|
|
int base_2_arr[10] = {200, 201, 202, 203, 204, 205, 206, 207, 208, 209};
|
|
Base *return_base_2() { return return_me(); }
|
|
};
|
|
|
|
struct Derived : public Base_1, Base_2 {
|
|
virtual ~Derived() = default;
|
|
int derived_int = 1000;
|
|
int method_of_derived() { return 500; }
|
|
};
|
|
|
|
Base *MakeADerivedReportABase() { return (Base *)((Base_1 *)new Derived()); }
|
|
|
|
int main() {
|
|
Derived my_derived;
|
|
int call_it = my_derived.method_of_derived();
|
|
|
|
Base_1 *base_1_ptr = (Base_1 *)&my_derived;
|
|
|
|
Base_2 *base_2_ptr = (Base_2 *)&my_derived;
|
|
|
|
Base *base_through_1 = my_derived.return_base_1();
|
|
Base *base_through_2 = my_derived.return_base_2();
|
|
|
|
// Call this to make sure the compiler makes it.
|
|
Base *fake_base = MakeADerivedReportABase();
|
|
|
|
uint64_t base_through_1_addr = (uint64_t)base_through_1;
|
|
uint64_t base_through_2_addr = (uint64_t)base_through_2;
|
|
int64_t base_offset = base_through_2_addr - base_through_1_addr;
|
|
printf("Base offset (should be 0): 0x%llx.\n", base_offset);
|
|
uint64_t base_1_addr = (uint64_t)base_1_ptr;
|
|
uint64_t base_2_addr = (uint64_t)base_2_ptr;
|
|
int64_t offset = base_2_addr - base_1_addr;
|
|
|
|
// Set a breakpoint here
|
|
return my_derived.derived_int + base_1_ptr->base_1_arr[0] +
|
|
base_2_ptr->base_2_arr[0] + my_derived.return_base_1()->base_int;
|
|
}
|