This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".
I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
ReflectionContext::allocationMetadataPointer() was reading the
metadata pointer from a wrong offset because of the out-of-sync struct
layouts and dump-generic-metadata was not working correctly.
This change resync's the layouts and adds a static_assert to verify
that the offsets match between GenericMetadataCacheEntry and
GenericCacheEntry.
Handle the top node directly in `createBoundGenericType`
so that we can be sure to always include it regardless
of whether it has direct generic type params or not.
The helper function can now focus only on handling
parents (where we must only include ones that actually
contain generic type params). This separates the two
different cases and makes it a little easier to follow.
I refactored `reconstructParentsOfBoundGenericType` to
be iterative rather than recursive, though I'm not sure that
really matters.
The recursive structure made it a little awkward to correctly
distinguish between the root node (which has to be included
regardless of whether it has direct generic params)
and the parent nodes (which must only be included if they
have direct params).
So I rewrote this to do a simple two-pass iteration:
* The first pass walks the parent list collecting candidates
* The second pass walks the list backwards, assigning generic params
We then just stack the start node onto the end of the
list regardless of whether it has generic params.
This is a more correct fix for the issue that inspired PR #62854.
In particular, this does not change the numbering of generic
argument levels, and so does not break generic type parameter
lookups.
Added a new test case to verify that nested types that mix
generics and non-generics in different ways consistently identify
the correct generic argument labels.
A "generic" case is any case whose payload type depends
on generic type parameters for the enum or any enclosing type.
Some examples:
```
struct S<T> {
enum E {
case a // Non-generic case
case b(Int) // Non-generic case
case c(T) // Generic case
case d([U]) // Generic case
case e([Int]) // Non-generic case
}
}
```
This is important for correctly distinguishing MPE versus
SPE layouts. A case is considered "empty" only if it
is either a non-payload case (`case a`) or if the payload
is zero-sized and non-generic. Generic cases are always
treated as non-zero-sized for purposes of determining
the layout strategy.
Correctly testing this is tricky, since some of the
layout strategies differ only in whether they export
extra tag values as XIs. The easiest way to verify is
to check whether wrapping the result in an `Optional<>`
adds another byte to the overall size.
This exercises a number of cases that the previous logic got
wrong, including cases where MPEs are laid out like SPEs,
and cases where we use the SPE or MPE layout strategies for enums
that have no non-empty payloads. (These cases are superficially
similar but differ in how they handle XIs.)
These new tests allowed me to correct a number logical flaws
about how layouts are selected. In particular, cases with
generic payloads are always considered to be non-empty for
purposes of selecting a layout strategy. Only cases that
are statically known to be empty are considered empty for
layout purposes.
We clear the NodeFactory to prevent unbounded buildup of allocated memory, but this is done too eagerly. In particular, normalizeReflectionName can end up clearing the factory while the calling code is still using nodes that were allocated from it.
To keep peak memory usage low while avoiding this problem, we introduce a checkpoint mechanism in NodeFactory. A checkpoint can be pushed and then subsequently popped. When a checkpoint is popped, only the nodes allocated since the checkpoint was pushed are invalidated and the memory reclaimed. This allows us to quickly clear short-lived nodes like those created in normalizeReflectionName, while preserving longer-lived nodes used in code calling it. Uses of clearNodeFactory are replaced with this checkpoint mechanism.
rdar://106547092
Allocate an empty BuiltinTypeInfo. The code previously allocated a TypeInfo but set its kind to Builtin, which led to calling code doing an incorrect cast and reading an invalid value for the Name field.
rdar://106563125
TypeInfoProvider's address was used as part of the key to cache type
infos. This can cause the unnecessary recomputation of type infos, as
different instances of TypeInfoProviders may provide the exact same type
infos. Allow TypeInfoProviders to provide an id which can be used for
caching purposes.
rdar://80001304
that contain zero-sized payloads, which should resolve a number of issues with
RemoteMirror incorrectly reflecting enum cases and/or measuring the layout of
structures containing enums.
Background: Enum cases that have zero-sized payloads are handled
differently from other payload-bearing cases.
1. For layout purposes, they're treated as
non-payload cases. This can cause an MPE to
actually get represented in memory as a single-payload
or non-payload enum.
2. However, zero-sized payloads are still considered for
extra inhabitant calculations. Since they have no
extra inhabitants, this tends to cause such enums to
also not expose extra inhabitants to containing enums.
This commit makes several change to how RemoteMirror determines
enum layout:
* The various "*EnumTypeInfo" classes now represent
layout mechanisms -- as described in (1) above,
this can differ from the source code concept.
* An Enum "kind" is separately computed to reflect the
source code concept; this ensures that the dumped
type information reflects the source code.
* For single-payload and no-payload _layouts_,
the extra inhabitant calculation has been adjusted
to ensure that zero-sized payloads are correctly
considered.
Resolves: rdar://92945673
Fix computation of generic params per level when a generic type is
nested in a non-generic one. For example, for the following code:
```
class A {
class B<T, U> {
}
}
```
Fix the array of generic params per level from [2] to [0, 2].
rdar://103457629