mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-27 22:02:33 +01:00
b44ba47cf375e6b2cf8aedef45dd3caabef2dd8c
11
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5e3bb523f8 |
Add builtin functions for destroy, with special requirements in facet types (#6035)
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>
|
||
|
|
12ddfb9c7c |
[Carbon/C++ interop] Add support for C++ overloaded functions (#5891)
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 |
||
|
|
1ec8ac7ef9 |
Add Copy interface and use it for making copies. (#6034)
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> |
||
|
|
e8cd229e74 |
When performing an impl lookup, only import impls for related interfaces. (#6040)
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 |
||
|
|
d6fbe3c663 |
C++ interop: Support importing operators defined in namespaces (#6024)
C++ Interop Demo:
```c++
// my_number.h
namespace MyNamespace {
class MyNumber {
public:
explicit MyNumber(int value) : value_(value) {}
auto value() const -> int { return value_; }
private:
int value_;
};
auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber;
} // namespace MyNamespace
```
```c++
// my_number.cpp
#include "my_number.h"
namespace MyNamespace {
auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() + rhs.value());
}
} // namespace MyNamespace
```
```carbon
// main.carbon
library "Main";
import Core library "io";
import Cpp library "my_number.h";
fn Run() -> i32 {
let n1: Cpp.MyNamespace.MyNumber = Cpp.MyNamespace.MyNumber.MyNumber(5);
Core.Print(n1.value());
let n2: Cpp.MyNamespace.MyNumber = Cpp.MyNamespace.MyNumber.MyNumber(7);
Core.Print(n2.value());
let n3: Cpp.MyNamespace.MyNumber = n1 + n2;
Core.Print(n3.value());
return 0;
}
```
Before this change:
```
$ bazel-bin/toolchain/carbon compile main.carbon
main.carbon:13:38: error: cannot access member of interface `Core.AddWith(Cpp.MyNamespace.MyNumber)` in type `Cpp.MyNamespace.MyNumber` that does not implement that interface
let n3: Cpp.MyNamespace.MyNumber = n1 + n2;
^~~~~~~
```
With this change:
```shell
$ clang -c my_number.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link my_number.o main.o --output=demo
$ ./demo
5
7
12
```
Part of https://github.com/carbon-language/carbon-lang/issues/5995.
|
||
|
|
0518fdebbc |
Fix potential fingerprint conflict in constraints (#6033)
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`. |
||
|
|
56adfa20ce |
C++ interop: Add a test for calling an operator on an inner class (#6030)
This currently works and I'd like to keep it that way when adding operators in namespace support. Part of #5995. |
||
|
|
471b394c6d |
C++ interop: Support unary operators (#6020)
Newly supported: `-`.
Partially supported due to lack of reference support: `++` (prefix),
`--` (prefix).
Not supported due to lack of Carbon support to call them correctly: `+`,
`++` (postfix), `--` (postfix), `~`, `!`, `&`, `*`, `->`.
Also (for consistency):
* Add the operator declarations to unsupported binary operators tests.
* Logical operators and the unary `operator&` (address of) are expected
to be called by explicitly calling `operatorX`.
C++ Interop Demo:
```c++
// my_number.h
class MyNumber {
public:
explicit MyNumber(int value) : value_(value) {}
auto value() const -> int { return value_; }
private:
int value_;
};
auto operator++(MyNumber operand) -> MyNumber;
auto operator--(MyNumber operand) -> MyNumber;
auto operator-(MyNumber operand) -> MyNumber;
```
```c++
// my_number.cpp
#include "my_number.h"
auto operator++(MyNumber operand) -> MyNumber {
return MyNumber(operand.value() + 1);
}
auto operator--(MyNumber operand) -> MyNumber {
return MyNumber(operand.value() - 1);
}
auto operator-(MyNumber operand) -> MyNumber {
return MyNumber(-operand.value());
}
```
```carbon
// main.carbon
library "Main";
import Core library "io";
import Cpp library "my_number.h";
fn Run() -> i32 {
var num: Cpp.MyNumber = Cpp.MyNumber.MyNumber(14);
Core.Print(num.value());
++num;
Core.Print(num.value());
--num;
Core.Print(num.value());
num = -num;
Core.Print(num.value());
return 0;
}
```
```shell
$ clang -c my_number.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link my_number.o main.o --output=demo
$ ./demo
14
14
14
-14
```
Part of https://github.com/carbon-language/carbon-lang/issues/5995.
|
||
|
|
ee42b2db93 |
C++ interop: Support more binary operators (#6017)
Already supported: `+`.
Newly supported: `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, `>>`, `==`,
`!=`, `<`, `>`, `<=`, `>=`.
Partially supported due to lack of reference support: `+=`, `-=`, `*=`,
`/=`, `%=`, `&=`, `|=`, `^=`.
Not supported due to lack of reference support: `<<=`, `>>=`.
Not supported (I think Carbon doesn't want overloading these): `&&`,
`||`.
C++ Interop Demo:
```c++
// my_number.h
class MyNumber {
public:
explicit MyNumber(int value) : value_(value) {}
auto value() const -> int { return value_; }
void set_value(int value) { value_ = value; }
private:
int value_;
};
// Arithmetic
auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator-(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator*(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator/(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator%(MyNumber lhs, MyNumber rhs) -> MyNumber;
// Bitwise
auto operator&(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator|(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator^(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator<<(MyNumber lhs, int shift) -> MyNumber;
auto operator>>(MyNumber lhs, int shift) -> MyNumber;
// Compound Arithmetic
auto operator+=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator-=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator*=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator/=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator%=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
// Compound Bitwise
auto operator&=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator|=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
auto operator^=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull;
// Relational
auto operator==(MyNumber lhs, MyNumber rhs) -> bool;
auto operator!=(MyNumber lhs, MyNumber rhs) -> bool;
auto operator<(MyNumber lhs, MyNumber rhs) -> bool;
auto operator>(MyNumber lhs, MyNumber rhs) -> bool;
auto operator<=(MyNumber lhs, MyNumber rhs) -> bool;
auto operator>=(MyNumber lhs, MyNumber rhs) -> bool;
```
```c++
// my_number.cpp
#include "my_number.h"
// Arithmetic
auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() + rhs.value());
}
auto operator-(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() - rhs.value());
}
auto operator*(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() * rhs.value());
}
auto operator/(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() / rhs.value());
}
auto operator%(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() % rhs.value());
}
// Bitwise
auto operator&(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() & rhs.value());
}
auto operator|(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() | rhs.value());
}
auto operator^(MyNumber lhs, MyNumber rhs) -> MyNumber {
return MyNumber(lhs.value() ^ rhs.value());
}
auto operator<<(MyNumber lhs, int shift) -> MyNumber {
return MyNumber(lhs.value() << shift);
}
auto operator>>(MyNumber lhs, int shift) -> MyNumber {
return MyNumber(lhs.value() >> shift);
}
// Compound Arithmetic
auto operator+=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs + rhs);
}
auto operator-=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs - rhs);
}
auto operator*=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs * rhs);
}
auto operator/=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs / rhs);
}
auto operator%=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs % rhs);
}
// Compound Bitwise
auto operator&=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs & rhs);
}
auto operator|=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs | rhs);
}
auto operator^=(MyNumber* _Nonnull lhs, MyNumber rhs) -> MyNumber* _Nonnull {
return &(*lhs = *lhs ^ rhs);
}
// Relational
auto operator==(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() == rhs.value();
}
auto operator!=(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() != rhs.value();
}
auto operator<(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() < rhs.value();
}
auto operator>(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() > rhs.value();
}
auto operator<=(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() <= rhs.value();
}
auto operator>=(MyNumber lhs, MyNumber rhs) -> bool {
return lhs.value() >= rhs.value();
}
```
```carbon
// main.carbon
library "Main";
import Core library "io";
import Cpp library "my_number.h";
fn PrintBool(b: bool) {
if (b) {
Core.Print(1);
} else {
Core.Print(0);
}
}
fn Run() -> i32 {
// Arithmetic
var num1: Cpp.MyNumber = Cpp.MyNumber.MyNumber(14);
var num2: Cpp.MyNumber = Cpp.MyNumber.MyNumber(5);
Core.Print(num1.value());
Core.Print(num2.value());
Core.Print((num1 + num2).value());
Core.Print((num1 - num2).value());
Core.Print((num1 * num2).value());
Core.Print((num1 / num2).value());
Core.Print((num1 % num2).value());
// Bitwise
var bits1: Cpp.MyNumber = Cpp.MyNumber.MyNumber(12);
var bits2: Cpp.MyNumber = Cpp.MyNumber.MyNumber(10);
Core.Print(bits1.value());
Core.Print(bits2.value());
Core.Print((bits1 & bits2).value());
Core.Print((bits1 | bits2).value());
Core.Print((bits1 ^ bits2).value());
Core.Print((bits1 << 2).value());
Core.Print((bits1 >> 1).value());
// Compound Arithmetic
var c: Cpp.MyNumber = Cpp.MyNumber.MyNumber(100);
Core.Print(c.value());
&c += Cpp.MyNumber.MyNumber(10);
Core.Print(c.value());
&c -= Cpp.MyNumber.MyNumber(20);
Core.Print(c.value());
&c *= Cpp.MyNumber.MyNumber(2);
Core.Print(c.value());
&c /= Cpp.MyNumber.MyNumber(6);
Core.Print(c.value());
&c %= Cpp.MyNumber.MyNumber(9);
Core.Print(c.value());
// Compound Bitwise
&c |= Cpp.MyNumber.MyNumber(12);
Core.Print(c.value());
&c &= Cpp.MyNumber.MyNumber(7);
Core.Print(c.value());
&c ^= Cpp.MyNumber.MyNumber(10);
Core.Print(c.value());
// Relational
var rel1: Cpp.MyNumber = Cpp.MyNumber.MyNumber(20);
var rel2: Cpp.MyNumber = Cpp.MyNumber.MyNumber(30);
var rel3: Cpp.MyNumber = Cpp.MyNumber.MyNumber(20);
Core.Print(rel1.value());
Core.Print(rel2.value());
Core.Print(rel3.value());
PrintBool(rel1 == rel3);
PrintBool(rel1 != rel2);
PrintBool(rel1 < rel2);
PrintBool(rel2 > rel1);
PrintBool(rel1 <= rel3);
PrintBool(rel1 >= rel2);
return 0;
}
```
```shell
$ clang -c my_number.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link my_number.o main.o --output=demo
$ ./demo
14
5
19
9
70
2
4
12
10
8
14
6
48
6
100
110
90
180
30
3
15
7
13
20
30
20
1
1
1
1
1
0
```
Part of https://github.com/carbon-language/carbon-lang/issues/5995.
|
||
|
|
db0a00d713 |
Fix double-destruction of temporaries. (#6010)
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. |
||
|
|
870c5380a0 |
C++ interop: Support importing binary operator+ (#5996)
Triggered by calling a binary operator with LHS being an imported C++
class type.
Not supported (yet):
* Multiple overloads.
* Other operators.
C++ Interop Demo:
```c++
// hello_world.h
class C {
public:
C(int x) : x_(x) {}
auto x() const -> int { return x_; }
private:
int x_ = 0;
};
auto operator+ (C c1, C c2) -> C;
```
```c++
// hello_world.cpp
#include "hello_world.h"
#include <cstdio>
auto operator+ (C c1, C c2) -> C {
printf("Adding %d with %d\n", c1.x(), c2.x());
return C(c1.x() + c2.x());
}
```
```carbon
// main.carbon
library "Main";
import Cpp library "hello_world.h";
fn Run() -> i32 {
let c1 : Cpp.C = Cpp.C.C(7);
let c2 : Cpp.C = Cpp.C.C(8);
let c3 : Cpp.C = c1 + c2;
let c4 : Cpp.C = c3 + c2;
return 0;
}
```
```shell
$ clang -c hello_world.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo
$ ./demo
Adding 7 with 8
Adding 15 with 8
```
Part of #5995.
|