[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
This commit is contained in:
Ivana Ivanovska
2025-09-15 12:29:49 +00:00
committed by GitHub
parent 20ac6b9270
commit 12ddfb9c7c
61 changed files with 4633 additions and 2252 deletions
@@ -780,8 +780,8 @@ fn F() {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.217: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -801,11 +801,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -835,7 +831,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT: %Cpp.ref.loc8_18: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %C.ref.loc8_21: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_23: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_23: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_26.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc8_26.1: %ptr.d9e = addr_of %.loc8_26.1
// CHECK:STDOUT: %C__carbon_thunk.call: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_26.1)
@@ -909,8 +905,8 @@ fn F() {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.217: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -997,11 +993,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -1140,7 +1132,7 @@ fn F() {
// CHECK:STDOUT: %c1.var: ref %C = var %c1.var_patt
// CHECK:STDOUT: %Cpp.ref.loc8_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_3: ref %C = splice_block %c1.var {}
// CHECK:STDOUT: %addr.loc8_27: %ptr.d9e = addr_of %.loc8_3
// CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_27)
@@ -1158,7 +1150,7 @@ fn F() {
// CHECK:STDOUT: %c2.var: ref %C = var %c2.var_patt
// CHECK:STDOUT: %Cpp.ref.loc9_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %C.ref.loc9_22: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc9_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc9_3: ref %C = splice_block %c2.var {}
// CHECK:STDOUT: %addr.loc9_27: %ptr.d9e = addr_of %.loc9_3
// CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_27)
@@ -1748,8 +1740,8 @@ fn F() {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.217: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -1765,11 +1757,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -1789,7 +1777,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT: %Cpp.ref.loc8_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_27.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc8_27.1: %ptr.d9e = addr_of %.loc8_27.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_27.1)
@@ -1806,7 +1794,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT: %Cpp.ref.loc9_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %C.ref.loc9_22: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc9_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc9_27.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc9_27.1: %ptr.d9e = addr_of %.loc9_27.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_27.1)
@@ -1912,8 +1900,8 @@ fn F() {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.69f: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.169: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.169 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.838: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -1933,11 +1921,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.c52: %.169 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -1958,7 +1942,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc8_21: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %N.ref.loc8_24: <namespace> = name_ref N, imports.%N [concrete = imports.%N]
// CHECK:STDOUT: %C.ref.loc8_26: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_28: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc8_31.1: %ptr.838 = addr_of %.loc8_31.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_31.1)
@@ -1977,7 +1961,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc9_21: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %N.ref.loc9_24: <namespace> = name_ref N, imports.%N [concrete = imports.%N]
// CHECK:STDOUT: %C.ref.loc9_26: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc9_28: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc9_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc9_31.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc9_31.1: %ptr.838 = addr_of %.loc9_31.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_31.1)
@@ -2035,15 +2019,15 @@ fn F() {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C1: type = class_type @C1 [concrete]
// CHECK:STDOUT: %pattern_type.20f: type = pattern_type %C1 [concrete]
// CHECK:STDOUT: %C1.C1.type: type = fn_type @C1.C1 [concrete]
// CHECK:STDOUT: %C1.C1: %C1.C1.type = struct_value () [concrete]
// CHECK:STDOUT: %.eb7: type = cpp_overload_set_type @C1__carbon_thunk [concrete]
// CHECK:STDOUT: %empty_struct.56f: %.eb7 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.087: type = ptr_type %C1 [concrete]
// CHECK:STDOUT: %C1__carbon_thunk.type: type = fn_type @C1__carbon_thunk [concrete]
// CHECK:STDOUT: %C1__carbon_thunk: %C1__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %C2: type = class_type @C2 [concrete]
// CHECK:STDOUT: %pattern_type.846: type = pattern_type %C2 [concrete]
// CHECK:STDOUT: %C2.C2.type: type = fn_type @C2.C2 [concrete]
// CHECK:STDOUT: %C2.C2: %C2.C2.type = struct_value () [concrete]
// CHECK:STDOUT: %.74f: type = cpp_overload_set_type @C2.C2 [concrete]
// CHECK:STDOUT: %empty_struct.c81: %.74f = struct_value () [concrete]
// CHECK:STDOUT: %ptr.51f: type = ptr_type %C2 [concrete]
// CHECK:STDOUT: %C2__carbon_thunk.type: type = fn_type @C2__carbon_thunk [concrete]
// CHECK:STDOUT: %C2__carbon_thunk: %C2__carbon_thunk.type = struct_value () [concrete]
@@ -2068,11 +2052,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C1.decl: type = class_decl @C1 [concrete = constants.%C1] {} {}
// CHECK:STDOUT: %C1.C1.decl: %C1.C1.type = fn_decl @C1.C1 [concrete = constants.%C1.C1] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.91f: %.eb7 = cpp_overload_set_value @C1__carbon_thunk [concrete = constants.%empty_struct.56f]
// CHECK:STDOUT: %C1__carbon_thunk.decl: %C1__carbon_thunk.type = fn_decl @C1__carbon_thunk [concrete = constants.%C1__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -2083,11 +2063,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C2.decl: type = class_decl @C2 [concrete = constants.%C2] {} {}
// CHECK:STDOUT: %C2.C2.decl: %C2.C2.type = fn_decl @C2.C2 [concrete = constants.%C2.C2] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.ed5: %.74f = cpp_overload_set_value @C2.C2 [concrete = constants.%empty_struct.c81]
// CHECK:STDOUT: %C2__carbon_thunk.decl: %C2__carbon_thunk.type = fn_decl @C2__carbon_thunk [concrete = constants.%C2__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -2113,7 +2089,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc8_23: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %N1.ref.loc8_26: <namespace> = name_ref N1, imports.%N1 [concrete = imports.%N1]
// CHECK:STDOUT: %C1.ref.loc8_29: type = name_ref C1, imports.%C1.decl [concrete = constants.%C1]
// CHECK:STDOUT: %C1.ref.loc8_32: %C1.C1.type = name_ref C1, imports.%C1.C1.decl [concrete = constants.%C1.C1]
// CHECK:STDOUT: %C1.ref.loc8_32: %.eb7 = name_ref C1, imports.%.91f [concrete = constants.%empty_struct.56f]
// CHECK:STDOUT: %.loc8_36.1: ref %C1 = temporary_storage
// CHECK:STDOUT: %addr.loc8_36.1: %ptr.087 = addr_of %.loc8_36.1
// CHECK:STDOUT: %C1__carbon_thunk.call: init %empty_tuple.type = call imports.%C1__carbon_thunk.decl(%addr.loc8_36.1)
@@ -2132,7 +2108,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc9_23: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %N2.ref.loc9_26: <namespace> = name_ref N2, imports.%N2 [concrete = imports.%N2]
// CHECK:STDOUT: %C2.ref.loc9_29: type = name_ref C2, imports.%C2.decl [concrete = constants.%C2]
// CHECK:STDOUT: %C2.ref.loc9_32: %C2.C2.type = name_ref C2, imports.%C2.C2.decl [concrete = constants.%C2.C2]
// CHECK:STDOUT: %C2.ref.loc9_32: %.74f = name_ref C2, imports.%.ed5 [concrete = constants.%empty_struct.c81]
// CHECK:STDOUT: %.loc9_36.1: ref %C2 = temporary_storage
// CHECK:STDOUT: %addr.loc9_36.1: %ptr.51f = addr_of %.loc9_36.1
// CHECK:STDOUT: %C2__carbon_thunk.call: init %empty_tuple.type = call imports.%C2__carbon_thunk.decl(%addr.loc9_36.1)
@@ -2216,8 +2192,8 @@ fn F() {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.69f: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.169: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.169 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.838: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -2235,11 +2211,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.c52: %.169 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -2255,7 +2227,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc8_21: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %N.ref.loc8_24: <namespace> = name_ref N, imports.%N [concrete = imports.%N]
// CHECK:STDOUT: %C.ref.loc8_26: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_28: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc8_31.1: %ptr.838 = addr_of %.loc8_31.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_31.1)
@@ -2274,7 +2246,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc9_21: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %N.ref.loc9_24: <namespace> = name_ref N, imports.%N [concrete = imports.%N]
// CHECK:STDOUT: %C.ref.loc9_26: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc9_28: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc9_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc9_31.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc9_31.1: %ptr.838 = addr_of %.loc9_31.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_31.1)
@@ -2318,8 +2290,8 @@ fn F() {
// CHECK:STDOUT: %O: type = class_type @O [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.b28: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.d80: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.d80 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.de2: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -2336,11 +2308,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.7a9: %.d80 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -2361,7 +2329,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc8_21: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %O.ref.loc8_24: type = name_ref O, imports.%O.decl [concrete = constants.%O]
// CHECK:STDOUT: %C.ref.loc8_26: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_28: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_28: %.d80 = name_ref C, imports.%.7a9 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc8_31.1: %ptr.de2 = addr_of %.loc8_31.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_31.1)
@@ -2380,7 +2348,7 @@ fn F() {
// CHECK:STDOUT: %Cpp.ref.loc9_21: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %O.ref.loc9_24: type = name_ref O, imports.%O.decl [concrete = constants.%O]
// CHECK:STDOUT: %C.ref.loc9_26: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc9_28: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc9_28: %.d80 = name_ref C, imports.%.7a9 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc9_31.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc9_31.1: %ptr.de2 = addr_of %.loc9_31.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_31.1)
@@ -2439,8 +2407,8 @@ fn F() {
// CHECK:STDOUT: %O: type = class_type @O [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.84b: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.62f: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.62f = struct_value () [concrete]
// CHECK:STDOUT: %ptr.4b2: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -2461,11 +2429,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {}
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.f56: %.62f = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -2487,7 +2451,7 @@ fn F() {
// CHECK:STDOUT: %N.ref.loc8_26: <namespace> = name_ref N, imports.%N [concrete = imports.%N]
// CHECK:STDOUT: %O.ref.loc8_28: type = name_ref O, imports.%O.decl [concrete = constants.%O]
// CHECK:STDOUT: %C.ref.loc8_30: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_32: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_32: %.62f = name_ref C, imports.%.f56 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_35.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc8_35.1: %ptr.4b2 = addr_of %.loc8_35.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_35.1)
@@ -2508,7 +2472,7 @@ fn F() {
// CHECK:STDOUT: %N.ref.loc9_26: <namespace> = name_ref N, imports.%N [concrete = imports.%N]
// CHECK:STDOUT: %O.ref.loc9_28: type = name_ref O, imports.%O.decl [concrete = constants.%O]
// CHECK:STDOUT: %C.ref.loc9_30: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc9_32: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc9_32: %.62f = name_ref C, imports.%.f56 [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc9_35.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc9_35.1: %ptr.4b2 = addr_of %.loc9_35.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_35.1)
@@ -2568,8 +2532,8 @@ fn F() {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %C: type = class_type @C [concrete]
// CHECK:STDOUT: %pattern_type.217: type = pattern_type %C [concrete]
// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete]
// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete]
// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @C.C [concrete]
// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete]
// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete]
// CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete]
// CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete]
@@ -2583,11 +2547,7 @@ fn F() {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct]
// CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
@@ -2602,7 +2562,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT: %Cpp.ref.loc8_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc8_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc8_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc8_27.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc8_27.1: %ptr.d9e = addr_of %.loc8_27.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_27.1)
@@ -2619,7 +2579,7 @@ fn F() {
// CHECK:STDOUT: }
// CHECK:STDOUT: %Cpp.ref.loc9_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %C.ref.loc9_22: type = name_ref C, imports.%C.decl [concrete = constants.%C]
// CHECK:STDOUT: %C.ref.loc9_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C]
// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct]
// CHECK:STDOUT: %.loc9_27.1: ref %C = temporary_storage
// CHECK:STDOUT: %addr.loc9_27.1: %ptr.d9e = addr_of %.loc9_27.1
// CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_27.1)