Import non-const rvalue references as var parameters. (#7125)

When importing a C++ function with an rvalue reference parameter, we
previously produced a Carbon value parameter. This would lead to the
toolchain believing it could pass the address of a non-expiring object
to the function, which would lead to a use-after-move.

Instead, we now map non-const rvalue reference parameters to Carbon
`var` parameters. This forces the object passed into C++ to be unique
and owned by the call. While that's not an exact match for C++ rvalue
reference parameters, given that it provides "always move" not
"conditionally move", it's the closest match we have at the moment.
This commit is contained in:
Richard Smith
2026-04-29 00:28:00 +00:00
committed by GitHub
parent ab0aff91b8
commit 0124aae041
23 changed files with 412 additions and 411 deletions
@@ -185,7 +185,6 @@ fn Call() {
// CHECK:STDOUT: %X.B.cpp_overload_set.type: type = cpp_overload_set_type @X.B.cpp_overload_set [concrete]
// CHECK:STDOUT: %X.B.cpp_overload_set.value: %X.B.cpp_overload_set.type = cpp_overload_set_value @X.B.cpp_overload_set [concrete]
// CHECK:STDOUT: %bound_method.a5d: <bound method> = bound_method %.3af, %X.B.cpp_overload_set.value [concrete]
// CHECK:STDOUT: %pattern_type.46b: type = pattern_type %X [concrete]
// CHECK:STDOUT: %X.B.type: type = fn_type @X.B [concrete]
// CHECK:STDOUT: %X.B: %X.B.type = struct_value () [concrete]
// CHECK:STDOUT: %X.C.cpp_overload_set.type: type = cpp_overload_set_type @X.C.cpp_overload_set [concrete]
@@ -226,12 +225,8 @@ fn Call() {
// CHECK:STDOUT: %X.decl: type = class_decl @X [concrete = constants.%X] {} {}
// CHECK:STDOUT: %X.B.cpp_overload_set.value: %X.B.cpp_overload_set.type = cpp_overload_set_value @X.B.cpp_overload_set [concrete = constants.%X.B.cpp_overload_set.value]
// CHECK:STDOUT: %X.B.decl: %X.B.type = fn_decl @X.B [concrete = constants.%X.B] {
// CHECK:STDOUT: %self.param_patt: %pattern_type.46b = ref_param_pattern [concrete]
// CHECK:STDOUT: %self.patt: %pattern_type.46b = at_binding_pattern self, %self.param_patt [concrete]
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: ref %X = ref_param call_param0
// CHECK:STDOUT: %self: ref %X = ref_binding self, %self.param
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %X.C.cpp_overload_set.value: %X.C.cpp_overload_set.type = cpp_overload_set_value @X.C.cpp_overload_set [concrete = constants.%X.C.cpp_overload_set.value]
@@ -247,11 +242,9 @@ fn Call() {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: %X.cpp_destructor.decl: %X.cpp_destructor.type = fn_decl @X.cpp_destructor [concrete = constants.%X.cpp_destructor] {
// CHECK:STDOUT: %self.param_patt: %pattern_type.46b = ref_param_pattern [concrete]
// CHECK:STDOUT: %self.patt: %pattern_type.46b = at_binding_pattern self, %self.param_patt [concrete]
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: ref %X = ref_param call_param0
// CHECK:STDOUT: %self: ref %X = ref_binding self, %self.param
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -865,7 +858,6 @@ fn Call() {
// CHECK:STDOUT: %X.D.cpp_overload_set.type: type = cpp_overload_set_type @X.D.cpp_overload_set [concrete]
// CHECK:STDOUT: %X.D.cpp_overload_set.value: %X.D.cpp_overload_set.type = cpp_overload_set_value @X.D.cpp_overload_set [concrete]
// CHECK:STDOUT: %bound_method.d5c: <bound method> = bound_method %.3af, %X.D.cpp_overload_set.value [concrete]
// CHECK:STDOUT: %pattern_type.46b: type = pattern_type %X [concrete]
// CHECK:STDOUT: %X.cpp_destructor.type: type = fn_type @X.cpp_destructor [concrete]
// CHECK:STDOUT: %X.cpp_destructor: %X.cpp_destructor.type = struct_value () [concrete]
// CHECK:STDOUT: }
@@ -884,11 +876,9 @@ fn Call() {
// CHECK:STDOUT: %X.C.cpp_overload_set.value: %X.C.cpp_overload_set.type = cpp_overload_set_value @X.C.cpp_overload_set [concrete = constants.%X.C.cpp_overload_set.value]
// CHECK:STDOUT: %X.D.cpp_overload_set.value: %X.D.cpp_overload_set.type = cpp_overload_set_value @X.D.cpp_overload_set [concrete = constants.%X.D.cpp_overload_set.value]
// CHECK:STDOUT: %X.cpp_destructor.decl: %X.cpp_destructor.type = fn_decl @X.cpp_destructor [concrete = constants.%X.cpp_destructor] {
// CHECK:STDOUT: %self.param_patt: %pattern_type.46b = ref_param_pattern [concrete]
// CHECK:STDOUT: %self.patt: %pattern_type.46b = at_binding_pattern self, %self.param_patt [concrete]
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: %self.param: ref %X = ref_param call_param0
// CHECK:STDOUT: %self: ref %X = ref_binding self, %self.param
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -532,7 +532,6 @@ fn F() {
// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete]
// CHECK:STDOUT: %TakesRValue__carbon_thunk.type: type = fn_type @TakesRValue__carbon_thunk [concrete]
// CHECK:STDOUT: %TakesRValue__carbon_thunk: %TakesRValue__carbon_thunk.type = struct_value () [concrete]
// CHECK:STDOUT: %.6ef: ref %S = temporary invalid, %S.val [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
@@ -557,13 +556,11 @@ fn F() {
// CHECK:STDOUT: %.loc8_20.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
// CHECK:STDOUT: %Cpp.ref.loc8_25: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S]
// CHECK:STDOUT: %.loc8_20.2: ref %S = temporary_storage
// CHECK:STDOUT: %.loc8_20.3: init %S to %.loc8_20.2 = class_init () [concrete = constants.%S.val]
// CHECK:STDOUT: %.loc8_22.1: init %S = converted %.loc8_20.1, %.loc8_20.3 [concrete = constants.%S.val]
// CHECK:STDOUT: %.loc8_22.2: ref %S = temporary %.loc8_20.2, %.loc8_22.1 [concrete = constants.%.6ef]
// CHECK:STDOUT: %.loc8_22.3: %S = acquire_value %.loc8_22.2 [concrete = constants.%S.val]
// CHECK:STDOUT: %.loc8_22.4: ref %S = value_as_ref %.loc8_22.3
// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %.loc8_22.4
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %.loc8_20.2: init %S to %_.var = class_init () [concrete = constants.%S.val]
// CHECK:STDOUT: %.loc8_22: init %S = converted %.loc8_20.1, %.loc8_20.2 [concrete = constants.%S.val]
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %_.var
// CHECK:STDOUT: %TakesRValue__carbon_thunk.call: init %empty_tuple.type = call imports.%TakesRValue__carbon_thunk.decl(%addr)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }