Pursuant to recent decisions on #6124, switch `Destroy` to use a
`CustomWitness` for its implementation. Right now this is manufacturing
no-op implementation functions on each lookup, which obviously isn't
ideal but is intended as a first pass. I'm mostly trying to find the
right balance between updating the approach to reflect new decisions,
while still breaking apart work in a way.
The `CoreInterface` logic is intended to build on `CoreIdentifier`
support. We have a number of additional interfaces that require
specialized logic, and that'll extend pretty far with C++ interop, so it
seemed easiest to have a generic function for it. That's what's
replacing the logic inside C++ interop that was doing string comparisons
(which could have already been moved to `CoreIdentifier`, I just missed
it in my first pass).
This adds `CustomWitness` support because the `Destroy` witnesses can be
imported cross-file. `CustomWitness` was previously only used for C++
types, which don't yet support import, which is why that wasn't
previously an issue. The addition of `query_specific_interface_id` is
similarly needed in order to get correct sorting of witness blocks when
imported.
This PR also removes builtin constraint logic (note this is in a
separate commit to help review; it's not a separate PR because it's
difficult to split apart without tests breaking). This had been made
generic with the expectation that destroy, copy, move, and conversions
would all need related support. Under the new decision, we are not going
to do blanket impls and will instead just manufacture a `CustomWitness`
for everything.
A lot of SemIR fingerprints change, but that's probably because the
addition of `Destroy` on core classes is yielding structural changes.
### Description
Currently, unqualified access to private members of the base class
compiles without error. This is due to `LookupUnqualifiedName` calling
`LookupQualifiedName` internally with `access_info` parameter set to
`std::nullopt`. This causes `IsAccessProhibited` to return `false`
immediately.
This PR fixes this issue.
### Changes
- Added a check where if the `access_info` is null and the current scope
we are looking is an extended scope (parent), initializes the
`access_info` with `highest_allowed_access` set to `Protected`.
Fixes#6239
Allow passing a C++ template as a template template argument to another
C++ template. Does not allow passing a Carbon generic as an argument.
Depends on #6474.
Instead of naming the root namespace `package` (because it's accessed by
the `package` keyword), change it to use the current package name. Note,
buried in the checksum changes,
`toolchain/check/testdata/package_expr/fail_not_found.carbon`:
```
- // CHECK:STDERR: fail_not_found.carbon:[[@LINE+4]]:16: error: member name `x` not found in `package` [MemberNameNotFoundInInstScope]
+ // CHECK:STDERR: fail_not_found.carbon:[[@LINE+4]]:16: error: member name `x` not found in `Main` [MemberNameNotFoundInInstScope]
```
for:
```
// CHECK:STDERR: var y: i32 = package.x;
// CHECK:STDERR: ^~~~~~~~~
```
I'll leave it to you if you prefer this; the alternative I see is to
just rename `IsCorePackage` to `IsImportedCorePackage`, and/or change it
to a helper that takes a `Context` and does the right thing with
`parse_tree` (which, I need for `Destroy`-related reasons and was my
default approach).
This is in anticipation of using the same construct for all
implementations of `Destroy`, as well as other similar use-cases with
language-defined interfaces.
Expose C++ class templates, variable templates, alias templates, and
concepts as callable values in Carbon, and map calls to them into
template-id formation, mirroring how Carbon generics behave. For now,
only type template parameters are supported; non-type and template
template parameters produce a TODO error.
Instead of parsing a complete C++ translation unit and then interacting
with the translation unit further after the fact, delay finishing the
translation unit until we finish the Carbon check phase. This fixes some
issues where we would produce duplicated or incorrect diagnostics at the
end of the C++ translation unit, particularly for unused declarations.
Now we're in control of how we parse the translation unit, also disable
parsing of C++20 modules if the syntax appears within `import Cpp
inline` code.
Keep the same clang parser alive throughout check, and use it instead of
building a new one when parsing macros. This resolves issues where the
translation unit scope was destroyed too early, resulting in unqualified
lookup within macros being unable to find global scope entities.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This separates the return type from the return pattern, and replaces the
return pattern with a block of return patterns. This is a step toward
support for `ref` returns (where there's no corresponding return
pattern) and compund-form returns (where there may be multiple return
patterns).
This is a prerequisite for support for interop with C++ template names.
No behavior change here, except that it sadly changes the fingerprinting
for a lot of tests.
Add a `CppWitness` and use it instead of using `ImplWitness` with an
`ImplId` and `SpecificId` of `None`. This witness can be substantially
simpler because we never need a `SpecificId`.
Similarly to the enums, these are for the moment only available when
referenced with a global scope “::”. Only integer constexpr are
available for now.
Part of #6303
Some of the macros tests were not printing the SemIR. Printing it can
help spot issues (as in PR #6440), so added that now for all passing
tests.
Part of #6303
If an impl lookup finds a final result, cache that and reuse it if we
perform the same lookup later.
In addition to reducing repeated work, this allows us to produce the
same result for repeated lookups that find a C++ operator. This isn't a
great solution to that problem, as it's not clear how to extend it to
behave correctly across import, but we don't have a solution for that
for C++ interop in general.
When performing impl lookup for `Core.Copy` for a C++ class type, look
for a copy constructor. If we find one, synthesize an impl witness that
calls the constructor.
This adds initial support for impl lookup to delegate to the C++ interop
logic for queries involving C++ types. For now, we don't implement the
rules from #6166 that compare a synthesized type structure for the C++
impl against the best Carbon type structure, but the framework for
building that support is established here.
Currently there is no caching of the lookup here, and we build unique
`ImplWitnessTable`s for each lookup, which leads to each impl lookup
producing a distinct facet value. This results in some errors in generic
contexts; this will be addressed in follow-up changes. This PR aims only
to support the non-generic case.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
This extends #6364 to allow having:
* `Cpp.unsigned_long` as a distinct type when `unsigned long` is 32
bits.
* `Cpp.long_long` and `Cpp.unsigned_long_long` as distinct types when
`long` and `unsigned long` are 64 bits.
Similarly to #6364, we only support implicit conversions from the
matching literal type (`u32`, `i64` and `u64`).
See #6275 for rationale.
Part of #5263.
We already did this translation in the other direction, but we had no
mapping from `Optional(T)` to anything, so round-tripping a nullable
pointer from C++ through Carbon and back to C++ was previously rejected.
Enum constants in a macro replacement list are recognized only when
prefixed with “::”.
There is a `todo` test to make explicit that this still needs to be
fixed.
When prefixed with a global scope “::”, they are correctly found and
evaluated to a const.
Part of #6303
Don't attempt to defer overload resolution by creating a
`CppOverloadSet`; this was incorrect as we weren't saving the complete
clang::OverloadCandidateSet, resulting in template candidates not being
found. Moreover, saving the overload candidate set would be expensive,
as the representation is surprisingly large, and is unnecessary since
we're about to build a call.
In passing, improve the diagnostics for overload resolution failure to
use Clang's operator overload resolution messages rather than its call
overload resolution messages.
This fixes calls to templated operator overloads, which is the final
piece needed for us to successfully compile an iostream-based "Hello
world" program.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
I was trying to figure out the right way to get specifics to be added to
the work.
Technically, we could keep the pending_specific list; this is taking a
different approach of inserting inside the work stack, which will do
extra work moving entries, although typically that should be expected to
be small. One challenge of `pending_specifics` is that if we would need
to shift them to work after both `Done` (for immediate processing) and
`Retry` (for processing after the current instruction is later revisited
and done). That feels kind of awkward as additional tracking to do.
Also, the common case is probably that there's either 0 or 1 specifics
being added, so an additional vector may be significant overhead. That's
why I leaned more in this direction of just inserting them in the vector
of work.
For now, treat such classes as being final, since we can't correctly
derive from them.
This removes the last category of C++ class that we are entirely unable
to interop with, and is a prerequisite for interop with C++ iostreams
(which have a virtual base class).
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).
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.
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.
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`.
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*`.
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
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>
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
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 ?
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.
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>