Commit Graph
170 Commits
Author SHA1 Message Date
Richard SmithandJon Ross-Perkins 1e7b7e53ae C++ interop: support for default arguments. (#6108)
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>
2025-09-24 01:07:59 +00:00
Dana JansensandRichard Smith 82679e6689 Make BindSymbolicName the canonical form of a FacetValue wrapping the BindSymbolicName (#6107)
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>
2025-09-23 22:11:11 +00:00
Boaz Brickner 87efd4cb0b Change C++ interop operators tests to use references for parameters of operators that should mutate them (#6111)
Returning by reference is still not supported and marked with a TODO.

C++ Interop Demo (compare to #6020):

```c++
// my_number.h

class MyNumber {
 public:
  explicit MyNumber(int value) : value_(value) {}
  auto value() const -> int { return value_; }
  auto set_value(int value) -> void { value_ = value; }

 private:
  int value_;
};

auto operator++(MyNumber& operand) -> MyNumber;
auto operator--(MyNumber& operand) -> MyNumber;
```

```c++
// my_number.cpp

#include "my_number.h"

auto operator++(MyNumber& operand) -> MyNumber {
  operand.set_value(operand.value() + 1);
  return operand;
}

auto operator--(MyNumber& operand) -> MyNumber {
  operand.set_value(operand.value() - 1);
  return operand;
}
```

```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());
  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
15
14
```

Part of https://github.com/carbon-language/carbon-lang/issues/5995.
2025-09-22 18:26:20 +00:00
Jon Ross-Perkins 6070db0b8a Fix handling of large int types in interop (#6102)
This fixes a crash on `i8388608`.
2025-09-22 17:50:42 +00:00
Richard SmithandJon Ross-Perkins 925250f8f9 Improve diagnostics for overload resolution failure. (#6091)
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>
2025-09-19 20:22:47 +00:00
Boaz Brickner ef488f00fa Overload resolution for C++ operators (#6092)
Multiple overloads for the same operator are now resolved using overload
resolution.
This change doesn't try to solve all issues with operator lookup.

Moved the operator lookup logic from `import` to `operators` and changed
it to take the args into account.
Use `Sema::LookupOverloadedBinOp()` (with ADL) when looking up operator
functions to create an overload set.

Verified all demos in #6017, #6020 and #6024 still work.

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_;
};

class NotMyNumber {};

auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber;
auto operator+(NotMyNumber lhs, NotMyNumber rhs) -> NotMyNumber;
```

```c++
// my_number.cpp

#include "my_number.h"

auto operator+(MyNumber lhs, MyNumber rhs) -> MyNumber {
  return MyNumber(lhs.value() + rhs.value());
}

auto operator+(NotMyNumber lhs, NotMyNumber /*rhs*/) -> NotMyNumber {
  return lhs;
}
```

```carbon
// main.carbon

library "Main";

import Core library "io";
import Cpp library "my_number.h";

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());

  return 0;
}
```

**After 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
14
5
19
```

**Before this change**

```shell
$ bazel-bin/toolchain/carbon compile main.carbon
main.carbon:14:15: error: semantics TODO: `Unsupported: Lookup succeeded but couldn't find a single result; LookupResultKind: 3`
  Core.Print((num1 + num2).value());
              ^~~~~~~~~~~
main.carbon:14:15: note: in `Cpp` operator `AddWith` lookup
  Core.Print((num1 + num2).value());
              ^~~~~~~~~~~
```

Part of https://github.com/carbon-language/carbon-lang/issues/5995.
2025-09-19 16:42:46 +00:00
Jon Ross-Perkins 9704dc670e Change the Destroy blanket impls to be more specific (#6098)
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.
2025-09-18 22:10:50 +00:00
Boaz Brickner 868c4b768c C++ interop: Don't crash when looking up names inside an incomplete C++ class/struct/union (#6096)
Only do the lookup when the class is complete.

Before this change we crash in `Sema::LookupQualifiedName()` on
`Declaration context must already be complete!`.
2025-09-18 22:03:42 +00:00
Boaz Brickner 3f6b26c6f2 Fix the import C++ namespace indirectly test to make it expected to fail (#6076)
Imported namespace do not implicitly import its content, so lookup
inside them is expected to fail.
2025-09-18 07:21:00 +00:00
David BlaikieandDana Jansens bff0e5978b Rudimentary virtual function call interop support (#6050)
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>
2025-09-17 23:30:13 +00:00
Boaz Brickner cac3578b86 Avoid crashing when importing a C++ struct indirectly (#6086)
Return an error constant id instead and output a TODO.

Part of #6060.
2025-09-17 17:27:52 +00:00
Boaz Brickner 02ea39f2a4 Avoid crashing when importing a C++ function indirectly (#6085)
Return an error instruction instead and output a `TODO`.

Part of #6060.
2025-09-17 12:45:30 +00:00
Richard Smith 1e47f29963 Add reference support to C++ interop. (#6082)
For now this works as follows:

* `T&&` is mapped to a by-value `param: T` parameter.
* `T&` is mapped to an `addr param: T*` parameter.

In either case, we will generate a thunk, which will internally pass the
parameter as a pointer.
2025-09-17 02:03:22 +00:00
Richard Smith 65a7e50037 Instantiate C++ templates at end of file. (#6084)
Mark C++ functions as used when overload resolution selects them, and
trigger Clang's end-of-TU processing at the end of the Carbon
compilation to perform instantiation and other pending cleanup steps.
2025-09-17 01:06:47 +00:00
730935691a Support for mapping str to std::string_view in interop. (#6079)
We already did the opposite direction; this enables use of `str` in
overload resolution.

Fixes #6062

---------

Co-authored-by: Dana Jansens <danakj@orodu.net>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
2025-09-16 23:40:33 +00:00
Richard Smith 9d84391f11 Support for passing pointers to function templates. (#6080)
When a function template takes a parameter of deduced type, and we
deduce that type to a pointer type because we passed a Carbon pointer as
the argument, don't complain that the deduced type is not nullable. We
still know that it can't be null, because we deduced it from a
non-nullable type.
2025-09-16 23:39:07 +00:00
Richard Smith b054e3d2b0 Overload resolution support for more kinds of candidate. (#6071)
* 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.
2025-09-16 21:57:32 +00:00
Richard Smith bac828d244 Add support for char keyword per #5903. (#6078)
Make inst namer and stringify print `Core.Char` and `Core.String` as
`char` and `str` respectively. Plus a few cleanups.
2025-09-16 20:45:01 +00:00
Boaz Brickner c24975d3a5 Add a test for importing a C++ namespace indirectly (#6075)
Part of #6060.
2025-09-16 14:25:31 +00:00
Boaz Brickner 9b35640a31 C++ interop: Add Cpp.<builtin_type> (#6047)
Based on proposal #5448.

Defining all `Cpp.<builtin_type>` names.
Still unsupported types on LP64: `long long`, `unsigned long long` and
`long double`.
Still unsupported types on LLP64: `long`, `unsigned long` and `long
double`.

C++ Interop Demo (on LP64):

```c++
// half.h

auto Half(long x) -> float;
auto PrintLong(long x) -> void;
auto PrintFloat(float x) -> void;
```

```c++
// half.cpp

#include <cstdio>

auto Half(long x) -> float {
  return static_cast<float>(x) / 2;
}

auto PrintLong(long x) -> void {
  printf("%ld\n", x);
}

auto PrintFloat(float x) -> void {
  printf("%f\n", x);
}
```

```carbon
// main.carbon

library "Main";

import Cpp library "half.h";

fn Run() -> i32 {
  let x: Cpp.long = 5;
  Cpp.PrintLong(x);
  let y: Cpp.float = Cpp.Half(x);
  Cpp.PrintFloat(y);
  return 0;
}
```

```shell
$ clang -c half.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link half.o main.o --output=demo
$ ./demo
5
2.500000
```

Part of #5263.
2025-09-16 09:29:10 +00:00
Richard Smith b44ba47cf3 Don't treat dependent types as having a copy value representation. (#6055)
Add `Dependent` value and initializing representations for types whose
representations are unknown because they are dependent. When generating
SemIR in such cases, use a worst-case initializing representation that
both provides a destination address and also propagates a potential
result value.

Use this to fix incorrect lowering and lowering crashes for specific
functions involving generic types that don't use a copy value
representation.

In lowering, be careful to distinguish between whether the initializing
representation for the generic return type uses a return slot (which
affects whether the SemIR declaration and call have one) and whether the
initializing representation for the specific return type uses a return
slot (which affects whether the LLVM IR declaration and call have one).
2025-09-15 23:59:00 +00:00
Richard Smith ca40e9d693 Support making method calls to C++ overload sets. (#6069)
Fixes #6059
2025-09-15 23:41:15 +00:00
Jon Ross-PerkinsandDana Jansens 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>
2025-09-15 17:03:43 +00:00
Ivana Ivanovska 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
2025-09-15 12:29:49 +00:00
Elliott KaltandRichard Smith f4bd6e42f9 Replace impl fn with override fn (#6008)
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>
2025-09-12 23:27:02 +00:00
Boaz Brickner 508a88e2a9 C++ inteop: Set type source info for a generated C++ thunk function (#6049)
This prevents a null pointer access crash when generating a thunk with
an automatically deduced trivial return type.
In this case, Clang calls `Sema::DeduceFunctionTypeFromReturnExpr()`
which calls `Sema::getReturnTypeLoc()`, which requires this information.

Part of #5514.
2025-09-12 07:11:36 +00:00
Richard Smith d60900cbeb Remove special case for returning value expressions by copy (#6052)
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.
2025-09-12 00:13:33 +00:00
Richard SmithandGeoff Romer 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>
2025-09-10 23:55:55 +00:00
Richard Smith 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
2025-09-10 21:40:27 +00:00
Boaz Brickner 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.
2025-09-10 14:03:09 +00:00
Jon Ross-Perkins 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`.
2025-09-09 21:44:03 +00:00
Boaz Brickner 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.
2025-09-09 13:06:55 +00:00
Boaz Brickner 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.
2025-09-08 15:39:08 +00:00
Boaz Brickner b88b53e7e3 C++ interop: Add support for importing globals (#6005)
This supports importing globals in the global scope and within
namespaces, and support for class static data members.

C++ Interop Demo:

```c++
// my_global.h

extern int my_global;
void inc_my_global();
```

```c++
// my_global.cpp

#include "my_global.h"

int my_global = 5;

void inc_my_global() {
  ++my_global;
}
```

```carbon
// main.carbon

library "Main";

import Core library "io";
import Cpp library "my_global.h";

fn Run() -> i32 {
  Core.Print(Cpp.my_global);
  Cpp.inc_my_global();
  Core.Print(Cpp.my_global);
  return 0;
}
```

```shell
$ clang -c my_global.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link my_global.o main.o --output=demo
$ ./demo
5
6
```

Part of #6006.
2025-09-08 08:34:55 +00:00
Boaz Brickner 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.
2025-09-05 13:03:10 +00:00
Richard Smith 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.
2025-09-04 19:19:59 +00:00
Richard Smith cb5e2e1597 Improve support for qualification conversions. (#5999)
* 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.
2025-09-03 21:00:12 +00:00
Boaz Brickner 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.
2025-09-03 12:01:20 +00:00
Richard SmithandDana Jansens 4483d1e5a7 Recover better from invalid C++ classes. (#5992)
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>
2025-09-02 19:32:35 +00:00
Boaz Brickner b5d86fdb6f Properly dump SemIR for inline C++ imports (#6001)
Dumping SemIR crashed on inline C++ imports and this outputs `import Cpp
inline` instead.
Followup of #5904.
2025-08-29 21:36:10 +00:00
Boaz Brickner 8adb3570ac C++ Interop: Add support for char (#5988)
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.
2025-08-29 01:11:24 +00:00
Richard SmithandChandler Carruth bd90fe1d9b Interop: map C++ std::string_view into Carbon str when importing. (#5985)
We assume these types have the same representation. For now, that will
only be the case for libc++ on 64-bit targets, because libc++ puts the
size field first, and `Core.String` always uses a 64-bit size field even
on 32-bit targets.

---------

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
2025-08-27 01:02:39 +00:00
Richard Smith 82ba1a43a1 Support for importing C++ enum types. (#5978)
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.
2025-08-26 23:11:35 +00:00
Richard Smith 3533668186 Support for building thunks for C++ constructors. (#5977) 2025-08-26 21:49:11 +00:00
Richard Smith d37f1ae6b5 Add return value support to C++ thunks. (#5976)
Based on #5948. A couple of tricky parts:

* When generating the C++ side of the thunk, we are given a pointer to
the location to emplace the return value. The only mechanism C++
provides to perform this emplacement is using placement `operator new`,
which requires a library function in the `<new>` header. We handle this
by declaring that library function ourselves, and rely on Clang not
actually needing a definition for it (which the standard library owns).

* On the Carbon side of the thunk, we want to form an initializing
expression as the result of the call. We don't have a way of expressing
in SemIR that an initializing expression performs its initialization by
storing through a pointer, so this PR adds a new initializing
instruction, `InPlaceInit`, to model an initialization that's performed
opaquely in-place.
2025-08-26 02:23:38 +00:00
Richard Smith 8c9080801c Support for building thunks for C++ methods. (#5972)
Also tweak how we import C++ methods to properly handle C++23's explicit
object parameters.
2025-08-25 22:33:51 +00:00
Richard Smith ddafbc9331 Use direct passing for 32- and 64-bit unsigned integers. (#5980)
Previously we only avoided creating a thunk for signed integers. But the
same logic also applies to the unsigned 32-bit and 64-bit types.
2025-08-25 21:49:03 +00:00
Richard Smithandjosh11b 30b8a93fde Support conversion from T* to const T*. (#5971)
Also support conversion from Derived* to const Base*.

---------

Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
2025-08-20 23:27:03 +00:00
Richard Smith b72c11e94a Support importing nested types from C++. (#5955)
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.
2025-08-20 07:39:12 +00:00
Richard Smith b851e8c423 Add support for f16, f64, f128. (#5952)
Generalize the f64 support to support other sizes. Also provide interop
support for `float`, `_Float16`, and `__float128`.

Also lay some groundwork for non-standard floating-point types, though
we don't have any syntax to name them yet.
2025-08-14 01:14:40 +00:00