This resolves a TODO in `expr_info.cpp` by using the inst kind rather
than the bound value to track the binding's category.
Since we're churning all the `bind_name` insts in testdata anyway, I'm
also taking this opportunity to align the inst naming with the design's
terminology, by calling these insts "bindings" (this aspect of the PR is
dependent on #6231 resolving an ambiguity in that terminology). For
consistency we'll need to rename several other insts as well (see the
TODO on `RefBinding`); I'm deferring that to a separate PR to minimize
the review load, but I think those name changes are in-scope for this
review.
`const` doesn't mean much on the type of a value expression; it's valid
to remove it because we can't perform modifications to a const value
regardless.
We already allowed most of this, but only as part of adapter conversion
rather than in general, and we didn't previously allow it when the
source of the conversion was a reference expression.
---------
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
This demonstrates two issues:
1. It seems like we wrongly treat private static data members the same
way we treat protected and allow access to them from within derived
classes member functions.
2. Calling instance member functions of a base C++ class using a derived
class as self (no implicit upcast) is not yet supported. This isn't
related to access control, but prevents us from testing some access
control use cases.
Part of #5859.
Implemented by generalizing the reference type support for parameters
and return values to other use cases.
The changes to the `method.carbon` test are due to to supporting the
reference types but not supporting the necessary conversions.
C++ Interop Demo:
```c++
// global.h
struct C {
int member = 0;
int& member_ref = member;
};
extern C& global;
```
```c++
// global.cpp
#include "global.h"
static C static_c;
C& global= static_c;
```
```carbon
// main.carbon
library "Main";
import Core library "io";
import Cpp library "global.h";
fn Run() -> i32 {
Core.Print(Cpp.global->member);
++(*Cpp.global->member_ref);
Core.Print(Cpp.global->member);
++(*Cpp.global->member_ref);
Core.Print(Cpp.global->member);
return 0;
}
```
```shell
$ clang++ -stdlib=libc++ -c global.cpp
$ bazel build toolchain:carbon && bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link global.o main.o --output=demo
$ ./demo
0
1
2
```
**Without this change**:
```shell
main.carbon:10:14: error: semantics TODO: `Unsupported: var type: C &`
Core.Print(Cpp.global->member);
^~~~~~~~~~
main.carbon:10:14: note: in `Cpp` name lookup for `global`
Core.Print(Cpp.global->member);
^~~~~~~~~~
```
Part of #6006 and #6186.
The tests are almost identical and test the same logic so basically
duplicated.
The extra coverage that was in `struct.carbon` is added to
`class.carbon`.
One basic test in `struct.carbon` was left just to make sure `struct` is
supported.
Part of #5150.
When deducing arguments for generic parameters of an `impl`, the
deduction calls `Convert` on the input arguments. Often, the input
argument is a facet, and needs to be converted to a type via
FacetAccessType in order to produce a different facet. These
instructions end up being added to the semir, but only their constant
values are needed for the resulting specific returned from Deduce.
In the best case, these extra instructions are just noise in the semir,
or they just cause instruction names to get differentiated with larger
suffixes.
In the worst case, these extra instructions contain references to
instructions from a generic context, and leak them out of that generic
context and into another. In particular, when importing a
LookupImplWitness instruction, the re-evaluation of it can do deduce
(when the lookup is against a generic `impl`). The instructions created
in Deduce are not part of the import, and end up referring to imported
instructions from the local context, which leads to confusion in the
toolchain, and can crash.
The `import_self_specific.carbon` test demonstrates this. It causes the
`I.F` function to be imported from the `I` interface when building the
witness table for the `impl`. Doing so imports the specific of `C` which
includes a LookupImplWitness for `Self.Accoc` in `I`. The `Self` is a
BindSymbolicName with generic binding index 0, in `I`. When Convert
creates instructions in the generic `impl forall D`, however, they end
up referencing and including this BindSymbolicName into its eval block.
But the generic binding 0 in the `impl` is a very different thing (a
value of type `E`). This confusion leads to crashes.
This fixes a bug, which seems to have been introduced in #6108.
In the new test, without this change, we will diagnose with
```
error: semantics TODO: `Unsupported: parameter type: ExplicitObjectParam` [SemanticsTodo]
```
The SymbolicBindingType refers to the type value that will be
substituted in for the BindSymbolicName, but holds onto the EntityNameId
from the BindSymbolicName instead of (or in addition to, for now) the
instruction.
The EntityNameId will be used to look in the ScopeStack to find the
witnesses either from the BindSymbolicName instruction, or other
instructions that specify `impls` constraints against the EntityName.
This will allow us to have the `T` in `I(T)` resolve to a `.Self`
reference in the type so that we get type equality with the binding's
type: `T:! I(.Self)`.
After this change, we correctly increment the offset by the next switch
case type.
Before this change, we accidentally incremented the offset by
`functions()` size instead of `cpp_overload_sets()` size and vice versa.
Also sorted the switch cases according to the order of the enum, for
consistency. This might help prevent a future similar incident.
This fix prevents crashing in the newly introduced test
`multiple_too_few_args_calls`.
This also has the side effect of showing `null name` for
`cpp_overload_set_type` and `cpp_overload_set_value`, instead of having
an arbitrary name.
Examples that demonstrate the old name is arbitrary can easily be seen
in tests like `cpp_namespace.carbon` and `decayed_param.carbon`, but
careful review would show that all old names are arbitrary, though often
luckily almost make sense.
We might want to have a proper name for these, but it's beyond the scope
of this crash fixing change.
See #6156.
Part of #5915.
This also does a little restructuring in the same direction, following
#6124.
Leads want `Destroy` to work similarly now for all types. As a
consequence, there doesn't seem to be as much benefit to splitting off
aggregate destruction. In this PR, the `type.destroy` function can now
be expected to destroy anything that's destructible; that means it'll be
usable for the `final fn` once that support is available.
Similarly, this gets rid of the impls other than the single blanket
impl, now using `type.can_destroy`. Since they all need to use the same
function, there's no benefit to splitting approaches. Also, now it can
just be a `final impl` since there should be no need for people to
create specializations -- if this blanket impl applies, it means the
`final fn` is the same.
This also slips in `partial` support since there's no reason to have it
diverge anymore. Also `abstract`, which I'm not sure is broadly testable
since most cases it'd come up, the `abstract` keyword is explicitly
detected/rejected.
Note though that this doesn't make any really big changes. It's just
realigning on the leads decision. I'm going this way to try to reduce
name-related churn for other changes.
Locations are similarly fragile, because adding a comment changes them.
This has made me pause when making prelude changes in #6144, so dropping
them for those cases.
Instruction ids aren't actually that interesting outside debugging, and
can be churny when doing other structural changes. I've seen this in
particular when doing singleton changes, which bump every instruction
id.
Note there are still other ways fragility from locations can crop up.
This shouldn't be considered a complete fix, but hopefully a small
improvement.
Right now, the class destroy impl is incorrectly generated (first
discussed [in
Discord](https://discord.com/channels/655572317891461132/941071822756143115/1418614787449032826)).
If we want it to be correct, deferred definition logic would need to be
added, and the declaration would need to be moved inside the `class`
scope (along with whatever generic logic that needs).
This instead switches to a blanket impl, to avoid creating latent bugs
with generating the `impl` and function body in the wrong scope. This
approach uses the same blanket impl as aggregate destruction that was
added by #6098.
The intent here is to allow progress on other parts of `Destroy`. For
example, under this model the implementation of the function body could
be done as part of lowering the specific.
This turns out to be quite important, as several important standard
library types (such as `std::string`) have mixed-access overload sets
for their constructors as an implementation detail. The overall approach
here is:
- Use the most permissive access to determine the access of the overload
set itself. This affects whether name lookup finds the member name at
all.
- After overload resolution, re-check the access of the selected member,
if it's protected or private.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
If there's a unique "preferred" base class, then treat that as "the"
base class for Carbon's purposes. In particular:
* If there's exactly one polymorphic base class, that's our preferred
base class.
* If there's exactly one non-empty base class, that's our perferred base
class.
* (Degenerate case) If there's exactly one base class, that's our
preferred base class.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Don't ignore deleted constructors in overload resolution. If one is the
best match, we want an error rather than picking something else. Don't
crash if we find a constructor template or other weird thing; use
`getConstructorInfo` to map it into a constructor and skip it if it
isn't one, like Clang does.
The general strategy here is to force use of a thunk when we want to use
default arguments, and have Clang generate uses of the default arguments
on its side of the thunk.
To support this, change the key type used in `clang_decls` from being
just a `Decl*` to being a pair of `Decl*` and number of parameters in
the case of function decls. Import distinct `SemIR::Function`s for each
number of parameters that's used, and corresponding distinct thunks.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
If a `BindSymbolicName` is converted to `type` and then to its exact
`FacetType`, we get a `FacetValue` wrapping the `BindSymbolicName` but
providing no different information: it has the same witnesses and
`FacetType` as the original `BindSymbolicName`. Yet it is a different
constant value, creating multiple canonical forms with the same meaning.
Now we make that `FacetValue` with the same `FacetType` as the
`BindSymbolicName` it wraps evaluate back to the `BindSymbolicName`,
making it the unique canonical form.
This makes the "shortcut" in convert for avoiding impl lookup when
converting from `FacetAccessType` to `FacetType` in this exact scenario
work the same as doing the full impl lookup.
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Include notes listing the candidates and explaining why they didn't
work. Rather than duplicating the (substantial) logic for this, use the
Clang machinery to generate these diagnostics.
In order to support this, add a mechanism to map `SemIR::LocId`s to
`clang::SourceLocation`s. This works by creating source buffers in Clang
that refer into the Carbon source file so that `SourceLocation`s can
point into them.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
The main direction of this change is the edits to `destroy.carbon`
(matching in both prelude and min_prelude).
Previously there was a no-op blanket impl for `Destroy`, which hid all
missing implementations of `Destroy`. This does a few things:
- Sets up builtin aggregate destruction for struct and tuple types as
before, but also adds C++ class types and array types to the same
handling. (all as a TODO for actual implementation)
- Also maybe-unformed destruction, for now at least. (there's a chance I
may try a different approach on this, but the impl lookup wasn't working
as I'd hope in order to write it in code)
- Adds handlers for simple things that are easy to do in code: `type`,
`bool`, pointers. (because these are no-op destruction)
- Redirect `const T` destruction to `T` destruction.
This leaves as future issues:
- `partial T` destruction. (this can't be done similar to `const`
because it only works for non-`final` class types; I think `class`
definitions should just generate what's needed)
- Destruction of other prelude-provided types. (will probably come up as
we implement class destruction, that the adapted builtin type doesn't
implement `Destroy` -- but may end up special-casing that in a way that
moots it)
This moves the `&` operator from `facet_types.carbon` to
`convert.carbon` because more things need to handle type and now that
we're getting separate copy and destroy interfaces. It should be
low-cost (an interface and builtin) so hopefully this is the right
balance for complexity and re-use.
A few tests are also edited in order to focus them more on what they
intend to test, and avoid a `Destroy` dependency.
Only do the lookup when the class is complete.
Before this change we crash in `Sema::LookupQualifiedName()` on
`Declaration context must already be complete!`.
This is Itanium-specific for now (explicitly downcasting to the itanium
vtable handling code in Clang) - though it doesn't look like it'd be a
big stretch to either have conditional/two codepaths down Itanium and
MSVC in Carbon, or maybe add a virtual function in clang to avoid
needing to conditional+downcast in Carbon.
Here's a working example:
`dynamic_type.h`:
```
#ifndef TEST_H
#define TEST_H
struct A {
virtual auto virt0() -> int;
virtual auto virt1() -> int;
};
auto GetVal() -> A* _Nonnull;
#endif
```
`test.carbon`:
```
library "test";
import Cpp library "dynamic_type.h";
import Core library "io";
fn Run() {
var a: Cpp.A* = Cpp.GetVal();
Core.Print(a->virt0());
Core.Print(a->virt1());
}
```
`dynamic_type.cpp`:
```
#include "dynamic_type.h"
auto A::virt0() -> int {
return 0;
}
auto A::virt1() -> int {
return 1;
}
struct B: A {
auto virt0() -> int override {
return 7;
}
auto virt1() -> int override {
return 42;
}
};
auto GetVal() -> A* _Nonnull {
static B b;
return &b;
}
```
```
$ ./bazel-bin/toolchain/carbon compile test.carbon
$ clang++-tot -g dynamic_type.cpp test.o --output=a.out
$ ./a.out
7
42
```
(linking with `carbon link` failed because we aren't linking to the C++
runtime yet, it seems, so: `ld.lld: error: undefined symbol: vtable for
__cxxabiv1::__class_type_info`)
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
* Add support for template candidates by calling the suitable
`AddCandidate` function for them.
* Add support for overloading on `*this` qualifiers by calling
`AddMethodCandidate` when appropriate.
* Make mapping from Carbon arguments to Clang arguments a little more
faithful by mapping the Carbon expression category into the Clang value
kind.
This is in support of a goal of changing the blanket `destroy` impl to
use (roughly):
```
private fn CanAggregateDestroy() -> type = "type.can_aggregate_destroy";
// Handles aggregate type destruction.
impl forall [AggregateDestroyT:! CanAggregateDestroy()] AggregateDestroyT as Destroy {
fn Op[addr self: Self*]() = "type.aggregate_destroy";
}
```
That isn't done here because there's still other issues that migrating
raises. What this *does* do is add the builtin functions, and in
particular, support to `FacetTypeInfo` to make `CanAggregateDestroy`
work.
The "special requirement" approach in `FacetTypeInfo` allows us to
support restricting a blanket impl under the current approach of impls.
Maybe we'll find a cleaner approach that can work in the future, but
this fits into the current model by propagating similar to other
requirements. I'm using an enum mask because we have a number of similar
things to add (e.g. copy, move) but I'm not sure we need a full vector.
A few alternatives considered were:
- Supporting syntax more like `where .Self impls
TypeCanAggregateDestroy(.Self, SupportedInterface,
UnsupportedInterface)`. I think it'd be a little cleaner, but requires
better compile-time evaluation in order to assess the type of the call.
Right now it's expected to be a `FacetType` too early to make this work,
and I was concerned about pouring too much more time down this route.
- Providing an actual interface, in particular doing name lookup back
into `Core.` for an interface. This would've added name lookup overhead,
and the question of whether an `impl` exists.
- Generating an interface. This avoids the name lookup, but would still
raise the question of whether an `impl` should also be generated. Work
I've previously done generating interfaces for class destruction also
feels complex to both write and understand (an unfortunate issue).
- Still modeling as an `ImplsConstraint`, for example by defining a
special `InterfaceId::CanAggregateDestroy = -2` similar to what we do on
other ids. I was hesitant because of how this expands the number of
modes of `InterfaceId`, and things for consuming code to watch out for,
for what feels like a relatively niche set of use-cases that are only
interface-like.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
As proposed in [Carbon: C++ interop for overloaded functions and
function
templates](https://docs.google.com/document/d/1KUxumZtNe3mY3TsjW2s_ZADOlAaFlrtsLKHVILtqIaM/edit?tab=t.0),
Clang is used to perform the overload resolution using C++ rules, when
an overloaded C++ set is called from Carbon. Once a function is
selected, it's converted into a Carbon function and called using the
Carbon rules including argument conversions.
A single non-templated function is treated the same way as an overload
set and the same rules apply for its call.
Template functions are not supported yet.
Demo:
a) Non-templated function calls:
```c++
// --- overloads.h
auto foo(int a, short b) -> void;
auto foo(double a) -> void;
auto foo(int a) -> void;
```
```c++
// overloads.cpp
#include "overloads.h"
#include <cstdio>
auto foo(int a, short b) -> void {
printf("hello from foo_int_short(%d, %d) \n", a, b);
}
auto foo(double a) -> void { printf("hello from foo_double(%f) \n", a); }
auto foo(int a) -> void { printf("hello from foo_int(%d) \n", a); }
```
```c++
library "Main";
import Cpp library "overloads.h";
fn Run() -> i32 {
Cpp.foo(1.1 as f64);
return 0;
}
```
```
$ clang -c overloads.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link overloads.o main.o --output=demo
$ ./demo
hello from foo_double(1.100000)
```
b) Constructors:
```c++
// --- constructor_overloads.h
class C {
public:
C();
C(int a, int b);
};
```
```c++
// constructor_overloads.cpp
#include "constructor_overloads.h"
#include <cstdio>
C::C() { printf("hello from C() \n"); }
C::C(int a, int b) { printf("hello from C(%d, %d) \n", a, b); }
```
```c++
library "Main";
import Cpp library "constructor_overloads.h";
fn Run() -> i32 {
let c1: Cpp.C = Cpp.C.C();
let c2: Cpp.C = Cpp.C.C(1, 2);
return 0;
}
```
```
$ clang -c constructor_overloads.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link constructor_overloads.o main.o \--output=demo
$ ./demo
hello from C()
hello from C(1, 2)
```
Follow-ups:
- `Cpp.foo({})` - proper handling of struct literals as call args.
- Fix access for overloaded sets.
- Fix tests:
- Method calls: `error: missing object argument in method call
[MissingObjectInMethodCall]` in tests.
- Fix `toolchain/check/testdata/interop/cpp/import.carbon` test.
- Fix `enums` support.
- Fix `str` -> `std::string_view` mapping.
Part of #5915
This proposal renames the syntax used to mark an overriding definition
of a virtual method from `impl fn` to `override fn` to avoid ambiguity:
besides indicating an overriding virtual function, it can be parsed as
an "impl" declaration when the construct following "impl" begins with a
lambda introduced by "fn".
Closes#5711
---------
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
When returning a value from a function whose return type has a by-copy
initializing representation, perform initialization like we do when the
return type has an in-place initializing representation. This makes our
SemIR representation more uniform, as the return expression will now
always be an initializing expression rather than a value expression, but
more importantly it means that attempts to return a non-copyable type by
value now fail, even if the type has a by-copy initializing
representation.
This catches a bunch of places where we were returning a value of an
unconstrained template parameter `T:! type`, which we were incorrectly
allowing because we didn't notice it was not copyable. Unfortunately
this then requires quite a few test updates.
Like #6034, this exposes a lowering issue where lowering crashes when
attempting to lower a specific copy operation for certain types; a
couple more tests are temporarily disabled here. An upcoming PR
dependent on this one will fix the issue and re-enable those tests.
Instead of hardcoding which types are copyable, add a `Core.Copy`
interface to perform copying. Move almost all the current copy support
to that interface. Some remaining pieces are still using builtin logic
after this PR:
* For tuples and structs, builtin logic is used to perform elementwise
copies. This also supports copying *adapters of* tuples and structs,
which seems like it may not be desirable, especially for non-extending
adapters. A `Copy` impl is provided for tuples of at most 2 elements, so
that `Core.Copy` constraints are satisfied, but we can't implement this
generally until we have variadics support, and don't yet have a
mechanism to generalize this to structs.
* For `enum` types imported from C++, builtin logic is used to perform a
copy. This is temporary until we have a mechanism to identify these
types from an impl in the prelude.
One lowering test in `toolchain/lower/testdata/class/generic.carbon` is
disabled for now, as it causes a crash in the lowering code due to an
ABI mismatch between the call signature in the lowered declaration of a
specific function and the call that is generated in the specific callee.
Fixing this is a little involved, and will be done in a separate PR.
---------
Co-authored-by: Geoff Romer <gromer@google.com>
This avoids impl lookups involving, say, `Core.Int` pulling in all ~65
impls in "prelude/types/int", which resulted in a lot of unnecessary
importing work, followed by a lot of unnecessary inst namer and inst
formatter work.
Before:
```
Ran 1335 tests in 6186 ms wall time, 146818 ms across threads
Slowest tests:
- toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon: 5611 ms, 5532 ms in Run
- toolchain/check/testdata/interop/cpp/function/operators.carbon: 2034 ms, 1981 ms in Run
- toolchain/check/testdata/primitives/import_symbolic.carbon: 1796 ms, 1786 ms in Run
- toolchain/lower/testdata/operators/arithmetic.carbon: 1729 ms, 1728 ms in Run
- toolchain/lower/testdata/function/generic/call_recursive_sccs_deep.carbon: 1700 ms, 1697 ms in Run
[==========] 1335 tests from 1 test suite ran. (682 ms total)
```
After:
```
Ran 1335 tests in 2419 ms wall time, 109587 ms across threads
Slowest tests:
- toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon: 1748 ms, 1665 ms in Run
- toolchain/check/testdata/interop/cpp/function/operators.carbon: 1106 ms, 1057 ms in Run
- toolchain/lower/testdata/function/generic/call_recursive_diamond.carbon: 1044 ms, 1041 ms in Run
- toolchain/lower/testdata/function/generic/call_recursive_sccs_deep.carbon: 1015 ms, 1012 ms in Run
- toolchain/lower/testdata/operators/arithmetic.carbon: 998 ms, 997 ms in Run
[==========] 1335 tests from 1 test suite ran. (652 ms total)
```
That's still slower than it should be, but a large improvement
nonetheless.
Fixes#6029
This uses each vector's size as a barrier between lists, to eliminate
the possibility of incidental collisions between entries of different
lists. This is the same as is done inside `AddBlock`.
Attach the cleanup to the `Temporary` instruction instead of to the
`TemporaryStorage` instruction. We create `TemporaryStorage`
instructions speculatively when creating an initializing expression, and
may overwrite those instructions with other instructions if it turns out
that a temporary is not required. Instead, wait until we finalize the
temporary and create a `Temporary` instruction to register the cleanup.
* Treat `MaybeUnformed` and `partial` as qualifiers, like `const`.
* Allow pointer conversions to add qualifiers.
* Allow unsafe pointer conversions to remove qualifiers.
* Allow conversions on non-reference expressions to drop `const`.
* Allow unsafe conversions on any expression to drop `const`.
* Allow unsafe conversions on non-initializing expressions to drop
`partial`. For initializing expressions, we should initialize the
vptr when dropping `partial`; this is not yet supported so we reject.
* Allow conversions on reference expressions to add `MaybeUnformed`.
* Allow unsafe conversions on reference expressions to drop
`MaybeUnformed`. For non-reference expressions, additional work is
required, because the value / initializing representation may not
match between `T` and `MaybeUnformed(T)`, so those are rejected for
now.
When importing a class definition, don't ask for the class layout if the
definition is invalid. Avoids an assertion failure in Clang.
---------
Co-authored-by: Dana Jansens <danakj@orodu.net>
Added tests for different character types.
`char` is currently not in primitives prelude, so had to use full
prelude.
C++ Interop Demo:
```carbon
// main.carbon
library "Main";
import Cpp inline '''
auto output_char(char c) -> void {
printf("%c", c);
}
''';
fn Run() -> i32 {
let msg: array(Core.Char, 13) =
('H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n');
for (c: Core.Char in msg) {
Cpp.output_char(c);
}
return 0;
}
```
```shell
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link main.o --output=demo
$ ./demo
Hello world!
```
Part of https://github.com/carbon-language/carbon-lang/issues/5263.
We import C++ enum types as Carbon class types as adapters for the
corresponding builtin integer type, and we import enumerator constants
as integer constants of that class type.
No operators are supported on such values for now; eventually once we
start asking Clang to implement operators on C++-owned types, these
types should be handled in the same way. However, they can be converted
to the corresponding integer type with `as` via adapter conversion, and
integer builtin functions can operate on them.
Fix the algorithm for importing declarations in dependency order to
properly walk the dependency graph. Add the parent declaration of a
declaration to the dependency set so that we have a parent declaration
context to import a declaration into.
Fixes a crash when attempting to import a class whose parent is not
imported.
The main change here is that a bad type appearing somewhere within a
field or base class of a class shouldn't cause an import of that class
to fail. Instead, only that field or base class becomes inaccessible
from Carbon.
Also improve the way that type importing errors are diagnosed. While we
lose the precision of a diagnostic saying why a type is not supported,
we gain a useful source location for where the type was mentioned in C++
code.
---------
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
The self access is important; for the test `generic_class.carbon` being
added to `toolchain/check/testdata/class/destroy_calls.carbon`, it was
using `%T.as.Destroy` instead of `%D.as.Destroy`, indicating the default
blank impl was being used instead of the type-specific version. That
test is trying to focus on the issue, but the delta is visible in a
couple other files in this PR, for example
`toolchain/check/testdata/class/generic/init.carbon`.
I'm separately working on getting rid of the default impl, which is how
I noticed this.
I was thinking about this for destruction, which I may not be able to
use it for, but still think this may be a good change to keep features
consistent.
Although this focused on `Destroy` support, some choices here around
`implicit_type_impls` are because copy/move will likely follow a similar
approach. I'm trying not to predict too much about how we'll structure
those, but I'm putting `Destroy` impl logic in a file that could perhaps
be shared with those. They'd likely be interested in similar things,
e.g. traversing members of types (particularly class, struct literal,
tuple literal).
At present this sets the destroy function as `no_op` which is consistent
with current logic, but has a TODO to correctly define.
Constant importing for functions changes slightly due to some issues I
was having with `GetFunctionType`. zygoloid suggested this approach to
avoid `EvalInst` logic.
Adds a flag for controlling whether to generating these impls. While
this does generation for `class`, as noted above this'll also need to be
done for tuples and struct literals, which would leave the `none.carbon`
min_prelude unable to use any types. Note if destruction *would* occur,
it'll still look up `Core.Destroy` for that and fail, but that's already
true of any test using `none.carbon`. I'm trying to use the flag to see
if we can keep `none.carbon` working mostly-consistently.
I'd tried separating out the flag to #5852, but that got a lot of
pushback over whether the behavior was appropriate. I'm hoping that the
interactions here make it clearer why the particular approach -- the
goal is not to enable advanced testing, or create some new end-user
behavior that we really support, it's just to keep no-prelude tests
functional. The main question raised there was why not just keep
generating `impl T as Core.Destroy` if `fn destroy` is present -- but I
think here it should be apparent that would require additional
complexity, as the generation of `impl T as Core.Destroy` is not
currently conditioned based on the implementation of `fn destroy`. I'd
rather add complexity to this flag only if it's enabling interesting
test functionality.
---------
Co-authored-by: Geoff Romer <gromer@google.com>
Instead of taking the complete text of the Clang diagnostic and using it
as the message portion of a Carbon diagnostic, generate the individual
pieces separately and pass them into the Carbon diagnostic
infrastructure.
* Clang's context lines are generated by running a custom "diagnostic
renderer" and tracking which lines it wants to print as context for a
given source location. When mapping from a C++ source location back to a
Carbon location, the Carbon `Loc` structure is now fully populated,
including filling in the context line and the column number.
* Clang's snippet is generated by running a custom diagnostic renderer
that is a cut-down version of the full text diagnostic renderer that
only prints a snippet. This is then attached to the Carbon diagnostic
manually as an override for the snippet we'd usually create.
We no longer repeat the file location twice on each diagnostic, and no
longer produce a bogus "in import" line for all locations coming from
clang that point arbitrarily to the first C++ import in the Carbon file.
The `[diagnostic kind]` marker is now displayed at the end of the
diagnostic message, not on a line of its own after the snippet.