Files
carbon-lang/toolchain/check/testdata/interop/cpp/class/import/base.carbon
T
Geoff RomerandRichard Smith e023f75254 Implement thunking in terms of constant evaluation (#7332)
The bulk of this change is changing most pattern insts to be `Always`
rather than `AlwaysUnique` constants, so that they can be wrapped in
`SpecificConstant`s to perform substitution. That then lets thunking
rely much more on `SpecificConstant` wrappers instead of deep-copying
the inst tree with modified types.

This approach to thunking should scale better, particularly as things
like form generics make function signatures more complex, because we can
leverage the existing support for constant evaluation and substitution.
Unfortunately, applying this approach to binding patterns will require
more work; see the TODO near the top of `thunk.cpp` for details.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2026-06-13 00:22:00 +00:00

779 lines
40 KiB
Plaintext

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/import/base.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/import/base.carbon
// --- derived_to_base_conversion.h
class Base {};
class Derived : public Base {};
// --- use_derived_to_base_conversion.carbon
library "[[@TEST_NAME]]";
import Cpp library "derived_to_base_conversion.h";
//@dump-sem-ir-begin
fn ConvertPtr(d: Cpp.Derived*) -> Cpp.Base* {
return d;
}
//@dump-sem-ir-end
fn AcceptVal(b: Cpp.Base);
//@dump-sem-ir-begin
fn ConvertVal(d: Cpp.Derived) {
AcceptVal(d);
}
//@dump-sem-ir-end
// --- static_member.h
class Base {
public:
static auto base_fn() -> void;
};
class Derived : public Base {
public:
static auto derived_fn() -> void;
};
// --- use_static_member.carbon
library "[[@TEST_NAME]]";
import Cpp library "static_member.h";
fn MyF() {
//@dump-sem-ir-begin
Cpp.Base.base_fn();
Cpp.Derived.base_fn();
Cpp.Derived.derived_fn();
//@dump-sem-ir-end
}
// --- base_field.h
struct Base {
int a;
int b;
};
struct Derived : Base {
int b;
};
// --- use_base_field.carbon
library "[[@TEST_NAME]]";
import Cpp library "base_field.h";
fn AccessDirect(d: Cpp.Derived) -> i32 {
//@dump-sem-ir-begin
return d.a;
//@dump-sem-ir-end
}
fn AccessQualified(d: Cpp.Derived) -> i32 {
//@dump-sem-ir-begin
return d.(Cpp.Base.b);
//@dump-sem-ir-end
}
// --- base_method.h
struct Base {
void f() const;
void g() const;
};
struct Derived : Base {
void g() const;
};
// --- use_base_method.carbon
library "[[@TEST_NAME]]";
import Cpp library "base_method.h";
fn CallDirect(d: Cpp.Derived) {
//@dump-sem-ir-begin
d.f();
//@dump-sem-ir-end
}
fn CallQualified(d: Cpp.Derived) {
//@dump-sem-ir-begin
d.(Cpp.Base.g)();
//@dump-sem-ir-end
}
fn CallBaseQualifiedByDerived(d: Cpp.Derived, b: Cpp.Base) {
//@dump-sem-ir-begin
// `Cpp.Derived.f` names a member of `Cpp.Base`, so we allow that to be used
// when `self` is a `Cpp.Base` or anything that implicitly converts to
// `Cpp.Base`, such as `Cpp.Derived`.
d.(Cpp.Derived.f)();
b.(Cpp.Derived.f)();
//@dump-sem-ir-end
}
// --- multiple_inheritance.h
struct A { int a; };
struct B { int b; };
struct C : A, B {};
struct Empty1 {};
struct Empty2 {};
struct OneNonEmptyBase : Empty1, A, Empty2 {};
struct TwoNonEmptyBases : Empty1, A, B, Empty2 {};
struct Polymorphic1 {
virtual void f();
};
struct Polymorphic2 {
virtual void g();
};
struct OnePolymorphicBase : A, B, Polymorphic1, Empty1 {};
struct TwoPolymorphicBases : Polymorphic1, Polymorphic2 {};
// --- fail_todo_use_multiple_inheritance.carbon
library "[[@TEST_NAME]]";
import Cpp library "multiple_inheritance.h";
fn ConvertA(p: Cpp.C*) -> Cpp.A* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.C*` to `Cpp.A*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.C*` does not implement interface `Core.ImplicitAs(Cpp.A*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertB(p: Cpp.C*) -> Cpp.B* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.C*` to `Cpp.B*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.C*` does not implement interface `Core.ImplicitAs(Cpp.B*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertOneNonEmptyBaseToEmpty1(p: Cpp.OneNonEmptyBase*) -> Cpp.Empty1* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.OneNonEmptyBase*` to `Cpp.Empty1*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.OneNonEmptyBase*` does not implement interface `Core.ImplicitAs(Cpp.Empty1*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertOneNonEmptyBaseToEmpty2(p: Cpp.OneNonEmptyBase*) -> Cpp.Empty2* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.OneNonEmptyBase*` to `Cpp.Empty2*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.OneNonEmptyBase*` does not implement interface `Core.ImplicitAs(Cpp.Empty2*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertTwoNonEmptyBasesToA(p: Cpp.TwoNonEmptyBases*) -> Cpp.A* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.TwoNonEmptyBases*` to `Cpp.A*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.TwoNonEmptyBases*` does not implement interface `Core.ImplicitAs(Cpp.A*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertTwoNonEmptyBasesToB(p: Cpp.TwoNonEmptyBases*) -> Cpp.B* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.TwoNonEmptyBases*` to `Cpp.B*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.TwoNonEmptyBases*` does not implement interface `Core.ImplicitAs(Cpp.B*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertOnePolymorphicBaseToA(p: Cpp.OnePolymorphicBase*) -> Cpp.A* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.OnePolymorphicBase*` to `Cpp.A*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.OnePolymorphicBase*` does not implement interface `Core.ImplicitAs(Cpp.A*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertOnePolymorphicBaseToB(p: Cpp.OnePolymorphicBase*) -> Cpp.B* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.OnePolymorphicBase*` to `Cpp.B*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.OnePolymorphicBase*` does not implement interface `Core.ImplicitAs(Cpp.B*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertTwoPolymorphicBasesToPolymorphic1(p: Cpp.TwoPolymorphicBases*) -> Cpp.Polymorphic1* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.TwoPolymorphicBases*` to `Cpp.Polymorphic1*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.TwoPolymorphicBases*` does not implement interface `Core.ImplicitAs(Cpp.Polymorphic1*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertTwoPolymorphicBasesToPolymorphic2(p: Cpp.TwoPolymorphicBases*) -> Cpp.Polymorphic2* {
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.TwoPolymorphicBases*` to `Cpp.Polymorphic2*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_multiple_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.TwoPolymorphicBases*` does not implement interface `Core.ImplicitAs(Cpp.Polymorphic2*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
// --- multiple_inheritance_with_preferred_base.carbon
library "[[@TEST_NAME]]";
import Cpp library "multiple_inheritance.h";
// If there's only one non-empty base, that's our preferred base class. We can
// convert to that.
fn ConvertOneNonEmptyBaseToA(p: Cpp.OneNonEmptyBase*) -> Cpp.A* {
return p;
}
// If there's only one polymorphic base, that's our preferred base class. We can
// convert to that.
fn ConvertOnePolymorphicBaseToPolymorphic1(p: Cpp.OnePolymorphicBase*) -> Cpp.Polymorphic1* {
return p;
}
// --- virtual_inheritance.h
struct A { int a; };
struct B : virtual A {};
void UseB(B * _Nonnull p);
// --- use_virtual_inheritance_incomplete.carbon
library "[[@TEST_NAME]]";
import Cpp library "virtual_inheritance.h";
fn Convert(p: Cpp.B*) {
// OK, doesn't require `Cpp.B` to be a complete type.
Cpp.UseB(p);
}
// --- fail_todo_use_virtual_inheritance.carbon
library "[[@TEST_NAME]]";
import Cpp library "virtual_inheritance.h";
fn Convert(p: Cpp.B*) -> Cpp.A* {
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.B*` to `Cpp.A*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_virtual_inheritance.carbon:[[@LINE+4]]:3: note: type `Cpp.B*` does not implement interface `Core.ImplicitAs(Cpp.A*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
// --- diamond.h
struct A {
int a;
};
struct B : virtual A {
int b;
};
struct C : virtual A {
int c;
};
struct D : B, C {
int d;
};
// --- fail_todo_use_diamond.carbon
library "[[@TEST_NAME]]";
import Cpp library "diamond.h";
fn ConvertBA(p: Cpp.B*) -> Cpp.A* {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.B*` to `Cpp.A*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:3: note: type `Cpp.B*` does not implement interface `Core.ImplicitAs(Cpp.A*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertCA(p: Cpp.C*) -> Cpp.A* {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.C*` to `Cpp.A*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:3: note: type `Cpp.C*` does not implement interface `Core.ImplicitAs(Cpp.A*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertDB(p: Cpp.D*) -> Cpp.B* {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.D*` to `Cpp.B*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:3: note: type `Cpp.D*` does not implement interface `Core.ImplicitAs(Cpp.B*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn ConvertDC(p: Cpp.D*) -> Cpp.C* {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `Cpp.D*` to `Cpp.C*` [ConversionFailure]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:3: note: type `Cpp.D*` does not implement interface `Core.ImplicitAs(Cpp.C*)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return p;
// CHECK:STDERR: ^~~~~~~~~
// CHECK:STDERR:
return p;
}
fn AccessBA(d: Cpp.D) -> i32 {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:11: error: cannot convert expression of type `Cpp.D` to `Cpp.B` with `as` [ConversionFailure]
// CHECK:STDERR: return (d as Cpp.B).b;
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:11: note: type `Cpp.D` does not implement interface `Core.As(Cpp.B)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return (d as Cpp.B).b;
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
return (d as Cpp.B).b;
}
fn AccessCA(d: Cpp.D) -> i32 {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:11: error: cannot convert expression of type `Cpp.D` to `Cpp.C` with `as` [ConversionFailure]
// CHECK:STDERR: return (d as Cpp.C).b;
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:11: note: type `Cpp.D` does not implement interface `Core.As(Cpp.C)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return (d as Cpp.C).b;
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
return (d as Cpp.C).b;
}
fn AccessDB(d: Cpp.D) -> i32 {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:10: error: cannot implicitly convert expression of type `Cpp.D` to `Cpp.B` [ConversionFailure]
// CHECK:STDERR: return d.b;
// CHECK:STDERR: ^~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:10: note: type `Cpp.D` does not implement interface `Core.ImplicitAs(Cpp.B)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return d.b;
// CHECK:STDERR: ^~~
// CHECK:STDERR:
return d.b;
}
fn AccessDC(d: Cpp.D) -> i32 {
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+7]]:10: error: cannot implicitly convert expression of type `Cpp.D` to `Cpp.C` [ConversionFailure]
// CHECK:STDERR: return d.c;
// CHECK:STDERR: ^~~
// CHECK:STDERR: fail_todo_use_diamond.carbon:[[@LINE+4]]:10: note: type `Cpp.D` does not implement interface `Core.ImplicitAs(Cpp.C)` [MissingImplInMemberAccessInContext]
// CHECK:STDERR: return d.c;
// CHECK:STDERR: ^~~
// CHECK:STDERR:
return d.c;
}
// --- final.h
struct A final {};
// --- fail_derive_from_final.carbon
library "[[@TEST_NAME]]";
import Cpp library "final.h";
class B {
// CHECK:STDERR: fail_derive_from_final.carbon:[[@LINE+4]]:16: error: deriving from final type `A`; base type must be an `abstract` or `base` class [BaseIsFinal]
// CHECK:STDERR: extend base: Cpp.A;
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
extend base: Cpp.A;
}
// --- union.h
union U {};
// --- fail_derive_from_union.carbon
library "[[@TEST_NAME]]";
import Cpp library "union.h";
class V {
// CHECK:STDERR: fail_derive_from_union.carbon:[[@LINE+4]]:16: error: deriving from final type `U`; base type must be an `abstract` or `base` class [BaseIsFinal]
// CHECK:STDERR: extend base: Cpp.U;
// CHECK:STDERR: ^~~~~
// CHECK:STDERR:
extend base: Cpp.U;
}
// CHECK:STDOUT: --- use_derived_to_base_conversion.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
// CHECK:STDOUT: %ptr.976: type = ptr_type %Derived [concrete]
// CHECK:STDOUT: %pattern_type.d23: type = pattern_type %ptr.976 [concrete]
// CHECK:STDOUT: %d.param_patt.9b7: %pattern_type.d23 = value_param_pattern [concrete]
// CHECK:STDOUT: %d.patt.1fc: %pattern_type.d23 = at_binding_pattern d, %d.param_patt.9b7 [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %ptr.0e0: type = ptr_type %Base [concrete]
// CHECK:STDOUT: %.866: Core.Form = init_form %ptr.0e0 [concrete]
// CHECK:STDOUT: %pattern_type.cb0: type = pattern_type %ptr.0e0 [concrete]
// CHECK:STDOUT: %return.param_patt.b43: %pattern_type.cb0 = out_param_pattern [concrete]
// CHECK:STDOUT: %return.patt.363: %pattern_type.cb0 = return_slot_pattern %return.param_patt.b43, %ptr.0e0 [concrete]
// CHECK:STDOUT: %ConvertPtr.type: type = fn_type @ConvertPtr [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %ConvertPtr: %ConvertPtr.type = struct_value () [concrete]
// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete]
// CHECK:STDOUT: %T.67d: type = symbolic_binding T, 0 [symbolic]
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.type.ff5: type = fn_type @ptr.as.Copy.impl.Op, @ptr.as.Copy.impl(%T.67d) [symbolic]
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.ce9: %ptr.as.Copy.impl.Op.type.ff5 = struct_value () [symbolic]
// CHECK:STDOUT: %Copy.impl_witness.428: <witness> = impl_witness imports.%Copy.impl_witness_table.4f1, @ptr.as.Copy.impl(%Base) [concrete]
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.type.136: type = fn_type @ptr.as.Copy.impl.Op, @ptr.as.Copy.impl(%Base) [concrete]
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.377: %ptr.as.Copy.impl.Op.type.136 = struct_value () [concrete]
// CHECK:STDOUT: %Copy.facet: %Copy.type = facet_value %ptr.0e0, (%Copy.impl_witness.428) [concrete]
// CHECK:STDOUT: %Copy.WithSelf.Op.type.be3: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet) [concrete]
// CHECK:STDOUT: %.6e4: type = fn_type_with_self_type %Copy.WithSelf.Op.type.be3, %Copy.facet [concrete]
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.specific_fn: <specific function> = specific_function %ptr.as.Copy.impl.Op.377, @ptr.as.Copy.impl.Op(%Base) [concrete]
// CHECK:STDOUT: %AcceptVal.type: type = fn_type @AcceptVal [concrete]
// CHECK:STDOUT: %AcceptVal: %AcceptVal.type = struct_value () [concrete]
// CHECK:STDOUT: %pattern_type.2f5: type = pattern_type %Derived [concrete]
// CHECK:STDOUT: %d.param_patt.0f5: %pattern_type.2f5 = value_param_pattern [concrete]
// CHECK:STDOUT: %d.patt.e5a: %pattern_type.2f5 = at_binding_pattern d, %d.param_patt.0f5 [concrete]
// CHECK:STDOUT: %ConvertVal.type: type = fn_type @ConvertVal [concrete]
// CHECK:STDOUT: %ConvertVal: %ConvertVal.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .Derived = %Derived.decl
// CHECK:STDOUT: .Base = %Base.decl
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [concrete = constants.%Derived] {} {}
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [concrete = constants.%Base] {} {}
// CHECK:STDOUT: %Core.import_ref.e5f: @ptr.as.Copy.impl.%ptr.as.Copy.impl.Op.type (%ptr.as.Copy.impl.Op.type.ff5) = import_ref Core//prelude/parts/copy, loc{{\d+_\d+}}, loaded [symbolic = @ptr.as.Copy.impl.%ptr.as.Copy.impl.Op (constants.%ptr.as.Copy.impl.Op.ce9)]
// CHECK:STDOUT: %Copy.impl_witness_table.4f1 = impl_witness_table (%Core.import_ref.e5f), @ptr.as.Copy.impl [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: %ConvertPtr.decl: %ConvertPtr.type = fn_decl @ConvertPtr [concrete = constants.%ConvertPtr] {
// CHECK:STDOUT: %d.param_patt: %pattern_type.d23 = value_param_pattern [concrete = constants.%d.param_patt.9b7]
// CHECK:STDOUT: %d.patt: %pattern_type.d23 = at_binding_pattern d, %d.param_patt [concrete = constants.%d.patt.1fc]
// CHECK:STDOUT: %return.param_patt: %pattern_type.cb0 = out_param_pattern [concrete = constants.%return.param_patt.b43]
// CHECK:STDOUT: %return.patt: %pattern_type.cb0 = return_slot_pattern %return.param_patt, %ptr.loc7_43 [concrete = constants.%return.patt.363]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %Cpp.ref.loc7_35: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Base.ref: type = name_ref Base, imports.%Base.decl [concrete = constants.%Base]
// CHECK:STDOUT: %ptr.loc7_43: type = ptr_type %Base.ref [concrete = constants.%ptr.0e0]
// CHECK:STDOUT: %.loc7_43: Core.Form = init_form %ptr.loc7_43 [concrete = constants.%.866]
// CHECK:STDOUT: %d.param: %ptr.976 = value_param call_param0
// CHECK:STDOUT: %.loc7_29: type = splice_block %ptr.loc7_29 [concrete = constants.%ptr.976] {
// CHECK:STDOUT: %Cpp.ref.loc7_18: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Derived.ref: type = name_ref Derived, imports.%Derived.decl [concrete = constants.%Derived]
// CHECK:STDOUT: %ptr.loc7_29: type = ptr_type %Derived.ref [concrete = constants.%ptr.976]
// CHECK:STDOUT: }
// CHECK:STDOUT: %d: %ptr.976 = value_binding d, %d.param
// CHECK:STDOUT: %return.param: ref %ptr.0e0 = out_param call_param1
// CHECK:STDOUT: %return: ref %ptr.0e0 = return_slot %return.param
// CHECK:STDOUT: }
// CHECK:STDOUT: %ConvertVal.decl: %ConvertVal.type = fn_decl @ConvertVal [concrete = constants.%ConvertVal] {
// CHECK:STDOUT: %d.param_patt: %pattern_type.2f5 = value_param_pattern [concrete = constants.%d.param_patt.0f5]
// CHECK:STDOUT: %d.patt: %pattern_type.2f5 = at_binding_pattern d, %d.param_patt [concrete = constants.%d.patt.e5a]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %d.param: %Derived = value_param call_param0
// CHECK:STDOUT: %.loc15: type = splice_block %Derived.ref [concrete = constants.%Derived] {
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Derived.ref: type = name_ref Derived, imports.%Derived.decl [concrete = constants.%Derived]
// CHECK:STDOUT: }
// CHECK:STDOUT: %d: %Derived = value_binding d, %d.param
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @ConvertPtr(%d.param: %ptr.976) -> out %return.param: %ptr.0e0 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %ptr.976 = name_ref d, %d
// CHECK:STDOUT: %.loc8_11.1: ref %Derived = deref %d.ref
// CHECK:STDOUT: %.loc8_11.2: ref %Base = class_element_access %.loc8_11.1, element0
// CHECK:STDOUT: %addr: %ptr.0e0 = addr_of %.loc8_11.2
// CHECK:STDOUT: %.loc8_11.3: %ptr.0e0 = converted %d.ref, %addr
// CHECK:STDOUT: %impl.elem0: %.6e4 = impl_witness_access constants.%Copy.impl_witness.428, element0 [concrete = constants.%ptr.as.Copy.impl.Op.377]
// CHECK:STDOUT: %bound_method.loc8_11.1: <bound method> = bound_method %.loc8_11.3, %impl.elem0
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @ptr.as.Copy.impl.Op(constants.%Base) [concrete = constants.%ptr.as.Copy.impl.Op.specific_fn]
// CHECK:STDOUT: %bound_method.loc8_11.2: <bound method> = bound_method %.loc8_11.3, %specific_fn
// CHECK:STDOUT: %ptr.as.Copy.impl.Op.call: init %ptr.0e0 = call %bound_method.loc8_11.2(%.loc8_11.3)
// CHECK:STDOUT: return %ptr.as.Copy.impl.Op.call
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @ConvertVal(%d.param: %Derived) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %AcceptVal.ref: %AcceptVal.type = name_ref AcceptVal, file.%AcceptVal.decl [concrete = constants.%AcceptVal]
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %.loc16_13.1: ref %Base = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc16_13.2: ref %Base = converted %d.ref, %.loc16_13.1
// CHECK:STDOUT: %.loc16_13.3: %Base = acquire_value %.loc16_13.2
// CHECK:STDOUT: %AcceptVal.call: init %empty_tuple.type = call %AcceptVal.ref(%.loc16_13.3)
// CHECK:STDOUT: return
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_static_member.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %Base.base_fn.cpp_overload_set.type: type = cpp_overload_set_type @Base.base_fn.cpp_overload_set [concrete]
// CHECK:STDOUT: %Base.base_fn.cpp_overload_set.value: %Base.base_fn.cpp_overload_set.type = cpp_overload_set_value @Base.base_fn.cpp_overload_set [concrete]
// CHECK:STDOUT: %Base.base_fn.type: type = fn_type @Base.base_fn [concrete]
// CHECK:STDOUT: %Base.base_fn: %Base.base_fn.type = struct_value () [concrete]
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
// CHECK:STDOUT: %Derived.base_fn.cpp_overload_set.type: type = cpp_overload_set_type @Derived.base_fn.cpp_overload_set [concrete]
// CHECK:STDOUT: %Derived.base_fn.cpp_overload_set.value: %Derived.base_fn.cpp_overload_set.type = cpp_overload_set_value @Derived.base_fn.cpp_overload_set [concrete]
// CHECK:STDOUT: %Derived.derived_fn.cpp_overload_set.type: type = cpp_overload_set_type @Derived.derived_fn.cpp_overload_set [concrete]
// CHECK:STDOUT: %Derived.derived_fn.cpp_overload_set.value: %Derived.derived_fn.cpp_overload_set.type = cpp_overload_set_value @Derived.derived_fn.cpp_overload_set [concrete]
// CHECK:STDOUT: %Derived.derived_fn.type: type = fn_type @Derived.derived_fn [concrete]
// CHECK:STDOUT: %Derived.derived_fn: %Derived.derived_fn.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .Base = %Base.decl
// CHECK:STDOUT: .Derived = %Derived.decl
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [concrete = constants.%Base] {} {}
// CHECK:STDOUT: %Base.base_fn.cpp_overload_set.value: %Base.base_fn.cpp_overload_set.type = cpp_overload_set_value @Base.base_fn.cpp_overload_set [concrete = constants.%Base.base_fn.cpp_overload_set.value]
// CHECK:STDOUT: %Base.base_fn.decl: %Base.base_fn.type = fn_decl @Base.base_fn [concrete = constants.%Base.base_fn] {} {}
// CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [concrete = constants.%Derived] {} {}
// CHECK:STDOUT: %Derived.base_fn.cpp_overload_set.value: %Derived.base_fn.cpp_overload_set.type = cpp_overload_set_value @Derived.base_fn.cpp_overload_set [concrete = constants.%Derived.base_fn.cpp_overload_set.value]
// CHECK:STDOUT: %Derived.derived_fn.cpp_overload_set.value: %Derived.derived_fn.cpp_overload_set.type = cpp_overload_set_value @Derived.derived_fn.cpp_overload_set [concrete = constants.%Derived.derived_fn.cpp_overload_set.value]
// CHECK:STDOUT: %Derived.derived_fn.decl: %Derived.derived_fn.type = fn_decl @Derived.derived_fn [concrete = constants.%Derived.derived_fn] {} {}
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @MyF() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Cpp.ref.loc8: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Base.ref: type = name_ref Base, imports.%Base.decl [concrete = constants.%Base]
// CHECK:STDOUT: %base_fn.ref.loc8: %Base.base_fn.cpp_overload_set.type = name_ref base_fn, imports.%Base.base_fn.cpp_overload_set.value [concrete = constants.%Base.base_fn.cpp_overload_set.value]
// CHECK:STDOUT: %Base.base_fn.call.loc8: init %empty_tuple.type = call imports.%Base.base_fn.decl()
// CHECK:STDOUT: %Cpp.ref.loc9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Derived.ref.loc9: type = name_ref Derived, imports.%Derived.decl [concrete = constants.%Derived]
// CHECK:STDOUT: %base_fn.ref.loc9: %Derived.base_fn.cpp_overload_set.type = name_ref base_fn, imports.%Derived.base_fn.cpp_overload_set.value [concrete = constants.%Derived.base_fn.cpp_overload_set.value]
// CHECK:STDOUT: %Base.base_fn.call.loc9: init %empty_tuple.type = call imports.%Base.base_fn.decl()
// CHECK:STDOUT: %Cpp.ref.loc10: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Derived.ref.loc10: type = name_ref Derived, imports.%Derived.decl [concrete = constants.%Derived]
// CHECK:STDOUT: %derived_fn.ref: %Derived.derived_fn.cpp_overload_set.type = name_ref derived_fn, imports.%Derived.derived_fn.cpp_overload_set.value [concrete = constants.%Derived.derived_fn.cpp_overload_set.value]
// CHECK:STDOUT: %Derived.derived_fn.call: init %empty_tuple.type = call imports.%Derived.derived_fn.decl()
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_base_field.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
// CHECK:STDOUT: %N: Core.IntLiteral = symbolic_binding N, 0 [symbolic]
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %Base.elem: type = unbound_element_type %Base, %i32 [concrete]
// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete]
// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.ac8: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%N) [symbolic]
// CHECK:STDOUT: %Int.as.Copy.impl.Op.5e0: %Int.as.Copy.impl.Op.type.ac8 = struct_value () [symbolic]
// CHECK:STDOUT: %Copy.impl_witness.0e0: <witness> = impl_witness imports.%Copy.impl_witness_table.367, @Int.as.Copy.impl(%int_32) [concrete]
// CHECK:STDOUT: %Int.as.Copy.impl.Op.type.3f6: type = fn_type @Int.as.Copy.impl.Op, @Int.as.Copy.impl(%int_32) [concrete]
// CHECK:STDOUT: %Int.as.Copy.impl.Op.4f6: %Int.as.Copy.impl.Op.type.3f6 = struct_value () [concrete]
// CHECK:STDOUT: %Copy.facet: %Copy.type = facet_value %i32, (%Copy.impl_witness.0e0) [concrete]
// CHECK:STDOUT: %Copy.WithSelf.Op.type.d09: type = fn_type @Copy.WithSelf.Op, @Copy.WithSelf(%Copy.facet) [concrete]
// CHECK:STDOUT: %.7a6: type = fn_type_with_self_type %Copy.WithSelf.Op.type.d09, %Copy.facet [concrete]
// CHECK:STDOUT: %Int.as.Copy.impl.Op.specific_fn: <specific function> = specific_function %Int.as.Copy.impl.Op.4f6, @Int.as.Copy.impl.Op(%int_32) [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .Derived = %Derived.decl
// CHECK:STDOUT: .Base = %Base.decl
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [concrete = constants.%Derived] {} {}
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [concrete = constants.%Base] {} {}
// CHECK:STDOUT: %Core.import_ref.cd6: @Int.as.Copy.impl.%Int.as.Copy.impl.Op.type (%Int.as.Copy.impl.Op.type.ac8) = import_ref Core//prelude/parts/int, loc{{\d+_\d+}}, loaded [symbolic = @Int.as.Copy.impl.%Int.as.Copy.impl.Op (constants.%Int.as.Copy.impl.Op.5e0)]
// CHECK:STDOUT: %Copy.impl_witness_table.367 = impl_witness_table (%Core.import_ref.cd6), @Int.as.Copy.impl [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AccessDirect(%d.param: %Derived) -> out %return.param: %i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %a.ref: %Base.elem = name_ref a, @Base.%.1 [concrete = @Base.%.1]
// CHECK:STDOUT: %.loc8_11.1: ref %Base = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc8_11.2: ref %Base = converted %d.ref, %.loc8_11.1
// CHECK:STDOUT: %.loc8_11.3: ref %i32 = class_element_access %.loc8_11.2, element0
// CHECK:STDOUT: %.loc8_11.4: %i32 = acquire_value %.loc8_11.3
// CHECK:STDOUT: %impl.elem0: %.7a6 = impl_witness_access constants.%Copy.impl_witness.0e0, element0 [concrete = constants.%Int.as.Copy.impl.Op.4f6]
// CHECK:STDOUT: %bound_method.loc8_11.1: <bound method> = bound_method %.loc8_11.4, %impl.elem0
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
// CHECK:STDOUT: %bound_method.loc8_11.2: <bound method> = bound_method %.loc8_11.4, %specific_fn
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc8_11.2(%.loc8_11.4)
// CHECK:STDOUT: return %Int.as.Copy.impl.Op.call
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @AccessQualified(%d.param: %Derived) -> out %return.param: %i32 {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %Cpp.ref.loc14: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Base.ref: type = name_ref Base, imports.%Base.decl [concrete = constants.%Base]
// CHECK:STDOUT: %b.ref: %Base.elem = name_ref b, @Base.%.2 [concrete = @Base.%.2]
// CHECK:STDOUT: %.loc14_11.1: ref %Base = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc14_11.2: ref %Base = converted %d.ref, %.loc14_11.1
// CHECK:STDOUT: %.loc14_11.3: ref %i32 = class_element_access %.loc14_11.2, element1
// CHECK:STDOUT: %.loc14_11.4: %i32 = acquire_value %.loc14_11.3
// CHECK:STDOUT: %impl.elem0: %.7a6 = impl_witness_access constants.%Copy.impl_witness.0e0, element0 [concrete = constants.%Int.as.Copy.impl.Op.4f6]
// CHECK:STDOUT: %bound_method.loc14_11.1: <bound method> = bound_method %.loc14_11.4, %impl.elem0
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
// CHECK:STDOUT: %bound_method.loc14_11.2: <bound method> = bound_method %.loc14_11.4, %specific_fn
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call: init %i32 = call %bound_method.loc14_11.2(%.loc14_11.4)
// CHECK:STDOUT: return %Int.as.Copy.impl.Op.call
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: --- use_base_method.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: constants {
// CHECK:STDOUT: %Derived: type = class_type @Derived [concrete]
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
// CHECK:STDOUT: %Base: type = class_type @Base [concrete]
// CHECK:STDOUT: %Derived.f.cpp_overload_set.type: type = cpp_overload_set_type @Derived.f.cpp_overload_set [concrete]
// CHECK:STDOUT: %Derived.f.cpp_overload_set.value: %Derived.f.cpp_overload_set.type = cpp_overload_set_value @Derived.f.cpp_overload_set [concrete]
// CHECK:STDOUT: %f__carbon_thunk.type: type = fn_type @f__carbon_thunk [concrete]
// CHECK:STDOUT: %f__carbon_thunk: %f__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %Base.g.cpp_overload_set.type: type = cpp_overload_set_type @Base.g.cpp_overload_set [concrete]
// CHECK:STDOUT: %Base.g.cpp_overload_set.value: %Base.g.cpp_overload_set.type = cpp_overload_set_value @Base.g.cpp_overload_set [concrete]
// CHECK:STDOUT: %g__carbon_thunk.type: type = fn_type @g__carbon_thunk [concrete]
// CHECK:STDOUT: %g__carbon_thunk: %g__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .Derived = %Derived.decl
// CHECK:STDOUT: .Base = %Base.decl
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %Derived.decl: type = class_decl @Derived [concrete = constants.%Derived] {} {}
// CHECK:STDOUT: %Base.decl: type = class_decl @Base [concrete = constants.%Base] {} {}
// CHECK:STDOUT: %Derived.f.cpp_overload_set.value: %Derived.f.cpp_overload_set.type = cpp_overload_set_value @Derived.f.cpp_overload_set [concrete = constants.%Derived.f.cpp_overload_set.value]
// CHECK:STDOUT: %f__carbon_thunk.decl: %f__carbon_thunk.type = fn_decl @f__carbon_thunk [concrete = constants.%f__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %Base.g.cpp_overload_set.value: %Base.g.cpp_overload_set.type = cpp_overload_set_value @Base.g.cpp_overload_set [concrete = constants.%Base.g.cpp_overload_set.value]
// CHECK:STDOUT: %g__carbon_thunk.decl: %g__carbon_thunk.type = fn_decl @g__carbon_thunk [concrete = constants.%g__carbon_thunk] {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @CallDirect(%d.param: %Derived) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %f.ref: %Derived.f.cpp_overload_set.type = name_ref f, imports.%Derived.f.cpp_overload_set.value [concrete = constants.%Derived.f.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %d.ref, %f.ref
// CHECK:STDOUT: %.loc8_3.1: ref %Base = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc8_3.2: ref %Base = converted %d.ref, %.loc8_3.1
// CHECK:STDOUT: %.loc8_3.3: %Base = acquire_value %.loc8_3.2
// CHECK:STDOUT: %f__carbon_thunk.call: init %empty_tuple.type = call imports.%f__carbon_thunk.decl(%.loc8_3.3)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @CallQualified(%d.param: %Derived) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %Cpp.ref.loc14: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Base.ref: type = name_ref Base, imports.%Base.decl [concrete = constants.%Base]
// CHECK:STDOUT: %g.ref: %Base.g.cpp_overload_set.type = name_ref g, imports.%Base.g.cpp_overload_set.value [concrete = constants.%Base.g.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %d.ref, %g.ref
// CHECK:STDOUT: %.loc14_3.1: ref %Base = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc14_3.2: ref %Base = converted %d.ref, %.loc14_3.1
// CHECK:STDOUT: %.loc14_3.3: %Base = acquire_value %.loc14_3.2
// CHECK:STDOUT: %g__carbon_thunk.call: init %empty_tuple.type = call imports.%g__carbon_thunk.decl(%.loc14_3.3)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @CallBaseQualifiedByDerived(%d.param: %Derived, %b.param: %Base) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %d.ref: %Derived = name_ref d, %d
// CHECK:STDOUT: %Cpp.ref.loc23: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Derived.ref.loc23: type = name_ref Derived, imports.%Derived.decl [concrete = constants.%Derived]
// CHECK:STDOUT: %f.ref.loc23: %Derived.f.cpp_overload_set.type = name_ref f, imports.%Derived.f.cpp_overload_set.value [concrete = constants.%Derived.f.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc23: <bound method> = bound_method %d.ref, %f.ref.loc23
// CHECK:STDOUT: %.loc23_3.1: ref %Base = class_element_access %d.ref, element0
// CHECK:STDOUT: %.loc23_3.2: ref %Base = converted %d.ref, %.loc23_3.1
// CHECK:STDOUT: %.loc23_3.3: %Base = acquire_value %.loc23_3.2
// CHECK:STDOUT: %f__carbon_thunk.call.loc23: init %empty_tuple.type = call imports.%f__carbon_thunk.decl(%.loc23_3.3)
// CHECK:STDOUT: %b.ref: %Base = name_ref b, %b
// CHECK:STDOUT: %Cpp.ref.loc24: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Derived.ref.loc24: type = name_ref Derived, imports.%Derived.decl [concrete = constants.%Derived]
// CHECK:STDOUT: %f.ref.loc24: %Derived.f.cpp_overload_set.type = name_ref f, imports.%Derived.f.cpp_overload_set.value [concrete = constants.%Derived.f.cpp_overload_set.value]
// CHECK:STDOUT: %bound_method.loc24: <bound method> = bound_method %b.ref, %f.ref.loc24
// CHECK:STDOUT: %f__carbon_thunk.call.loc24: init %empty_tuple.type = call imports.%f__carbon_thunk.decl(%b.ref)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: