From dd47e41da6bdcf74fda5e66a4c2f7ce9508c1060 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 14 May 2026 13:22:32 -0700 Subject: [PATCH] Fix calls to functions with `const T&&` parameters. (#7208) This also fixes passing a value expression to a forwarding reference, since we currently deduce a `const T&&` parameter in that case. We were accidentally looking at the type of the thunk parameter (which is never an rvalue reference) rather than the type of the callee parameter. --- toolchain/check/cpp/thunk.cpp | 2 +- .../cpp/function/import/reference.carbon | 390 ++++++++++++++++++ 2 files changed, 391 insertions(+), 1 deletion(-) diff --git a/toolchain/check/cpp/thunk.cpp b/toolchain/check/cpp/thunk.cpp index 5e24b1ba16c3..1a1016a86188 100644 --- a/toolchain/check/cpp/thunk.cpp +++ b/toolchain/check/cpp/thunk.cpp @@ -497,7 +497,7 @@ static auto BuildThunkParamRef( // Cast to an xvalue when using pass-by-`var` or when initializing an rvalue // reference (which might be passed by value if it's const-qualified). if (passing_mode == SemIR::ClangDeclSignature::PassingMode::ByVar || - thunk_param->getType()->isRValueReferenceType()) { + (!type.isNull() && type->isRValueReferenceType())) { call_arg = clang::ImplicitCastExpr::Create( sema.getASTContext(), call_arg->getType(), clang::CK_NoOp, call_arg, nullptr, clang::ExprValueKind::VK_XValue, clang::FPOptionsOverride()); diff --git a/toolchain/check/testdata/interop/cpp/function/import/reference.carbon b/toolchain/check/testdata/interop/cpp/function/import/reference.carbon index 8aa82bf7b751..c9c911a059e3 100644 --- a/toolchain/check/testdata/interop/cpp/function/import/reference.carbon +++ b/toolchain/check/testdata/interop/cpp/function/import/reference.carbon @@ -232,6 +232,77 @@ fn F() { Cpp.TakesConstLValue(t); } +// ============================================================================ +// Const rvalue reference as a parameter type +// ============================================================================ + +// --- param_const_rvalue_ref.h + +struct S {}; +struct T {}; + +auto TakesConstRValue(const S&&) -> void; + +// --- param_value_arg_for_const_rvalue_ref.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "param_const_rvalue_ref.h"; + +fn F(v: Cpp.S, cv: const Cpp.S) { + //@dump-sem-ir-begin + Cpp.TakesConstRValue(v); + Cpp.TakesConstRValue(cv); + //@dump-sem-ir-end +} + +// --- param_init_arg_for_const_rvalue_ref.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "param_const_rvalue_ref.h"; + +fn Make() -> Cpp.S; + +fn F() { + Cpp.TakesConstRValue({}); + Cpp.TakesConstRValue({} as Cpp.S); + Cpp.TakesConstRValue(({} as Cpp.S) as const Cpp.S); + Cpp.TakesConstRValue(Make()); +} + +// --- fail_param_lvalue_ref_arg_const_rvalue_ref.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "param_const_rvalue_ref.h"; + +fn F() { + //@dump-sem-ir-begin + var s: Cpp.S; + // CHECK:STDERR: fail_param_lvalue_ref_arg_const_rvalue_ref.carbon:[[@LINE+8]]:25: error: no matching function for call to 'TakesConstRValue' [CppInteropParseError] + // CHECK:STDERR: 17 | Cpp.TakesConstRValue(s); + // CHECK:STDERR: | ^ + // CHECK:STDERR: fail_param_lvalue_ref_arg_const_rvalue_ref.carbon:[[@LINE-8]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./param_const_rvalue_ref.h:5:6: note: candidate function not viable: expects an rvalue for 1st argument [CppInteropParseNote] + // CHECK:STDERR: 5 | auto TakesConstRValue(const S&&) -> void; + // CHECK:STDERR: | ^ ~~~~~~~~~ + // CHECK:STDERR: + Cpp.TakesConstRValue(s); + + var t: Cpp.T; + // CHECK:STDERR: fail_param_lvalue_ref_arg_const_rvalue_ref.carbon:[[@LINE+8]]:25: error: no matching function for call to 'TakesConstRValue' [CppInteropParseError] + // CHECK:STDERR: 28 | Cpp.TakesConstRValue(t); + // CHECK:STDERR: | ^ + // CHECK:STDERR: fail_param_lvalue_ref_arg_const_rvalue_ref.carbon:[[@LINE-19]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./param_const_rvalue_ref.h:5:6: note: candidate function not viable: no known conversion from 'T' to 'const S' for 1st argument [CppInteropParseNote] + // CHECK:STDERR: 5 | auto TakesConstRValue(const S&&) -> void; + // CHECK:STDERR: | ^ ~~~~~~~~~ + // CHECK:STDERR: + Cpp.TakesConstRValue(t); + //@dump-sem-ir-end +} + // ============================================================================ // Lvalue reference as return type // ============================================================================ @@ -315,6 +386,61 @@ fn F() { let unused ref s: Cpp.S = Cpp.ReturnConstLValue(); } +// ============================================================================ +// Forwarding references +// ============================================================================ + +// --- forwarding_reference.carbon + +library "[[@TEST_NAME]]"; + +import Cpp; + +class X {} + +inline Cpp '''c++ +template void TakeAnything_ExpectLRef(T&&) { + static_assert(__is_same(T, Carbon::X&)); +} +template void TakeAnything_ExpectConstLRef(T&&) { + static_assert(__is_same(T, const Carbon::X&)); +} +template void TakeAnything_ExpectRRef(T&&) { + static_assert(__is_same(T, Carbon::X)); +} +template void TakeAnything_ExpectConstRRef(T&&) { + static_assert(__is_same(T, const Carbon::X)); +} +'''; + +fn Make() -> X; + +fn PassValue(x: X) { + //@dump-sem-ir-begin + // TODO: Is a `const X&&` the right choice here? + Cpp.TakeAnything_ExpectConstRRef(x); + //@dump-sem-ir-end +} + +fn PassRef(ref x: X) { + //@dump-sem-ir-begin + Cpp.TakeAnything_ExpectLRef(ref x); + //@dump-sem-ir-end +} + +fn PassConstRef(ref x: const X) { + //@dump-sem-ir-begin + // TODO: This crashes! + // Cpp.TakeAnything_ExpectConstLRef(ref x); + Cpp.TakeAnything_ExpectConstLRef(x); + //@dump-sem-ir-end +} + +fn PassInit() { + //@dump-sem-ir-begin + Cpp.TakeAnything_ExpectRRef(Make()); + //@dump-sem-ir-end +} // CHECK:STDOUT: --- call_param_lvalue_ref.carbon // CHECK:STDOUT: @@ -838,6 +964,156 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- param_value_arg_for_const_rvalue_ref.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %const: type = const_type %S [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %TakesConstRValue.cpp_overload_set.type: type = cpp_overload_set_type @TakesConstRValue.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakesConstRValue.cpp_overload_set.value: %TakesConstRValue.cpp_overload_set.type = cpp_overload_set_value @TakesConstRValue.cpp_overload_set [concrete] +// CHECK:STDOUT: %ptr.ff5: type = ptr_type %const [concrete] +// CHECK:STDOUT: %TakesConstRValue__carbon_thunk.type: type = fn_type @TakesConstRValue__carbon_thunk [concrete] +// CHECK:STDOUT: %TakesConstRValue__carbon_thunk: %TakesConstRValue__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .S = %S.decl +// CHECK:STDOUT: .TakesConstRValue = %TakesConstRValue.cpp_overload_set.value +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %TakesConstRValue.cpp_overload_set.value: %TakesConstRValue.cpp_overload_set.type = cpp_overload_set_value @TakesConstRValue.cpp_overload_set [concrete = constants.%TakesConstRValue.cpp_overload_set.value] +// CHECK:STDOUT: %TakesConstRValue__carbon_thunk.decl: %TakesConstRValue__carbon_thunk.type = fn_decl @TakesConstRValue__carbon_thunk [concrete = constants.%TakesConstRValue__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%v.param: %S, %cv.param: %const) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakesConstRValue.ref.loc8: %TakesConstRValue.cpp_overload_set.type = name_ref TakesConstRValue, imports.%TakesConstRValue.cpp_overload_set.value [concrete = constants.%TakesConstRValue.cpp_overload_set.value] +// CHECK:STDOUT: %v.ref: %S = name_ref v, %v +// CHECK:STDOUT: %.loc8_24: ref %S = value_as_ref %v.ref +// CHECK:STDOUT: %addr.loc8: %ptr.5c7 = addr_of %.loc8_24 +// CHECK:STDOUT: %.loc8_25.1: %ptr.ff5 = as_compatible %addr.loc8 +// CHECK:STDOUT: %.loc8_25.2: %ptr.ff5 = converted %addr.loc8, %.loc8_25.1 +// CHECK:STDOUT: %TakesConstRValue__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%TakesConstRValue__carbon_thunk.decl(%.loc8_25.2) +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakesConstRValue.ref.loc9: %TakesConstRValue.cpp_overload_set.type = name_ref TakesConstRValue, imports.%TakesConstRValue.cpp_overload_set.value [concrete = constants.%TakesConstRValue.cpp_overload_set.value] +// CHECK:STDOUT: %cv.ref: %const = name_ref cv, %cv +// CHECK:STDOUT: %.loc9_24.1: %S = as_compatible %cv.ref +// CHECK:STDOUT: %.loc9_24.2: %S = converted %cv.ref, %.loc9_24.1 +// CHECK:STDOUT: %.loc9_24.3: ref %S = value_as_ref %.loc9_24.2 +// CHECK:STDOUT: %addr.loc9: %ptr.5c7 = addr_of %.loc9_24.3 +// CHECK:STDOUT: %.loc9_26.1: %ptr.ff5 = as_compatible %addr.loc9 +// CHECK:STDOUT: %.loc9_26.2: %ptr.ff5 = converted %addr.loc9, %.loc9_26.1 +// CHECK:STDOUT: %TakesConstRValue__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%TakesConstRValue__carbon_thunk.decl(%.loc9_26.2) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_param_lvalue_ref_arg_const_rvalue_ref.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %pattern_type.7da: type = pattern_type %S [concrete] +// CHECK:STDOUT: %DefaultOrUnformed.type: type = facet_type <@DefaultOrUnformed> [concrete] +// CHECK:STDOUT: %Default.type: type = facet_type <@Default> [concrete] +// CHECK:STDOUT: %T.50c: %Default.type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %T.as_type.as.DefaultOrUnformed.impl.Op.type.2c3: type = fn_type @T.as_type.as.DefaultOrUnformed.impl.Op, @T.as_type.as.DefaultOrUnformed.impl(%T.50c) [symbolic] +// CHECK:STDOUT: %T.as_type.as.DefaultOrUnformed.impl.Op.85d: %T.as_type.as.DefaultOrUnformed.impl.Op.type.2c3 = struct_value () [symbolic] +// CHECK:STDOUT: %S.Op.type: type = fn_type @S.Op [concrete] +// CHECK:STDOUT: %S.Op: %S.Op.type = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.4cd: = custom_witness (%S.Op), @Default [concrete] +// CHECK:STDOUT: %Default.facet.889: %Default.type = facet_value %S, (%custom_witness.4cd) [concrete] +// CHECK:STDOUT: %DefaultOrUnformed.impl_witness.386: = impl_witness imports.%DefaultOrUnformed.impl_witness_table.fc3, @T.as_type.as.DefaultOrUnformed.impl(%Default.facet.889) [concrete] +// CHECK:STDOUT: %DefaultOrUnformed.facet.536: %DefaultOrUnformed.type = facet_value %S, (%DefaultOrUnformed.impl_witness.386) [concrete] +// CHECK:STDOUT: %TakesConstRValue.cpp_overload_set.type: type = cpp_overload_set_type @TakesConstRValue.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakesConstRValue.cpp_overload_set.value: %TakesConstRValue.cpp_overload_set.type = cpp_overload_set_value @TakesConstRValue.cpp_overload_set [concrete] +// CHECK:STDOUT: %T.e15: type = class_type @T [concrete] +// CHECK:STDOUT: %pattern_type.e6b: type = pattern_type %T.e15 [concrete] +// CHECK:STDOUT: %T.Op.type: type = fn_type @T.Op [concrete] +// CHECK:STDOUT: %T.Op: %T.Op.type = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.3b9: = custom_witness (%T.Op), @Default [concrete] +// CHECK:STDOUT: %Default.facet.2fe: %Default.type = facet_value %T.e15, (%custom_witness.3b9) [concrete] +// CHECK:STDOUT: %DefaultOrUnformed.impl_witness.23e: = impl_witness imports.%DefaultOrUnformed.impl_witness_table.fc3, @T.as_type.as.DefaultOrUnformed.impl(%Default.facet.2fe) [concrete] +// CHECK:STDOUT: %DefaultOrUnformed.facet.08c: %DefaultOrUnformed.type = facet_value %T.e15, (%DefaultOrUnformed.impl_witness.23e) [concrete] +// CHECK:STDOUT: %T.cpp_destructor.type: type = fn_type @T.cpp_destructor [concrete] +// CHECK:STDOUT: %T.cpp_destructor: %T.cpp_destructor.type = struct_value () [concrete] +// CHECK:STDOUT: %S.cpp_destructor.type: type = fn_type @S.cpp_destructor [concrete] +// CHECK:STDOUT: %S.cpp_destructor: %S.cpp_destructor.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .S = %S.decl +// CHECK:STDOUT: .TakesConstRValue = %TakesConstRValue.cpp_overload_set.value +// CHECK:STDOUT: .T = %T.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %Core.import_ref.653: @T.as_type.as.DefaultOrUnformed.impl.%T.as_type.as.DefaultOrUnformed.impl.Op.type (%T.as_type.as.DefaultOrUnformed.impl.Op.type.2c3) = import_ref Core//prelude/parts/default, loc{{\d+_\d+}}, loaded [symbolic = @T.as_type.as.DefaultOrUnformed.impl.%T.as_type.as.DefaultOrUnformed.impl.Op (constants.%T.as_type.as.DefaultOrUnformed.impl.Op.85d)] +// CHECK:STDOUT: %DefaultOrUnformed.impl_witness_table.fc3 = impl_witness_table (%Core.import_ref.653), @T.as_type.as.DefaultOrUnformed.impl [concrete] +// CHECK:STDOUT: %TakesConstRValue.cpp_overload_set.value: %TakesConstRValue.cpp_overload_set.type = cpp_overload_set_value @TakesConstRValue.cpp_overload_set [concrete = constants.%TakesConstRValue.cpp_overload_set.value] +// CHECK:STDOUT: %T.decl: type = class_decl @T [concrete = constants.%T.e15] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %s.patt: %pattern_type.7da = ref_binding_pattern s [concrete] +// CHECK:STDOUT: %s.var_patt: %pattern_type.7da = var_pattern %s.patt [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %s.var: ref %S = var %s.var_patt +// CHECK:STDOUT: %DefaultOrUnformed.facet.loc8: %DefaultOrUnformed.type = facet_value constants.%S, (constants.%DefaultOrUnformed.impl_witness.386) [concrete = constants.%DefaultOrUnformed.facet.536] +// CHECK:STDOUT: %.loc8_15.1: %DefaultOrUnformed.type = converted constants.%S, %DefaultOrUnformed.facet.loc8 [concrete = constants.%DefaultOrUnformed.facet.536] +// CHECK:STDOUT: %as_type.loc8: type = facet_access_type %.loc8_15.1 [concrete = constants.%S] +// CHECK:STDOUT: %.loc8_15.2: type = converted %.loc8_15.1, %as_type.loc8 [concrete = constants.%S] +// CHECK:STDOUT: +// CHECK:STDOUT: %.loc8_3: ref %S = splice_block %s.var {} +// CHECK:STDOUT: %T.as_type.as.DefaultOrUnformed.impl.Op.call.loc8: init %S to %.loc8_3 = call %T.as_type.as.DefaultOrUnformed.impl.Op.specific_fn.1() +// CHECK:STDOUT: assign %s.var, %T.as_type.as.DefaultOrUnformed.impl.Op.call.loc8 +// CHECK:STDOUT: %.loc8_13: type = splice_block %S.ref [concrete = constants.%S] { +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] +// CHECK:STDOUT: } +// CHECK:STDOUT: %s: ref %S = ref_binding s, %s.var +// CHECK:STDOUT: %Cpp.ref.loc17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakesConstRValue.ref.loc17: %TakesConstRValue.cpp_overload_set.type = name_ref TakesConstRValue, imports.%TakesConstRValue.cpp_overload_set.value [concrete = constants.%TakesConstRValue.cpp_overload_set.value] +// CHECK:STDOUT: %s.ref: ref %S = name_ref s, %s +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %t.patt: %pattern_type.e6b = ref_binding_pattern t [concrete] +// CHECK:STDOUT: %t.var_patt: %pattern_type.e6b = var_pattern %t.patt [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %t.var: ref %T.e15 = var %t.var_patt +// CHECK:STDOUT: %DefaultOrUnformed.facet.loc19: %DefaultOrUnformed.type = facet_value constants.%T.e15, (constants.%DefaultOrUnformed.impl_witness.23e) [concrete = constants.%DefaultOrUnformed.facet.08c] +// CHECK:STDOUT: %.loc19_15.1: %DefaultOrUnformed.type = converted constants.%T.e15, %DefaultOrUnformed.facet.loc19 [concrete = constants.%DefaultOrUnformed.facet.08c] +// CHECK:STDOUT: %as_type.loc19: type = facet_access_type %.loc19_15.1 [concrete = constants.%T.e15] +// CHECK:STDOUT: %.loc19_15.2: type = converted %.loc19_15.1, %as_type.loc19 [concrete = constants.%T.e15] +// CHECK:STDOUT: +// CHECK:STDOUT: %.loc19_3: ref %T.e15 = splice_block %t.var {} +// CHECK:STDOUT: %T.as_type.as.DefaultOrUnformed.impl.Op.call.loc19: init %T.e15 to %.loc19_3 = call %T.as_type.as.DefaultOrUnformed.impl.Op.specific_fn.2() +// CHECK:STDOUT: assign %t.var, %T.as_type.as.DefaultOrUnformed.impl.Op.call.loc19 +// CHECK:STDOUT: %.loc19_13: type = splice_block %T.ref [concrete = constants.%T.e15] { +// CHECK:STDOUT: %Cpp.ref.loc19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %T.ref: type = name_ref T, imports.%T.decl [concrete = constants.%T.e15] +// CHECK:STDOUT: } +// CHECK:STDOUT: %t: ref %T.e15 = ref_binding t, %t.var +// CHECK:STDOUT: %Cpp.ref.loc28: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakesConstRValue.ref.loc28: %TakesConstRValue.cpp_overload_set.type = name_ref TakesConstRValue, imports.%TakesConstRValue.cpp_overload_set.value [concrete = constants.%TakesConstRValue.cpp_overload_set.value] +// CHECK:STDOUT: %t.ref: ref %T.e15 = name_ref t, %t +// CHECK:STDOUT: %T.cpp_destructor.bound: = bound_method %t.var, constants.%T.cpp_destructor +// CHECK:STDOUT: %T.cpp_destructor.call: init %empty_tuple.type = call %T.cpp_destructor.bound(%t.var) +// CHECK:STDOUT: %S.cpp_destructor.bound: = bound_method %s.var, constants.%S.cpp_destructor +// CHECK:STDOUT: %S.cpp_destructor.call: init %empty_tuple.type = call %S.cpp_destructor.bound(%s.var) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- call_return_lvalue_ref.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -954,3 +1230,117 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- forwarding_reference.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %X: type = class_type @X [concrete] +// CHECK:STDOUT: %Make.type: type = fn_type @Make [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %Make: %Make.type = struct_value () [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef.cpp_overload_set.type: type = cpp_overload_set_type @TakeAnything_ExpectConstRRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef.cpp_overload_set.value: %TakeAnything_ExpectConstRRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectConstRRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %const: type = const_type %X [concrete] +// CHECK:STDOUT: %ptr.d4c: type = ptr_type %const [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef__carbon_thunk.type: type = fn_type @TakeAnything_ExpectConstRRef__carbon_thunk [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef__carbon_thunk: %TakeAnything_ExpectConstRRef__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.2a9: type = ptr_type %X [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectLRef.cpp_overload_set.type: type = cpp_overload_set_type @TakeAnything_ExpectLRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectLRef.cpp_overload_set.value: %TakeAnything_ExpectLRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectLRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectLRef.type: type = fn_type @TakeAnything_ExpectLRef [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectLRef: %TakeAnything_ExpectLRef.type = struct_value () [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef.cpp_overload_set.type: type = cpp_overload_set_type @TakeAnything_ExpectConstLRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef.cpp_overload_set.value: %TakeAnything_ExpectConstLRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectConstLRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef__carbon_thunk.type: type = fn_type @TakeAnything_ExpectConstLRef__carbon_thunk [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef__carbon_thunk: %TakeAnything_ExpectConstLRef__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectRRef.cpp_overload_set.type: type = cpp_overload_set_type @TakeAnything_ExpectRRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectRRef.cpp_overload_set.value: %TakeAnything_ExpectRRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectRRef.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectRRef__carbon_thunk.type: type = fn_type @TakeAnything_ExpectRRef__carbon_thunk [concrete] +// CHECK:STDOUT: %TakeAnything_ExpectRRef__carbon_thunk: %TakeAnything_ExpectRRef__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .TakeAnything_ExpectConstRRef = %TakeAnything_ExpectConstRRef.cpp_overload_set.value +// CHECK:STDOUT: .TakeAnything_ExpectLRef = %TakeAnything_ExpectLRef.cpp_overload_set.value +// CHECK:STDOUT: .TakeAnything_ExpectConstLRef = %TakeAnything_ExpectConstLRef.cpp_overload_set.value +// CHECK:STDOUT: .TakeAnything_ExpectRRef = %TakeAnything_ExpectRRef.cpp_overload_set.value +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef.cpp_overload_set.value: %TakeAnything_ExpectConstRRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectConstRRef.cpp_overload_set [concrete = constants.%TakeAnything_ExpectConstRRef.cpp_overload_set.value] +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef__carbon_thunk.decl: %TakeAnything_ExpectConstRRef__carbon_thunk.type = fn_decl @TakeAnything_ExpectConstRRef__carbon_thunk [concrete = constants.%TakeAnything_ExpectConstRRef__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %TakeAnything_ExpectLRef.cpp_overload_set.value: %TakeAnything_ExpectLRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectLRef.cpp_overload_set [concrete = constants.%TakeAnything_ExpectLRef.cpp_overload_set.value] +// CHECK:STDOUT: %TakeAnything_ExpectLRef.decl: %TakeAnything_ExpectLRef.type = fn_decl @TakeAnything_ExpectLRef [concrete = constants.%TakeAnything_ExpectLRef] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef.cpp_overload_set.value: %TakeAnything_ExpectConstLRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectConstLRef.cpp_overload_set [concrete = constants.%TakeAnything_ExpectConstLRef.cpp_overload_set.value] +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef__carbon_thunk.decl: %TakeAnything_ExpectConstLRef__carbon_thunk.type = fn_decl @TakeAnything_ExpectConstLRef__carbon_thunk [concrete = constants.%TakeAnything_ExpectConstLRef__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %TakeAnything_ExpectRRef.cpp_overload_set.value: %TakeAnything_ExpectRRef.cpp_overload_set.type = cpp_overload_set_value @TakeAnything_ExpectRRef.cpp_overload_set [concrete = constants.%TakeAnything_ExpectRRef.cpp_overload_set.value] +// CHECK:STDOUT: %TakeAnything_ExpectRRef__carbon_thunk.decl: %TakeAnything_ExpectRRef__carbon_thunk.type = fn_decl @TakeAnything_ExpectRRef__carbon_thunk [concrete = constants.%TakeAnything_ExpectRRef__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PassValue(%x.param: %X) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef.ref: %TakeAnything_ExpectConstRRef.cpp_overload_set.type = name_ref TakeAnything_ExpectConstRRef, imports.%TakeAnything_ExpectConstRRef.cpp_overload_set.value [concrete = constants.%TakeAnything_ExpectConstRRef.cpp_overload_set.value] +// CHECK:STDOUT: %x.ref: %X = name_ref x, %x +// CHECK:STDOUT: %.loc28_36: ref %X = value_as_ref %x.ref +// CHECK:STDOUT: %addr: %ptr.2a9 = addr_of %.loc28_36 +// CHECK:STDOUT: %.loc28_37.1: %ptr.d4c = as_compatible %addr +// CHECK:STDOUT: %.loc28_37.2: %ptr.d4c = converted %addr, %.loc28_37.1 +// CHECK:STDOUT: %TakeAnything_ExpectConstRRef__carbon_thunk.call: init %empty_tuple.type = call imports.%TakeAnything_ExpectConstRRef__carbon_thunk.decl(%.loc28_37.2) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PassRef(%x.param: ref %X) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakeAnything_ExpectLRef.ref: %TakeAnything_ExpectLRef.cpp_overload_set.type = name_ref TakeAnything_ExpectLRef, imports.%TakeAnything_ExpectLRef.cpp_overload_set.value [concrete = constants.%TakeAnything_ExpectLRef.cpp_overload_set.value] +// CHECK:STDOUT: %x.ref: ref %X = name_ref x, %x +// CHECK:STDOUT: %.loc34: %X = ref_tag %x.ref +// CHECK:STDOUT: %TakeAnything_ExpectLRef.call: init %empty_tuple.type = call imports.%TakeAnything_ExpectLRef.decl(%.loc34) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PassConstRef(%x.param: ref %const) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef.ref: %TakeAnything_ExpectConstLRef.cpp_overload_set.type = name_ref TakeAnything_ExpectConstLRef, imports.%TakeAnything_ExpectConstLRef.cpp_overload_set.value [concrete = constants.%TakeAnything_ExpectConstLRef.cpp_overload_set.value] +// CHECK:STDOUT: %x.ref: ref %const = name_ref x, %x +// CHECK:STDOUT: %.loc42_36.1: ref %X = as_compatible %x.ref +// CHECK:STDOUT: %.loc42_36.2: ref %X = converted %x.ref, %.loc42_36.1 +// CHECK:STDOUT: %.loc42_36.3: %X = acquire_value %.loc42_36.2 +// CHECK:STDOUT: %.loc42_36.4: ref %X = value_as_ref %.loc42_36.3 +// CHECK:STDOUT: %addr: %ptr.2a9 = addr_of %.loc42_36.4 +// CHECK:STDOUT: %.loc42_37.1: %ptr.d4c = as_compatible %addr +// CHECK:STDOUT: %.loc42_37.2: %ptr.d4c = converted %addr, %.loc42_37.1 +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef__carbon_thunk.call: init %empty_tuple.type = call imports.%TakeAnything_ExpectConstLRef__carbon_thunk.decl(%.loc42_37.2) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @PassInit() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakeAnything_ExpectRRef.ref: %TakeAnything_ExpectRRef.cpp_overload_set.type = name_ref TakeAnything_ExpectRRef, imports.%TakeAnything_ExpectRRef.cpp_overload_set.value [concrete = constants.%TakeAnything_ExpectRRef.cpp_overload_set.value] +// CHECK:STDOUT: %Make.ref: %Make.type = name_ref Make, file.%Make.decl [concrete = constants.%Make] +// CHECK:STDOUT: +// CHECK:STDOUT: %Make.call: init %X to %_.var = call %Make.ref() +// CHECK:STDOUT: +// CHECK:STDOUT: %addr: %ptr.2a9 = addr_of %_.var +// CHECK:STDOUT: %TakeAnything_ExpectRRef__carbon_thunk.call: init %empty_tuple.type = call imports.%TakeAnything_ExpectRRef__carbon_thunk.decl(%addr) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: