This continues work to eliminate pending generics/specifics and get them
to be interleaved with instruction imports. I'm trying to use
`FinishGenericOrDone` here as a way to help ensure that code correctly
handles generics, where the simple alternative would be for each
`TryResolveTypedInst` call `SetGenericData` directly (but which might
make it easier to call the wrong `ResolveResult` function, and we do
need the `GenericId`s to be passed).
Avoid using a large switch that needs to be manually extended when
adding a new kind of instruction. Instead, the expression category for
an instruction is now specified when defining the `InstKind`.
In passing, add a distinct expression category value for patterns. This
isn't used for much except some error checking at the moment, but it
keeps the number of instructions that we need to manually classify as
`NotExpr` despite having a type very low.
Replace all unexpected instruction ids in a line, not just the first
one. Otherwise you get something like this:
```
// CHECK:STDOUT: impl @<null name>: <unexpected>.inst{{[0-9A-F]+}}.loc20_6 as <unexpected>.inst6000002E.loc20_11;
```
This is just an incremental step towards removing pending logic. The
rest seems like it'll be more complex due to interdependencies (I've
been poking at behavior).
Following #6357, map C++ `void` to a prelude class type
`Core.CppCompat.VoidBase`, not to a builtin type. This is mostly just
moving logic around, but does notably change `Cpp.void` from being an
incomplete type to being a complete-but-abstract type.
Also change `NullptrT` to be an adapter for `void*` instead of `()*`, to
follow the approved design.
Implicit conversions to `void` and to `void*` are still absent.
Part of #6280.
Since `ValueStore` now separates its id and value types as two template
parameters, we can use a `ValueStore` of `optional<ValueType>` as the
storage instead of a `SmallVector`.
Otherwise the value fails in confusing ways while untagging:
CHECK failure at ./toolchain/base/value_store.h:71:
index >= initial_reserved_ids_: When removing tagging bits,
found an index that shouldn't've been tagged in the first place.
With this change:
CHECK failure at ./toolchain/base/fixed_size_value_store.h:112:
id.index >= 0: instFFFFFFFFFFFFFFFD
This is part of trying to rewrite pending specific/generic code to make
use of the standard constant resolution flow. The LoadImportRef code was
a particular sticking point due to the recursion it does, which makes it
difficult to adapt over.
We add tests showing that `ImplStore::GetOrAddLookupBucket` is doing the
wrong thing for impls of a named constraint, as the impl-file
redeclarations of impls in the api file are not getting flagged as such.
To do the right thing requires us to be able to get the constraint from
a require declaration with the specific of the named
constraint/interface applied, which is future work as described in the
[open discussion
notes](https://docs.google.com/document/d/1Yt-i5AmF76LSvD4TrWRIAE_92kii6j5yFiW-S7ahzlg/edit?tab=t.1ji9ixn9bbnn#heading=h.kijomnov90rz).
Every test that used `addr` before #6283 should be using `ref` after
this PR. In most cases that was done in #6283, but this PR transitions a
few that I missed in that first pass. In addition, #6283 cloned the old
`addr` tests from `foo.carbon` to `foo_addr.carbon` in order to maintain
test coverage during the transition; this PR removes those cloned tests.
The to_array was mainly needed for zip_equal, and the
GetBlockAsTypeInstIds is forming a vector that should also be size two.
But just writing this out should avoid memory allocations.
Of course, then I'm like "but maybe a lambda or function would be
clearer than a for loop"... So the second commit.
This helps at least lldb handle calling functions (currently the debug
info describes every function as `void()`, so no parameters or return
values are supported) - seems gdb and lldb both depend on demangling to
varying degrees in C code (marking a function as "prototyped" in C in
DWARF does seem to also address this problem).
Given:
```
fn PrintThree() {
Core.Print(3);
}
```
Before:
```
(lldb) p PrintThree()
error: Couldn't look up symbols:
PrintThree
Hint: The expression tried to call a function that is not present in
the target, perhaps because it was optimized out by the compiler.
```
After:
```
(lldb) p PrintThree()
3
(lldb)
```
This is the first real step towards building libc++ itself, and fleshes
out both the core runtimes management logic and the archive-based
runtimes logic for a quite simple runtime.
Nothing here causes us to _use_ libunwind, and in fact this doesn't
include even the "on-demand" aspect of building `libunwind`. Instead,
this just wires it up to the explicit `build-runtimes` subcommand for
simple testing. The full integration along side the target directory is
future work.
Previously, the Clang runtimes building only considered building the
target resource directory, and was only _internally_ asynchronous.
Because the asynchrony was only internal, it could use the function
frame as a context object throughout the build of the resource dir. This
is simple but doesn't generalize well to more runtimes: if we want to
add 2 or 3 more runtimes, we want them to _all_ build asynchronously.
That means using some asynchronous builder that maintains the context
and allows them to proceed concurrently with other work.
This also factors all the runtimes building code into a separate set of
files. These aren't separate libraries at this point due to the
`ClangRunner` in some cases wanting to build runtimes on-demand, but it
at least lets us organize the code more cleanly.
Because this splits code between `clang_runner.*` and
`clang_runtimes.*`, it also works to update the `#include`s for both to
be roughly accurate. I used ClangD's include cleaner for this and it
probably also did some latent cleaning as it went, but that's the reason
for the churn of `#include` lines.
The archive building is also factored out into a re-usable helper. This
is a bit "over factored" in this PR, but supports the next PR that uses
the same code to build archives for other runtimes.
This also overhauls the synchronization used -- it uses a simple `Latch`
construct introduced in a previous PR to coordinate between the steps of
building the runtimes.
Last but not least, it factors the "enable leaking" state out of a
boolean in the runner to a parameter. This is important in the face of
concurrent calls as otherwise toggling this boolean can create a race.
The next PR will layer building more runtimes on top of this new
factoring.
---------
Co-authored-by: David Blaikie <dblaikie@gmail.com>
There are two uses I'm not converting here, that seem to want the
"shortest" behavior. For everything else, I'm going to `zip_equal` since
it's more restrictive.
I wish `zip` were named `zip_shortest`.
This fixes the flakiness caused by reuse of inode values when refreshing
stale cache entries by keeping the relevant directory open even as it is
unlinked from the filesystem.
It does this in two places, as technically we had the same flakiness in
two tests. However, the second test was broken and not testing what it
intended to due to confusing off-by-one naming and a typo. I've tried to
improve the naming, removed the typo, and added the parallel flakiness
fix.
This test was also egregiously slow because we ended up building too
many runtimes and trying to prune stale runtimes while holding a file
lock on _all_ runtimes -- a scenario that is not what the code was
designed for in the first place. Fixing that makes the test go from 10s
to 1s in runtime, and makes it much easier to test for flakiness.
Now appears to pass 100% of the 10k runs I did.
Closes#6168
Move `GetWithDefault` into the `ValueStore` base class, and avoid doing
the tag -> index mapping twice.
Call `ValueStore::Get` instead of `ConstantValueStore::GetAttached` in
`GetUnattachedConstant`. This is equivalent, since we never need a
default value here, and should be faster and less surprising.
The standard `std::latch` is very restrictive in how it can be used, and
this makes it hard to easily leverage for simple coordination between a
set of dynamically scheduled tasks, where there isn't an interesting
synchronizing "merge" or future result.
This tool makes it easy to establish a latch, hand out handles to it,
and once all are destroyed, take whatever relevant action.
Note: this is split out of a larger change that uses it. I can wait
until the use case is ready, but seemed nice to review this separately.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
Proposal #5168 defines when a facet type must be identified or complete,
and what it means for an interface and a named constraint to be
identified or complete. This updates the toolchain to match the
requirements.
This implements identification of a facet type to require completed
named constraints and to include any interfaces from named constraints
into the resulting IdentifiedFacetType.
To complete a facet type, each interface in the IdentifiedFacetType, and
any interface named though a require declaration from them, must be
complete.
When importing an Interface or NamedConstraint, walk the block of
`RequireImplsId`s, and for each one:
- Import the RequireImplsDecl from it, which also imports the
`RequireImpls` structure and its id.
- Collect those decls and build a block of `RequireImplsId`s for the
local SemIR to reference from the Interface or NamedConstraint.
The import of RequireImplsDecl is done in a single phase instead of
three, unlike other decls. This is possible since require declarations
have no name, so they can't be referenced by instructions inside them,
thus there's no cycles to concern ourselves with.
This fixes various violations of C++'s One Definition Rule, where we
accidentally gave the same static data member multiple definitions in
different translation units. Clang happens to emit such definitions with
weak linkage, which allows us to get away with this without link errors,
but it's still formally incorrect.
Also switch keyword order around for a handful of instances of
`constexpr inline`, per agreement in open discussion.
This happens to reduce the size of a `-c dbg` toolchain binary by 7.2
MiB, presumably by making more of our symbols and especially debug info
discardable.
Give TupleLiteral and StructLiteral a constant value, if their contents
have constant values. Their constant values are TupleValue and
StructValue respectively. This supports their ability to convert to a
constant type (or facet type).
This way when deduce finds a TupleLiteral as the argument to a
_symbolic_ facet type, it can also find a constant value to use for that
argument. This allows deduction to move onto step two, where it can
substitute into the symbolic parameter from previous deduced arguments,
and then perform the conversion from the TupleValue to the desired facet
type.
Allow `PerformBuiltinConversion()` to convert from a canonical
TupleValue or StructValue to `type` instead of only from literals. Then,
also support conversion from a symbolic binding of type TupleType or
StructType to `type`.
- Makes a little more use of `MakeImportedLocIdAndInst` instead of
`UncheckedLoc`
- Requires use of `MakeImportedLocIdAndInst` with `ImportIRInstId`;
previously optional
- Relevant `if constexpr` moves to `AddPlaceholderImportedInst`, but is
more narrowly scoped there.
- Refactors out `AddPlaceholderImportedInstInNoBlock` to reduce how many
spots do an explicit `imports().push_back(...)`
I'd also considered removing `MakeImportedLocIdAndInst` where possible,
but went this route so that changes to the expected parse node wouldn't
affect callers. When it's required, `MakeImportedLocIdAndInst` is always
there; when it's conditionally present, changing `Parse::NodeId` between
enforceable and not-enforceable would require refactoring any callsites
that assumed one or the other.
When the missing definition is diagnosed at the end of the file, the
witness is set to an error. Impl lookup was skipping impls entirely when
the witness was an error, which means a non-final LookupImplWitness
could be later evaluated against a specific and crash since the lookup
fails instead of returning the error.
The same crash could also occur when verifying poisoned queries hadn't
changed, but now it can find an ErrorInst witness instead, so it is
changed to handle that gracefully.
Add a `Core.CppCompat.NullptrT` type that C++'s `nullptr_t` maps into.
Map `nullptr` to an uninitialized constant of that type -- `nullptr`
doesn't actually have any defined bits within it, despite having the
same representation as `void*`.
Right now some of the `ResolveResult` factories are on it, ones that
involve `ImportRefResolver` aren't; this more consistently makes callers
use `ResolveResult::` when returning a result.
I was looking at this due to the addition of more
`GetAsTypeInstId(AddLoadedImportRef(` in #6344. Looking at
`AddLoadedImportRef`, it also felt like the first declaration would be
clearer if collapsed into its overload (the overload is the only
caller). Note one benefit of using `ImportContext` in
`AddLoadedImportRef` is being able to call
`local_constant_values_for_import_insts` to handle the `GetRawIndex`
code.
Uses `clang::Parser::ParseConstantExpression()` to parse the macro
replacement tokens, added as a token stream to the preprocessor. This
extends the support from simple object-like macros with a single
replacement token, to multiple tokens like unary operators, binary
operators, casting, nested macros etc.
The support is still limited to macros that are evaluated to an integer
constant. More types to be added as a follow-up.
Part of #6303
This has subtle effects on the number of imported instructions, but
seems more standard for how this code is being written...
`GetLocalConstantId` calls `GetLocalConstantValueOrPush` which does
`local_constant_values_for_import_insts().GetAttached`. So what this is
really doing is causing some intermediate import steps to be skipped.
But per test changes, that doesn't really affect SemIR and will probably
have negligible effect. This *seems* right to me, otherwise I'd expect
we should probably refactor all `GetLocalConstantId(InstId)` calls.
When we `impl as Z` and `Z` is an interface with a require relationship
to another interface `Y`, we produce an error at the definition if the
self type does not impl the required interface `Y`.
The require relationship need not be satisfied yet at the declaration of
the `impl as Z`, and a declaration of `impl as Y` is enough to write the
definition of `impl as Z`.
They are not used for impl lookup or verifying anything yet, but now
they appear in the textual semir.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
The `RequireDecl` instruction points, via a `RequireImplsId` to a
`RequireImpls` structure in a `ValueStore`. That structure holds the
self-type and facet type, as well as the generic id and parent scope.
`RequireImpls` is always a generic since it only appears in an
`interface` or `constraint`, which both have a generic parameter `Self`
applied to all their members.
The `RequireDecl` instruction evaluates to itself, but drops the
decl_block_id since the instructions within the `require` declaration
are not required in the canonical value which is only used for import.
And import will want to import the `RequireImpls` structure along with
the `Interface` or `NamedConstraint` structure it is in, rather than
recreate it from the decl's instructions. This also avoids repeating all
the instructions within the `require` decl in the textual semir's
constants block.
Adding the `RequireImpls` to the `Interface` or `NamedConstraint`
structure is not yet done, so they are not available for impl lookup or
import yet.