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.
This commit is contained in:
Boaz Brickner
2025-10-08 16:33:09 +00:00
committed by GitHub
parent ba8ed99eb0
commit bfc4d2b127
4 changed files with 268 additions and 111 deletions
+16 -6
View File
@@ -1446,16 +1446,26 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
// TODO: Support more return types.
static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id,
clang::FunctionDecl* clang_decl) -> TypeExpr {
clang::QualType ret_type = clang_decl->getReturnType();
if (!ret_type->isVoidType()) {
TypeExpr mapped_type = MapType(context, loc_id, ret_type);
if (!mapped_type.inst_id.has_value()) {
clang::QualType orig_ret_type = clang_decl->getReturnType();
if (!orig_ret_type->isVoidType()) {
// We map `T&` return type to `addr param: T*`, and `T&&` parameters to
// `param: T`.
// TODO: Revisit this and decide what we really want to do here.
clang::QualType ret_type = orig_ret_type.getNonReferenceType();
auto [orig_type_inst_id, type_id] = MapType(context, loc_id, ret_type);
if (!orig_type_inst_id.has_value()) {
context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
ret_type.getAsString()));
orig_ret_type.getAsString()));
return {.inst_id = SemIR::ErrorInst::TypeInstId,
.type_id = SemIR::ErrorInst::TypeId};
}
return mapped_type;
if (orig_ret_type->isLValueReferenceType()) {
type_id = GetPointerType(context, orig_type_inst_id);
}
return {orig_type_inst_id, type_id};
}
auto* ctor = dyn_cast<clang::CXXConstructorDecl>(clang_decl);