Commit Graph
26 Commits
Author SHA1 Message Date
Richard Smith 71ba07239f Support pass-by-move when calling a C++ function taking by value. (#7135)
Previously, we picked a single Carbon parameter pattern for each C++
parameter pattern. This doesn't work well in cases where the Carbon
semantics and the C++ semantics are not perfectly aligned. In
particular, when a parameter is passed by value in C++, that might mean
either pass-by-move (which in Carbon would best be modeled by a `var`
pattern, as no other form of parameter would perform a move) or
pass-by-copy (which in Carbon would best be modeled by a value
parameter, as a `var` parameter would force an extra copy).

After this change, we compute a passing mode for each parameter based on
the implicit conversion sequence from the argument to the parameter as
determined by C++ overload resolution, and use that to determine the
Carbon pattern corresponding to each C++ parameter. This results in
potentially generating multiple different thunks for the same C++
function if it's called in different ways, but we already did that to
handle default arguments and list-initialization. The passing modes are
included in the thunk mangling.

Add a new value store for clang decl signatures, which capture the
information about parameter passing mode as well as the other existing
information about different ways that a C++ function might be imported
to Carbon.

Most of the rules for computing passing modes are the same as before:
const references use pass by value, non-const lvalue references use
pass-by-ref, non-const rvalue references use pass-by-var. But for C++
non-reference parameters, pick between pass-by-value and pass-by-var
based on whether the implicit conversion sequence was effectively
performing a copy. Prefer pass-by-value if either would work and they'd
do the same thing. We still use pass-by-value for const references, even
when the argument is an lvalue and we could pass a reference; we may
want to change this in future.

For virtual functions, we try to pick a worst-case passing mode, as we
can only pick a single signature for what goes in the vtable. Calls to
virtual functions will still use a thunk to C++, allowing variance in
the calling convention at call sites. We don't allow variance in the
overriders as we don't implement support for thunks for virtual
functions yet. We currently use pass-by-value for const reference
parameters here, but that should probably change at some point.

Assisted-by: Gemini via Antigravity
2026-05-13 01:44:07 +00:00
Geoff RomerandChandler Carruth 49c7288619 Restructure return declaration handling (#7076)
- A function with a return declaration always has exactly one
`ReturnSlotPattern`, representing the whole return declaration (whereas
previously that was omitted for value and reference returns).
- The `ReturnSlotPattern` always has a subpattern with the same form.
`OutParamPattern` already plays that role for initializing forms, and
`TuplePattern` will play that role for tuple forms. This change
introduces `ValueReturnPattern` and `RefReturnPattern` to represent
value and reference return forms.
- As before, the `ReturnSlotPattern` has a corresponding `ReturnSlot`
that represents the output that is initialized by a `return` statement.
Its structure parallels the structure of the `ReturnSlotPattern`, so we
need `ValueReturn` and `RefReturn` insts that correspond to
`ValueReturnPattern` and `RefReturnPattern`.

This is a step toward supporting generic return forms, where the
`ReturnSlotPattern`'s subpattern may be an action: this change ensures
that evaluating the action for a specific form produces the same SemIR
as if the form were concrete to begin with. More speculatively, this
should simplify the implementation of `return` statements with compound
return forms.

---------

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
2026-04-22 23:38:21 +00:00
Richard Smith be0c07dc7e Give Carbon -> C++ thunks internal linkage. (#7040)
Also declare them `inline` since we're putting the `always_inline`
attribute on them. Use the `internal_linkage` attribute rather than
`SC_Static` since it's a more precise mechanism and matches what we do
for static member functions in reverse interop (where `SC_Static` means
something else and would not give the function internal linkage).
2026-04-08 21:14:30 +00:00
Richard Smith e06eb8f532 Create a placement operator new directly. (#6941)
Instead of injecting code to declare an `operator new`, generate AST for
it directly. In order to use this, directly generate a `CXXNewExpr`
rather than asking Clang to build one.

This is less of a hack, and doesn't visibly leak an `operator new`
declaration that inline C++ code or template instantiations might see.
It also avoids generating a warning in C++26 and later that the
`constexpr` declaration of `operator new` is used but not defined.

Assisted-by: Gemini 3.1 Pro via Antigravity
2026-03-20 16:50:37 +00:00
Richard Smith 0a4fd2cb7e Fix thunk generation for &&-qualified methods. (#6881)
Use the object parameter type when creating a reference to the thunk
parameter so that we create an xvalue rather than an lvalue for the
`*this` expression in the thunk.
2026-03-11 20:34:18 +00:00
Jon Ross-Perkins 2c6d9c7f66 Rename type's GetInstId to GetTypeInstId, reflecting returned type (#6708)
Discussed briefly [on
Discord](https://discord.com/channels/655572317891461132/655578254970716160/1470442830118912265),
done to reduce confusion.

Assisted-by: Google Antigravity with Gemini 3 Flash
2026-02-09 22:00:21 +00:00
Geoff RomerandRichard Smith e5b05a1fac ExprCategory for guaranteed-in-place initializing expressions (#6623)
The primary change in this PR is to split the `Initializing` expression
category into separate `ReprInitializing` and `InPlaceInitializing`
categories, depending on whether initialization uses the types
initializing representation, or is guaranteed to be in place. It also
rationalizes and documents the SemIR-level semantics of those categories
(including where #5545's "ephemeral entire reference" category will
fit), and introduces two new inst kinds to close gaps exposed in the
process.

Some additional secondary changes:
- Consistently format the storage arguments of initializers with `to`,
regardless of whether initialization is in-place, and document the `to`
notation.
- Rename some inst kinds and functions, and restructure some of the
code, for clarity and consistency with the new documentation.
- Resolve a TODO to handle more category conversions in
`CategoryConverter`, in order to make it easier to reason about category
conversions.

See #6588 and the review history of this PR for background.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2026-02-04 02:27:12 +00:00
Richard Smith e69c3fd978 Support list initialization of C++ classes that is performed via a constructor call. (#6660)
The general strategy here is to import the constructor with a signature
that directly matches the argument. The intent is that the imported
function will eventually be usable directly as the `ImplicitAs.Convert`
function in a generated `impl`.

For initialization from a tuple, for example `(1, 2)`, we import the
selected constructor with a signature that takes a tuple pattern:

  `fn Class.Class((a: i32, b: i32)) -> Class;`

In order to support that, this PR also adds support in general for tuple
patterns in function signatures. It turns out the implementation was
already very close to allowing this.

Assisted-by: Gemini 3 Pro via Antigravity
2026-01-27 22:04:21 +00:00
Richard SmithandCarbon Infra Bot f5bb43bced Stop creating invalid clang identifier names. (#6578)
This doesn't appear to be causing any problems, but seems worth avoiding
anyway.

---------

Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
2026-01-11 21:06:22 +00:00
Richard Smith 6114df59ee Factor out a Check::CppContext holding C++-specific check state (#6482)
* Move `Sema` access from `CppFile` into `CppContext`.
* Move the mangle context from `SemIR::File` into `CppContext`.
* Move source location mapping state from `Context` into `CppContext`.

Also factor out the `GenerateAst` function that builds the `CppContext`
and `CppFile` into its own file.
2025-12-10 18:55:22 +00:00
Geoff Romer bf45b1cbf5 Refactor function return type representation (#6463)
This separates the return type from the return pattern, and replaces the
return pattern with a block of return patterns. This is a step toward
support for `ref` returns (where there's no corresponding return
pattern) and compund-form returns (where there may be multiple return
patterns).
2025-12-10 18:34:23 +00:00
Richard Smith c7cd24e1b2 Support for calling C++ destructors. (#6453)
Synthesize an impl of `Destroy` for C++ classes in response to impl
lookup.
2025-12-09 21:03:27 +00:00
Richard Smith 6011040481 Rework handling of C++ references. (#6268)
For now, map C++ reference types to const-qualified Carbon pointer types
rather than picking between a (non-const) pointer or a value type. This
fixes misbehavior in lowering for reference members in classes and
reference return types.

Update the special-case handling for references as function parameters
so that it continues to map const reference parameters to Carbon
pass-by-value, and unify the code paths for `self` parameters and other
parameters, which were mostly doing the same thing but had some subtle
differences.

Add references to the list of types that we can pass to and from C++
directly, without needing an additional layer of thunks.
2025-10-28 00:33:26 +00:00
Richard Smith a1a35c207e Unify "needs thunk" logic. (#6277)
Remove duplication between determining whether a parameter needs custom
thunk mapping and whether a function needs a thunk. Now a function needs
a thunk if any parameter or the return type does.

This fixes some inconsistencies; previously:
- We would not require a thunk when passing an `unsigned int`, but if we
  had a thunk we'd pass `unsigned int` indirectly.
- We would always require a thunk for an enum parameter, even though
  we'd actually pass it directly if its underlying type is a 32- or
  64-bit integer.
- We would require a thunk for a nullable pointer, even though
  we arrange for all pointer types to have the same ABI in Carbon and
  C++, including nullable pointers / Optional(T*).

This also causes us to use a thunk for rvalue reference return types,
which we used to miscompile.

Depends on #6276.
2025-10-27 22:49:29 +00:00
Richard SmithandDavid Blaikie f022e91e45 Create a Call instruction directly when building a thunk call. (#6276)
Don't go through the `PerformCall` machinery a second recursive time --
this is redundant, creates additional unnecessary temporaries, and is in
theory wrong because `PerformCall` takes a syntactic argument list (one
argument per callee parameter pattern), but we have a call argument list
(one argument per callee parameter).

---------

Co-authored-by: David Blaikie <dblaikie@gmail.com>
2025-10-27 21:22:24 +00:00
Richard Smith 8cf4c4d10d [C++ interop] Pass top-level declarations to the code generator. (#6237)
This allows us to lower indirectly-referenced C++ functions and
variables.
2025-10-17 17:10:14 +00:00
Boaz Brickner bfc4d2b127 C++ interop: Add return reference types support (#6178)
This is a follow up of #6082, which added support for reference types,
but not for return types.

C++ Interop Demo:

```carbon
// main.carbon

library "Main";

import Core library "io";

import Cpp inline '''
struct C {
  auto Inc() -> void { ++x; }
  int x = 0;
};
auto GetC() -> C& {
  static C c;
  return c;
}
''';

fn Run() -> i32 {
  Core.Print(Cpp.GetC()->x);
  Cpp.GetC()->Inc();
  Core.Print(Cpp.GetC()->x);
  Cpp.GetC()->Inc();
  Core.Print(Cpp.GetC()->x);
  return 0;
}
```

```shell
$ bazel build toolchain:carbon && bazel-bin/toolchain/carbon compile main.carbon && bazel-bin/toolchain/carbon link main.o --output=demo && ./demo
0
1
2
```

**Without this change**:
```shell
main.carbon:19:14: error: semantics TODO: `Unsupported: return type: C &`
  Core.Print(Cpp.GetC()->x);
             ^~~~~~~~~~
```

Part of #6148.
2025-10-08 16:33:09 +00:00
Boaz Brickner ce6bf91a83 Avoid extra work when thunk_required is already true in IsCppThunkRequired() (#6150)
Also set `thunk_required` in a more consistent way, to avoid bugs like
the one fixed in #6152.

Part #6148.
2025-10-02 19:11:31 +00:00
Boaz Brickner 57c0fde145 Fix C++ thunk triggering for functions with default args which return a simple type (#6152)
Before this change, we wrongly ignore the decision to generate a thunk
for a function with default args by overriding this decision with the
fact the return type by itself doesn't require a thunk.
This causes not generating a thunk which leads to crashing in lowering.
Add tests that show that now thunk is generated in `check` and it no
longer crashes in `lower`.

Follow up of #6108.
2025-10-02 15:16:28 +00:00
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
Jon Ross-Perkins 8004c2d5f6 CalleeFunction -> Callee name adjustments (#6117) 2025-09-23 17:51:31 +00:00
Jon Ross-Perkins 0f7df4ed7e Switch CalleeFunction to a variant (#6104)
Trying to make it easier to see what's intended to be present/correct on
`CalleeFunction` in its various modes.
2025-09-22 22:56:38 +00:00
Boaz Brickner a73e259620 Add Check::Context::clang_sema() method and use it (#6110)
This replaces `sem_ir().clang_ast_unit()->getSema()`.
2025-09-22 19:11:06 +00:00
Boaz Brickner 412d911578 Use context.x() instead of context.sema_ir().x() in check/cpp/ when possible (#6109)
Avoid using `const Context&`. We always work with a cmutable `Context&`
(https://github.com/carbon-language/carbon-lang/pull/6094#discussion_r2359199247).
2025-09-22 10:15:31 +00:00
Boaz Brickner 05c9fd768e Add Check::Context::clang_decls() methods (#6094)
Use them instead of explicitly going through `sem_ir()`.
2025-09-19 13:20:01 +00:00
Boaz Brickner f29515fe4e Move C++ interop related check code files to a cpp dir (#6065)
Context:
https://github.com/carbon-language/carbon-lang/pull/5891#pullrequestreview-3178216893
2025-09-17 09:31:36 +00:00