For
```c++
struct S {
constexpr S(int=0) : i(1) {}
int i;
};
constexpr volatile S vs;
```
reading from `vs.i` is not allowed, even though `i` is not volatile
qualified. Propagate the IsVolatile bit down the hierarchy, so we know
reading from `vs.i` is a volatile read.
Fix comparing type id pointers, add mor info when print()ing them, use
the most derived type in GetTypeidPtr() and the canonically unqualified
type when we know the type statically.
The Pointer class already has the capability to be a function pointer,
but we still classifed function pointers as PT_FnPtr/FunctionPointer.
This means when converting from a Pointer to a FunctionPointer, we lost
the information of what the original Pointer pointed to.
This issue is very convoluted, but in essence, in the new version:
For a Pointer P that points to the root of a multidimensional, primitive
array:
`P.narrow()` does nothing.
`P.atIndex(0)` points `P[0]`
`P.atIndex(0).atIndex(0)` is the same as `P.atIndex(0)` (as before)
`P.atIndex(0).narrow().atIndex(0)` points to `P[0][0]`
`P.atIndex(0).narrow().narrow()` is the same as `P.atIndex(0).narrow()`.
Make lifetime management more explicit. We're only using this for
CXXPseudoDestructorExprs for now but we need this to handle
std::construct_at/placement-new after destructor calls later anyway.
Add it as another kind of pointer, saving both a `Type*` for the result
of the typeid() expression as well as one for the type of the typeid
expression.
This requires adding a new opcode for PointerToBoolean casts, since we
otherwise emit too many diagnostics. But that fixes an older problem
when casting weak pointers to bool.
... to current offset. This breaks other tests which this commit also
fixes. Namely, getIndex() should return the integer representation for
non-block pointers.