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.
Adds support for object-like macros with a single replacement
numeric-literal kind token. Only macros that evaluate to an integer
constant are supported for now. When detected at name lookup, they are
imported as a constant integer value in Carbon.
Demo:
```c++
// --- macros.h
#define CONFIG_VALUE 2
```
``` c++
// main.carbon
library "Main";
import Cpp library "macros.h";
import Core library "io";
fn Run() {
let a: i32 = Cpp.CONFIG_VALUE;
Core.Print(a);
}
```
```c++
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link main.o \--output=demo_carbon
$ ./demo_carbon
2
```
Part of #6303
Most inputs are matched against the current regex. An input that starts
and ends with `/` sets a new regex instead. EOF terminates the program.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
This unit test uses "using UEnum = Enum;" and imports that into Carbon.
This is my very first try at contributing something to carbon, I'm
looking forward to your feedback.
The test is very basic.
What other cases should it test ?
What other comments do you have ?
Do this even if the operand is a `ConstType` instruction. This better
preserves the source form of the type, and avoids a special case.
Repeated `const`s are already flattened in constant evaluation, and this
special case also didn't prevent forming a `ConstType` whose operand is
`const` in general, only cases where the operand happens to literally be
a `ConstType` instruction.
This reverts commit eed21f6439.
Completing a pointer type is trivial, but we still need to do it, and
fail to do so in a few places, which can lead to crashes during
lowering. Switch to completing pointer types when the type is created to
avoid the issue.
Format the entity name into the instruction name for a FacetAccessType
of a SymbolicBinding. This means (T as type) gets formatted as
`T.as_type` instead of just as `as_type` for the non-canonical
FacetAccessType instruction. The same is already true for the canonical
SymbolicBindingType.
If the value representation of `T` is a copy representation, but it
copies all of the bits of `T`'s object representation, then it's OK to
use that as the value representation of `MaybeUnformed(T)` too.
This fixes the behavior of interop with nullable pointers, which are
represented as an adapter of `MaybeUnformed(T*)`, and need to be passed
to and returned from functions on the Carbon / C++ boundary as `T*`s.
Adds support to the `dump` debugger command for named constraint ids,
which are printed as `constraint<number>`. While doing so, we print
whether the `constraint` is complete or not, and add the same to
`interface` to match.
And we noticed that the printing of name and name scope ids, which are
not tagged, are very verbose by adding 7 `0`s to them for no reason. So
make the dump output easier to read by dropping 0 prefixes.
Before:
```
name_scope00000000: {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name00000000: inst6000000F, name00000001: inst60000011}} {kind: Namespace, arg0: name_scope00000000, arg1: inst<none>, type: type(inst(NamespaceType))} `package`
```
After:
```
name_scope0: {inst: instE, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst6000000F, name1: inst60000011}} {kind: Namespace, arg0: name_scope0, arg1: inst<none>, type: type(inst(NamespaceType))} `package`
```
This turns `Cpp` into a keyword, and makes it map to `NameId::Cpp` and
`PackageNameId::Cpp`.
Per discussion with zygoloid, the keyword versus identifier question is
deliberately kept open by #4846. This PR switches to a keyword because
mapping to a specific `PackageNameId` works best with a special `NameId`
not backed by an `IdentifierId`. We could in theory make it work using
`IdentifierId` or a runtime-tracked `PackageNameId` for `Cpp` (e.g.
stored on `SemIR::File`), but this approach is consistent with `Core`
and so seemed like a good starting point.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
If `T` implicitly converts to `U`, then:
* `const T` implicitly converts to `U`,
* `T` implicitly converts to `const U`, and
* `T` implicitly converts to `Optional(U)`.
Adds a flag `--optimize=<mode>` that specifies what to optimize for:
* `--optimize=none` turns off the optimizer as much as possible, but
still respects always_inline.
* `--optimize=debug` aims to be the equivalent of `-Og` / `-O1`, and
provides optimizations that don't affect the ability to debug the
program. This is the default.
* `--optimize=size` optimizes for the size of the produced program, and
aims to be the equivalent of `-Oz`.
* `--optimize=speed` optimizes for the execution time of the produced
program, and aims to be the equivalent of `-O3`.
Following the approach taken by Clang, the optimization level feeds into
both the configuration of the LLVM pass pipeline and the attributes
added to function definitions generated by the frontend.
Optimization is performed in a new phase, `optimize`, which runs between
`lower` and `codegen`.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
I was thinking that the incompleteness diagnostic for C++ types would've
been produced by Clang for record types, but seems they're produced by
Carbon & we already /are/ sharing that diagnostic (with #6302), and that
patch only adds an extra note rather than being a whole separate
codepath for effectively the same diagnostic.
As a byproduct, the only test that exercised the "address of a temporary
object" diagnostic now trigers the "address of a non-reference
expression" diagnostic. We could restore it by using a type that doesn't
support `value_of_initializer`, but it seems better to remove the
diagnostic altogether: not only does it simplify the code, I'd also
argue "non-reference expression" is more accurate as a user-facing
description of the operand.