Просмотр исходного кода

Expose C++ reference returns as Carbon reference returns (#6618)

Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
Geoff Romer 3 месяцев назад
Родитель
Сommit
95eb7b16bb

+ 3 - 1
toolchain/check/context.h

@@ -255,7 +255,9 @@ class Context {
 
   // Data about a form expression.
   struct FormExpr {
-    // The inst ID of the form expression itself.
+    // The inst ID of the form expression itself. This is always a form inst,
+    // such as InitForm or RefForm.
+    // TODO: Consider creating an AnyForm inst category to refer to those insts.
     SemIR::InstId form_inst_id;
     // The inst ID of the form expression's type component.
     SemIR::TypeInstId type_component_id;

+ 56 - 34
toolchain/check/cpp/import.cpp

@@ -1195,9 +1195,26 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
 // are treated as returning a class instance.
 // TODO: Support more return types.
 static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id,
-                              clang::FunctionDecl* clang_decl) -> TypeExpr {
+                              clang::FunctionDecl* clang_decl)
+    -> Context::FormExpr {
+  auto make_init_form = [&](SemIR::TypeInstId type_component_inst_id) {
+    SemIR::InitForm inst = {
+        .type_id = SemIR::FormType::TypeId,
+        .type_component_inst_id = type_component_inst_id,
+        .index = context.full_pattern_stack().NextCallParamIndex()};
+    return context.constant_values().GetInstId(TryEvalInst(context, inst));
+  };
+  auto make_ref_form = [&](SemIR::TypeInstId type_component_inst_id) {
+    SemIR::RefForm inst = {.type_id = SemIR::FormType::TypeId,
+                           .type_component_inst_id = type_component_inst_id};
+    return context.constant_values().GetInstId(TryEvalInst(context, inst));
+  };
   clang::QualType orig_ret_type = clang_decl->getReturnType();
   if (!orig_ret_type->isVoidType()) {
+    bool is_reference = orig_ret_type->isReferenceType();
+    if (is_reference) {
+      orig_ret_type = orig_ret_type->getPointeeType();
+    }
     // TODO: We should eventually map reference returns to non-pointer types
     // here. We should return by `ref` for `T&` return types once `ref` return
     // is implemented.
@@ -1205,24 +1222,33 @@ static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id,
     if (!orig_type_inst_id.has_value()) {
       context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
                                          orig_ret_type.getAsString()));
-      return {.inst_id = SemIR::ErrorInst::TypeInstId,
+      return {.form_inst_id = SemIR::ErrorInst::InstId,
+              .type_component_id = SemIR::ErrorInst::TypeInstId,
               .type_id = SemIR::ErrorInst::TypeId};
     }
+    Context::FormExpr result = {
+        .form_inst_id = is_reference ? make_ref_form(orig_type_inst_id)
+                                     : make_init_form(orig_type_inst_id),
+        .type_component_id = orig_type_inst_id,
+        .type_id = type_id};
 
-    return {orig_type_inst_id, type_id};
+    return result;
   }
 
   auto* ctor = dyn_cast<clang::CXXConstructorDecl>(clang_decl);
   if (!ctor) {
     // void.
-    return TypeExpr::None;
+    return {.form_inst_id = SemIR::InstId::None,
+            .type_component_id = SemIR::TypeInstId::None,
+            .type_id = SemIR::TypeId::None};
   }
 
   // TODO: Make this a `PartialType`.
   SemIR::TypeInstId record_type_inst_id = context.types().GetAsTypeInstId(
       LookupClangDeclInstId(context, SemIR::ClangDeclKey(ctor->getParent())));
   return {
-      .inst_id = record_type_inst_id,
+      .form_inst_id = make_init_form(record_type_inst_id),
+      .type_component_id = record_type_inst_id,
       .type_id = context.types().GetTypeIdForTypeInstId(record_type_inst_id)};
 }
 
@@ -1240,16 +1266,17 @@ struct ReturnInfo {
 // Constructors are treated as returning a class instance.
 static auto GetReturnInfo(Context& context, SemIR::LocId loc_id,
                           clang::FunctionDecl* clang_decl) -> ReturnInfo {
-  auto [type_inst_id, type_id] = GetReturnTypeExpr(context, loc_id, clang_decl);
-  if (!type_inst_id.has_value()) {
+  auto [form_inst_id, type_inst_id, type_id] =
+      GetReturnTypeExpr(context, loc_id, clang_decl);
+  if (!form_inst_id.has_value()) {
     // void.
-    return {.return_type_inst_id = type_inst_id,
+    return {.return_type_inst_id = SemIR::TypeInstId::None,
             .return_form_inst_id = SemIR::InstId::None,
             .return_patterns_id = SemIR::InstBlockId::None};
   }
-  if (type_inst_id == SemIR::ErrorInst::TypeInstId) {
-    return {.return_type_inst_id = type_inst_id,
-            .return_form_inst_id = SemIR::InstId::None,
+  if (form_inst_id == SemIR::ErrorInst::InstId) {
+    return {.return_type_inst_id = SemIR::ErrorInst::TypeInstId,
+            .return_form_inst_id = SemIR::ErrorInst::InstId,
             .return_patterns_id = SemIR::InstBlockId::None};
   }
   auto pattern_type_id = GetPatternType(context, type_id);
@@ -1264,30 +1291,25 @@ static auto GetReturnInfo(Context& context, SemIR::LocId loc_id,
   }
   SemIR::ImportIRInstId return_type_import_ir_inst_id =
       AddImportIRInst(context.sem_ir(), return_type_loc);
-  SemIR::InstId return_slot_pattern_id = AddPatternInst(
-      context, MakeImportedLocIdAndInst(
-                   context, return_type_import_ir_inst_id,
-                   SemIR::ReturnSlotPattern({.type_id = pattern_type_id,
-                                             .type_inst_id = type_inst_id})));
-  auto return_index = context.full_pattern_stack().NextCallParamIndex();
-  SemIR::InstId param_pattern_id = AddPatternInst(
-      context,
-      MakeImportedLocIdAndInst(
-          context, return_type_import_ir_inst_id,
-          SemIR::OutParamPattern({.type_id = pattern_type_id,
-                                  .subpattern_id = return_slot_pattern_id,
-                                  .index = return_index})));
-  auto return_patterns_id = context.inst_blocks().Add({param_pattern_id});
-
-  // For consistency with how C++ import handles types, we use TryEvalInst to
-  // directly create a constant rather than adding it to insts() first.
-  auto return_form_const_id = TryEvalInst(
-      context, SemIR::InitForm{.type_id = SemIR::FormType::TypeId,
-                               .type_component_inst_id = type_inst_id,
-                               .index = return_index});
+  auto return_patterns_id = SemIR::InstBlockId::Empty;
+  if (auto init_form =
+          context.insts().TryGetAs<SemIR::InitForm>(form_inst_id)) {
+    SemIR::InstId return_slot_pattern_id = AddPatternInst(
+        context, MakeImportedLocIdAndInst(
+                     context, return_type_import_ir_inst_id,
+                     SemIR::ReturnSlotPattern({.type_id = pattern_type_id,
+                                               .type_inst_id = type_inst_id})));
+    auto param_pattern_id = AddPatternInst(
+        context,
+        MakeImportedLocIdAndInst(
+            context, return_type_import_ir_inst_id,
+            SemIR::OutParamPattern({.type_id = pattern_type_id,
+                                    .subpattern_id = return_slot_pattern_id,
+                                    .index = init_form->index})));
+    return_patterns_id = context.inst_blocks().Add({param_pattern_id});
+  }
   return {.return_type_inst_id = type_inst_id,
-          .return_form_inst_id =
-              context.constant_values().GetInstId(return_form_const_id),
+          .return_form_inst_id = form_inst_id,
           .return_patterns_id = return_patterns_id};
 }
 

+ 12 - 14
toolchain/check/testdata/interop/cpp/function/operators.carbon

@@ -1081,7 +1081,6 @@ fn F() {
 // 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]
-// CHECK:STDOUT:   %const: type = const_type %ptr.d9e [concrete]
 // CHECK:STDOUT:   %cpp_operator.type.1ea478.1: type = fn_type @cpp_operator.1 [concrete]
 // CHECK:STDOUT:   %cpp_operator.0a3797.1: %cpp_operator.type.1ea478.1 = struct_value () [concrete]
 // CHECK:STDOUT:   %cpp_operator.type.1ea478.2: type = fn_type @cpp_operator.2 [concrete]
@@ -1149,9 +1148,9 @@ fn F() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %c: ref %C = ref_binding c, %c.var
 // CHECK:STDOUT:   %c.ref.loc11: ref %C = name_ref c, %c
-// CHECK:STDOUT:   %cpp_operator.call.loc11: init %const = call imports.%cpp_operator.decl.4206c9.1(%c.ref.loc11)
+// CHECK:STDOUT:   %cpp_operator.call.loc11: ref %C = call imports.%cpp_operator.decl.4206c9.1(%c.ref.loc11)
 // CHECK:STDOUT:   %c.ref.loc12: ref %C = name_ref c, %c
-// CHECK:STDOUT:   %cpp_operator.call.loc12: init %const = call imports.%cpp_operator.decl.4206c9.2(%c.ref.loc12)
+// CHECK:STDOUT:   %cpp_operator.call.loc12: ref %C = call imports.%cpp_operator.decl.4206c9.2(%c.ref.loc12)
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %minus.patt: %pattern_type.217 = value_binding_pattern minus [concrete]
 // CHECK:STDOUT:   }
@@ -1252,7 +1251,6 @@ fn F() {
 // CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.005: <bound method> = bound_method %int_5.64b, %Core.IntLiteral.as.ImplicitAs.impl.Convert.0b5 [concrete]
 // CHECK:STDOUT:   %bound_method.e9d: <bound method> = bound_method %int_5.64b, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete]
 // CHECK:STDOUT:   %int_5.0f6: %i32 = int_value 5 [concrete]
-// CHECK:STDOUT:   %const.7c5: type = const_type %ptr.d9e [concrete]
 // CHECK:STDOUT:   %operator_PlusEqual__carbon_thunk.type: type = fn_type @operator_PlusEqual__carbon_thunk [concrete]
 // CHECK:STDOUT:   %operator_PlusEqual__carbon_thunk: %operator_PlusEqual__carbon_thunk.type = struct_value () [concrete]
 // CHECK:STDOUT:   %operator_MinusEqual__carbon_thunk.type: type = fn_type @operator_MinusEqual__carbon_thunk [concrete]
@@ -1726,49 +1724,49 @@ fn F() {
 // CHECK:STDOUT:   %.loc26_9.1: %C = acquire_value %c2.ref.loc26
 // CHECK:STDOUT:   %.loc26_9.2: ref %C = value_as_ref %.loc26_9.1
 // CHECK:STDOUT:   %addr.loc26: %ptr.d9e = addr_of %.loc26_9.2
-// CHECK:STDOUT:   %operator_PlusEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_PlusEqual__carbon_thunk.decl(%c1.ref.loc26, %addr.loc26)
+// CHECK:STDOUT:   %operator_PlusEqual__carbon_thunk.call: ref %C = call imports.%operator_PlusEqual__carbon_thunk.decl(%c1.ref.loc26, %addr.loc26)
 // CHECK:STDOUT:   %c1.ref.loc27: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %c2.ref.loc27: ref %C = name_ref c2, %c2
 // CHECK:STDOUT:   %.loc27_9.1: %C = acquire_value %c2.ref.loc27
 // CHECK:STDOUT:   %.loc27_9.2: ref %C = value_as_ref %.loc27_9.1
 // CHECK:STDOUT:   %addr.loc27: %ptr.d9e = addr_of %.loc27_9.2
-// CHECK:STDOUT:   %operator_MinusEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_MinusEqual__carbon_thunk.decl(%c1.ref.loc27, %addr.loc27)
+// CHECK:STDOUT:   %operator_MinusEqual__carbon_thunk.call: ref %C = call imports.%operator_MinusEqual__carbon_thunk.decl(%c1.ref.loc27, %addr.loc27)
 // CHECK:STDOUT:   %c1.ref.loc28: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %c2.ref.loc28: ref %C = name_ref c2, %c2
 // CHECK:STDOUT:   %.loc28_9.1: %C = acquire_value %c2.ref.loc28
 // CHECK:STDOUT:   %.loc28_9.2: ref %C = value_as_ref %.loc28_9.1
 // CHECK:STDOUT:   %addr.loc28: %ptr.d9e = addr_of %.loc28_9.2
-// CHECK:STDOUT:   %operator_StarEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_StarEqual__carbon_thunk.decl(%c1.ref.loc28, %addr.loc28)
+// CHECK:STDOUT:   %operator_StarEqual__carbon_thunk.call: ref %C = call imports.%operator_StarEqual__carbon_thunk.decl(%c1.ref.loc28, %addr.loc28)
 // CHECK:STDOUT:   %c1.ref.loc29: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %c2.ref.loc29: ref %C = name_ref c2, %c2
 // CHECK:STDOUT:   %.loc29_9.1: %C = acquire_value %c2.ref.loc29
 // CHECK:STDOUT:   %.loc29_9.2: ref %C = value_as_ref %.loc29_9.1
 // CHECK:STDOUT:   %addr.loc29: %ptr.d9e = addr_of %.loc29_9.2
-// CHECK:STDOUT:   %operator_SlashEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_SlashEqual__carbon_thunk.decl(%c1.ref.loc29, %addr.loc29)
+// CHECK:STDOUT:   %operator_SlashEqual__carbon_thunk.call: ref %C = call imports.%operator_SlashEqual__carbon_thunk.decl(%c1.ref.loc29, %addr.loc29)
 // CHECK:STDOUT:   %c1.ref.loc30: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %c2.ref.loc30: ref %C = name_ref c2, %c2
 // CHECK:STDOUT:   %.loc30_9.1: %C = acquire_value %c2.ref.loc30
 // CHECK:STDOUT:   %.loc30_9.2: ref %C = value_as_ref %.loc30_9.1
 // CHECK:STDOUT:   %addr.loc30: %ptr.d9e = addr_of %.loc30_9.2
-// CHECK:STDOUT:   %operator_PercentEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_PercentEqual__carbon_thunk.decl(%c1.ref.loc30, %addr.loc30)
+// CHECK:STDOUT:   %operator_PercentEqual__carbon_thunk.call: ref %C = call imports.%operator_PercentEqual__carbon_thunk.decl(%c1.ref.loc30, %addr.loc30)
 // CHECK:STDOUT:   %c1.ref.loc33: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %c2.ref.loc33: ref %C = name_ref c2, %c2
 // CHECK:STDOUT:   %.loc33_9.1: %C = acquire_value %c2.ref.loc33
 // CHECK:STDOUT:   %.loc33_9.2: ref %C = value_as_ref %.loc33_9.1
 // CHECK:STDOUT:   %addr.loc33: %ptr.d9e = addr_of %.loc33_9.2
-// CHECK:STDOUT:   %operator_AmpEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_AmpEqual__carbon_thunk.decl(%c1.ref.loc33, %addr.loc33)
+// CHECK:STDOUT:   %operator_AmpEqual__carbon_thunk.call: ref %C = call imports.%operator_AmpEqual__carbon_thunk.decl(%c1.ref.loc33, %addr.loc33)
 // CHECK:STDOUT:   %c1.ref.loc34: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %c2.ref.loc34: ref %C = name_ref c2, %c2
 // CHECK:STDOUT:   %.loc34_9.1: %C = acquire_value %c2.ref.loc34
 // CHECK:STDOUT:   %.loc34_9.2: ref %C = value_as_ref %.loc34_9.1
 // CHECK:STDOUT:   %addr.loc34: %ptr.d9e = addr_of %.loc34_9.2
-// CHECK:STDOUT:   %operator_PipeEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_PipeEqual__carbon_thunk.decl(%c1.ref.loc34, %addr.loc34)
+// CHECK:STDOUT:   %operator_PipeEqual__carbon_thunk.call: ref %C = call imports.%operator_PipeEqual__carbon_thunk.decl(%c1.ref.loc34, %addr.loc34)
 // CHECK:STDOUT:   %c1.ref.loc35: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %c2.ref.loc35: ref %C = name_ref c2, %c2
 // CHECK:STDOUT:   %.loc35_9.1: %C = acquire_value %c2.ref.loc35
 // CHECK:STDOUT:   %.loc35_9.2: ref %C = value_as_ref %.loc35_9.1
 // CHECK:STDOUT:   %addr.loc35: %ptr.d9e = addr_of %.loc35_9.2
-// CHECK:STDOUT:   %operator_CaretEqual__carbon_thunk.call: init %const.7c5 = call imports.%operator_CaretEqual__carbon_thunk.decl(%c1.ref.loc35, %addr.loc35)
+// CHECK:STDOUT:   %operator_CaretEqual__carbon_thunk.call: ref %C = call imports.%operator_CaretEqual__carbon_thunk.decl(%c1.ref.loc35, %addr.loc35)
 // CHECK:STDOUT:   %c1.ref.loc36: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %int_3.loc36: Core.IntLiteral = int_value 3 [concrete = constants.%int_3.1ba]
 // CHECK:STDOUT:   %impl.elem0.loc36: %.863 = impl_witness_access constants.%ImplicitAs.impl_witness.6bc, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.0b5]
@@ -1778,7 +1776,7 @@ fn F() {
 // CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc36: init %i32 = call %bound_method.loc36_10.2(%int_3.loc36) [concrete = constants.%int_3.822]
 // CHECK:STDOUT:   %.loc36_10.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc36 [concrete = constants.%int_3.822]
 // CHECK:STDOUT:   %.loc36_10.2: %i32 = converted %int_3.loc36, %.loc36_10.1 [concrete = constants.%int_3.822]
-// CHECK:STDOUT:   %cpp_operator.call.loc36: init %const.7c5 = call imports.%cpp_operator.decl.4206c9.19(%c1.ref.loc36, %.loc36_10.2)
+// CHECK:STDOUT:   %cpp_operator.call.loc36: ref %C = call imports.%cpp_operator.decl.4206c9.19(%c1.ref.loc36, %.loc36_10.2)
 // CHECK:STDOUT:   %c1.ref.loc37: ref %C = name_ref c1, %c1
 // CHECK:STDOUT:   %int_5.loc37: Core.IntLiteral = int_value 5 [concrete = constants.%int_5.64b]
 // CHECK:STDOUT:   %impl.elem0.loc37: %.863 = impl_witness_access constants.%ImplicitAs.impl_witness.6bc, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.0b5]
@@ -1788,7 +1786,7 @@ fn F() {
 // CHECK:STDOUT:   %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc37: init %i32 = call %bound_method.loc37_10.2(%int_5.loc37) [concrete = constants.%int_5.0f6]
 // CHECK:STDOUT:   %.loc37_10.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc37 [concrete = constants.%int_5.0f6]
 // CHECK:STDOUT:   %.loc37_10.2: %i32 = converted %int_5.loc37, %.loc37_10.1 [concrete = constants.%int_5.0f6]
-// CHECK:STDOUT:   %cpp_operator.call.loc37: init %const.7c5 = call imports.%cpp_operator.decl.4206c9.20(%c1.ref.loc37, %.loc37_10.2)
+// CHECK:STDOUT:   %cpp_operator.call.loc37: ref %C = call imports.%cpp_operator.decl.4206c9.20(%c1.ref.loc37, %.loc37_10.2)
 // CHECK:STDOUT:   name_binding_decl {
 // CHECK:STDOUT:     %equal.patt: %pattern_type.831 = value_binding_pattern equal [concrete]
 // CHECK:STDOUT:   }

+ 38 - 94
toolchain/check/testdata/interop/cpp/function/reference.carbon

@@ -248,7 +248,7 @@ import Cpp library "return_lvalue_ref.h";
 
 fn F() {
   //@dump-sem-ir-begin
-  let s: Cpp.S* = Cpp.ReturnsLValue();
+  let ref s: Cpp.S = Cpp.ReturnsLValue();
   //@dump-sem-ir-end
 }
 
@@ -270,7 +270,7 @@ import Cpp library "return_rvalue_ref.h";
 
 fn F() {
   //@dump-sem-ir-begin
-  var s: Cpp.S* = Cpp.ReturnsRValue();
+  let ref s: Cpp.S = Cpp.ReturnsRValue();
   //@dump-sem-ir-end
 }
 
@@ -292,7 +292,7 @@ import Cpp library "return_const_lvalue_ref.h";
 
 fn F() {
   //@dump-sem-ir-begin
-  var s: const Cpp.S* = Cpp.ReturnConstLValue();
+  let ref s: const Cpp.S = Cpp.ReturnConstLValue();
   //@dump-sem-ir-end
 }
 
@@ -303,16 +303,17 @@ library "[[@TEST_NAME]]";
 import Cpp library "return_const_lvalue_ref.h";
 
 fn F() {
-  // CHECK:STDERR: fail_call_return_const_lvalue_ref_const_correctness.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `const (const Cpp.S*)` to `Cpp.S*` [ConversionFailure]
-  // CHECK:STDERR:   var s: Cpp.S* = Cpp.ReturnConstLValue();
-  // CHECK:STDERR:   ^~~~~~~~~~~~~
-  // CHECK:STDERR: fail_call_return_const_lvalue_ref_const_correctness.carbon:[[@LINE+4]]:3: note: type `const (const Cpp.S*)` does not implement interface `Core.ImplicitAs(Cpp.S*)` [MissingImplInMemberAccessNote]
-  // CHECK:STDERR:   var s: Cpp.S* = Cpp.ReturnConstLValue();
-  // CHECK:STDERR:   ^~~~~~~~~~~~~
+  // CHECK:STDERR: fail_call_return_const_lvalue_ref_const_correctness.carbon:[[@LINE+7]]:22: error: cannot implicitly convert expression of type `const Cpp.S` to `Cpp.S` [ConversionFailure]
+  // CHECK:STDERR:   let ref s: Cpp.S = Cpp.ReturnConstLValue();
+  // CHECK:STDERR:                      ^~~~~~~~~~~~~~~~~~~~~~~
+  // CHECK:STDERR: fail_call_return_const_lvalue_ref_const_correctness.carbon:[[@LINE+4]]:22: note: type `const Cpp.S` does not implement interface `Core.ImplicitAs(Cpp.S)` [MissingImplInMemberAccessNote]
+  // CHECK:STDERR:   let ref s: Cpp.S = Cpp.ReturnConstLValue();
+  // CHECK:STDERR:                      ^~~~~~~~~~~~~~~~~~~~~~~
   // CHECK:STDERR:
-  var s: Cpp.S* = Cpp.ReturnConstLValue();
+  let ref s: Cpp.S = Cpp.ReturnConstLValue();
 }
 
+
 // CHECK:STDOUT: --- call_param_lvalue_ref.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
@@ -849,17 +850,12 @@ fn F() {
 // CHECK:STDOUT: --- call_return_lvalue_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:   %ptr: type = ptr_type %S [concrete]
-// CHECK:STDOUT:   %pattern_type.259: type = pattern_type %ptr [concrete]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %S [concrete]
 // CHECK:STDOUT:   %ReturnsLValue.cpp_overload_set.type: type = cpp_overload_set_type @ReturnsLValue.cpp_overload_set [concrete]
 // CHECK:STDOUT:   %ReturnsLValue.cpp_overload_set.value: %ReturnsLValue.cpp_overload_set.type = cpp_overload_set_value @ReturnsLValue.cpp_overload_set [concrete]
-// CHECK:STDOUT:   %const: type = const_type %ptr [concrete]
 // CHECK:STDOUT:   %ReturnsLValue.type: type = fn_type @ReturnsLValue [concrete]
 // CHECK:STDOUT:   %ReturnsLValue: %ReturnsLValue.type = struct_value () [concrete]
-// CHECK:STDOUT:   %DestroyOp.type: type = fn_type @DestroyOp [concrete]
-// CHECK:STDOUT:   %DestroyOp: %DestroyOp.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -870,53 +866,34 @@ fn F() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
 // CHECK:STDOUT:   %ReturnsLValue.cpp_overload_set.value: %ReturnsLValue.cpp_overload_set.type = cpp_overload_set_value @ReturnsLValue.cpp_overload_set [concrete = constants.%ReturnsLValue.cpp_overload_set.value]
-// CHECK:STDOUT:   %ReturnsLValue.decl: %ReturnsLValue.type = fn_decl @ReturnsLValue [concrete = constants.%ReturnsLValue] {
-// CHECK:STDOUT:     <elided>
-// CHECK:STDOUT:   } {
-// CHECK:STDOUT:     <elided>
-// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %ReturnsLValue.decl: %ReturnsLValue.type = fn_decl @ReturnsLValue [concrete = constants.%ReturnsLValue] {} {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %s.patt: %pattern_type.259 = value_binding_pattern s [concrete]
+// CHECK:STDOUT:     %s.patt: %pattern_type = ref_binding_pattern s [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Cpp.ref.loc8_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   %Cpp.ref.loc8_22: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
 // CHECK:STDOUT:   %ReturnsLValue.ref: %ReturnsLValue.cpp_overload_set.type = name_ref ReturnsLValue, imports.%ReturnsLValue.cpp_overload_set.value [concrete = constants.%ReturnsLValue.cpp_overload_set.value]
-// CHECK:STDOUT:   %ReturnsLValue.call: init %const = call imports.%ReturnsLValue.decl()
-// CHECK:STDOUT:   %.loc8_15: type = splice_block %ptr [concrete = constants.%ptr] {
-// CHECK:STDOUT:     %Cpp.ref.loc8_10: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   %ReturnsLValue.call: ref %S = call imports.%ReturnsLValue.decl()
+// CHECK:STDOUT:   %.loc8: type = splice_block %S.ref [concrete = constants.%S] {
+// CHECK:STDOUT:     %Cpp.ref.loc8_14: <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:     %ptr: type = ptr_type %S.ref [concrete = constants.%ptr]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc8_37.1: init %ptr = as_compatible %ReturnsLValue.call
-// CHECK:STDOUT:   %.loc8_37.2: init %ptr = converted %ReturnsLValue.call, %.loc8_37.1
-// CHECK:STDOUT:   %.loc8_37.3: ref %ptr = temporary_storage
-// CHECK:STDOUT:   %.loc8_37.4: ref %ptr = temporary %.loc8_37.3, %.loc8_37.2
-// CHECK:STDOUT:   %.loc8_37.5: %ptr = acquire_value %.loc8_37.4
-// CHECK:STDOUT:   %s: %ptr = value_binding s, %.loc8_37.5
-// CHECK:STDOUT:   %DestroyOp.bound: <bound method> = bound_method %.loc8_37.4, constants.%DestroyOp
-// CHECK:STDOUT:   %DestroyOp.call: init %empty_tuple.type = call %DestroyOp.bound(%.loc8_37.4)
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %s: ref %S = ref_binding s, %ReturnsLValue.call
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @DestroyOp(%self.param: %ptr) = "no_op";
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- call_return_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:   %ptr: type = ptr_type %S [concrete]
-// CHECK:STDOUT:   %pattern_type.259: type = pattern_type %ptr [concrete]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %S [concrete]
 // CHECK:STDOUT:   %ReturnsRValue.cpp_overload_set.type: type = cpp_overload_set_type @ReturnsRValue.cpp_overload_set [concrete]
 // CHECK:STDOUT:   %ReturnsRValue.cpp_overload_set.value: %ReturnsRValue.cpp_overload_set.type = cpp_overload_set_value @ReturnsRValue.cpp_overload_set [concrete]
-// CHECK:STDOUT:   %const: type = const_type %ptr [concrete]
 // CHECK:STDOUT:   %ReturnsRValue.type: type = fn_type @ReturnsRValue [concrete]
 // CHECK:STDOUT:   %ReturnsRValue: %ReturnsRValue.type = struct_value () [concrete]
-// CHECK:STDOUT:   %DestroyOp.type: type = fn_type @DestroyOp [concrete]
-// CHECK:STDOUT:   %DestroyOp: %DestroyOp.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -927,54 +904,35 @@ fn F() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
 // CHECK:STDOUT:   %ReturnsRValue.cpp_overload_set.value: %ReturnsRValue.cpp_overload_set.type = cpp_overload_set_value @ReturnsRValue.cpp_overload_set [concrete = constants.%ReturnsRValue.cpp_overload_set.value]
-// CHECK:STDOUT:   %ReturnsRValue.decl: %ReturnsRValue.type = fn_decl @ReturnsRValue [concrete = constants.%ReturnsRValue] {
-// CHECK:STDOUT:     <elided>
-// CHECK:STDOUT:   } {
-// CHECK:STDOUT:     <elided>
-// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %ReturnsRValue.decl: %ReturnsRValue.type = fn_decl @ReturnsRValue [concrete = constants.%ReturnsRValue] {} {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %s.patt: %pattern_type.259 = ref_binding_pattern s [concrete]
-// CHECK:STDOUT:     %s.var_patt: %pattern_type.259 = var_pattern %s.patt [concrete]
+// CHECK:STDOUT:     %s.patt: %pattern_type = ref_binding_pattern s [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %s.var: ref %ptr = var %s.var_patt
-// CHECK:STDOUT:   %Cpp.ref.loc8_19: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   %Cpp.ref.loc8_22: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
 // CHECK:STDOUT:   %ReturnsRValue.ref: %ReturnsRValue.cpp_overload_set.type = name_ref ReturnsRValue, imports.%ReturnsRValue.cpp_overload_set.value [concrete = constants.%ReturnsRValue.cpp_overload_set.value]
-// CHECK:STDOUT:   %ReturnsRValue.call: init %const = call imports.%ReturnsRValue.decl()
-// CHECK:STDOUT:   %.loc8_3.1: init %ptr = as_compatible %ReturnsRValue.call
-// CHECK:STDOUT:   %.loc8_3.2: init %ptr = converted %ReturnsRValue.call, %.loc8_3.1
-// CHECK:STDOUT:   assign %s.var, %.loc8_3.2
-// CHECK:STDOUT:   %.loc8_15: type = splice_block %ptr [concrete = constants.%ptr] {
-// CHECK:STDOUT:     %Cpp.ref.loc8_10: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   %ReturnsRValue.call: ref %S = call imports.%ReturnsRValue.decl()
+// CHECK:STDOUT:   %.loc8: type = splice_block %S.ref [concrete = constants.%S] {
+// CHECK:STDOUT:     %Cpp.ref.loc8_14: <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:     %ptr: type = ptr_type %S.ref [concrete = constants.%ptr]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %s: ref %ptr = ref_binding s, %s.var
-// CHECK:STDOUT:   %DestroyOp.bound: <bound method> = bound_method %s.var, constants.%DestroyOp
-// CHECK:STDOUT:   %DestroyOp.call: init %empty_tuple.type = call %DestroyOp.bound(%s.var)
+// CHECK:STDOUT:   %s: ref %S = ref_binding s, %ReturnsRValue.call
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @DestroyOp(%self.param: %ptr) = "no_op";
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- call_return_const_lvalue_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:   %const.e39: type = const_type %S [concrete]
-// CHECK:STDOUT:   %ptr: type = ptr_type %const.e39 [concrete]
-// CHECK:STDOUT:   %pattern_type.32f: type = pattern_type %ptr [concrete]
+// CHECK:STDOUT:   %const: type = const_type %S [concrete]
+// CHECK:STDOUT:   %pattern_type: type = pattern_type %const [concrete]
 // CHECK:STDOUT:   %ReturnConstLValue.cpp_overload_set.type: type = cpp_overload_set_type @ReturnConstLValue.cpp_overload_set [concrete]
 // CHECK:STDOUT:   %ReturnConstLValue.cpp_overload_set.value: %ReturnConstLValue.cpp_overload_set.type = cpp_overload_set_value @ReturnConstLValue.cpp_overload_set [concrete]
-// CHECK:STDOUT:   %const.179: type = const_type %ptr [concrete]
 // CHECK:STDOUT:   %ReturnConstLValue.type: type = fn_type @ReturnConstLValue [concrete]
 // CHECK:STDOUT:   %ReturnConstLValue: %ReturnConstLValue.type = struct_value () [concrete]
-// CHECK:STDOUT:   %DestroyOp.type: type = fn_type @DestroyOp [concrete]
-// CHECK:STDOUT:   %DestroyOp: %DestroyOp.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -985,37 +943,23 @@ fn F() {
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
 // CHECK:STDOUT:   %ReturnConstLValue.cpp_overload_set.value: %ReturnConstLValue.cpp_overload_set.type = cpp_overload_set_value @ReturnConstLValue.cpp_overload_set [concrete = constants.%ReturnConstLValue.cpp_overload_set.value]
-// CHECK:STDOUT:   %ReturnConstLValue.decl: %ReturnConstLValue.type = fn_decl @ReturnConstLValue [concrete = constants.%ReturnConstLValue] {
-// CHECK:STDOUT:     <elided>
-// CHECK:STDOUT:   } {
-// CHECK:STDOUT:     <elided>
-// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %ReturnConstLValue.decl: %ReturnConstLValue.type = fn_decl @ReturnConstLValue [concrete = constants.%ReturnConstLValue] {} {}
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: fn @F() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %s.patt: %pattern_type.32f = ref_binding_pattern s [concrete]
-// CHECK:STDOUT:     %s.var_patt: %pattern_type.32f = var_pattern %s.patt [concrete]
+// CHECK:STDOUT:     %s.patt: %pattern_type = ref_binding_pattern s [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %s.var: ref %ptr = var %s.var_patt
-// CHECK:STDOUT:   %Cpp.ref.loc8_25: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   %Cpp.ref.loc8_28: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
 // CHECK:STDOUT:   %ReturnConstLValue.ref: %ReturnConstLValue.cpp_overload_set.type = name_ref ReturnConstLValue, imports.%ReturnConstLValue.cpp_overload_set.value [concrete = constants.%ReturnConstLValue.cpp_overload_set.value]
-// CHECK:STDOUT:   %ReturnConstLValue.call: init %const.179 = call imports.%ReturnConstLValue.decl()
-// CHECK:STDOUT:   %.loc8_3.1: init %ptr = as_compatible %ReturnConstLValue.call
-// CHECK:STDOUT:   %.loc8_3.2: init %ptr = converted %ReturnConstLValue.call, %.loc8_3.1
-// CHECK:STDOUT:   assign %s.var, %.loc8_3.2
-// CHECK:STDOUT:   %.loc8_21: type = splice_block %ptr [concrete = constants.%ptr] {
-// CHECK:STDOUT:     %Cpp.ref.loc8_16: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:   %ReturnConstLValue.call: ref %const = call imports.%ReturnConstLValue.decl()
+// CHECK:STDOUT:   %.loc8: type = splice_block %const [concrete = constants.%const] {
+// CHECK:STDOUT:     %Cpp.ref.loc8_20: <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:     %const: type = const_type %S.ref [concrete = constants.%const.e39]
-// CHECK:STDOUT:     %ptr: type = ptr_type %const [concrete = constants.%ptr]
+// CHECK:STDOUT:     %const: type = const_type %S.ref [concrete = constants.%const]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %s: ref %ptr = ref_binding s, %s.var
-// CHECK:STDOUT:   %DestroyOp.bound: <bound method> = bound_method %s.var, constants.%DestroyOp
-// CHECK:STDOUT:   %DestroyOp.call: init %empty_tuple.type = call %DestroyOp.bound(%s.var)
+// CHECK:STDOUT:   %s: ref %const = ref_binding s, %ReturnConstLValue.call
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: fn @DestroyOp(%self.param: %ptr) = "no_op";
-// CHECK:STDOUT:

+ 54 - 116
toolchain/lower/testdata/interop/cpp/reference.carbon

@@ -92,13 +92,13 @@ auto ReturnConstIntRef() -> const int&;
 ''';
 
 fn GetRefs() {
-  var _: Cpp.C* = Cpp.ReturnCRef();
-  var _: Cpp.C* = Cpp.ReturnCRRef();
-  var _: const Cpp.C* = Cpp.ReturnConstCRef();
+  let ref _: Cpp.C = Cpp.ReturnCRef();
+  let ref _: Cpp.C = Cpp.ReturnCRRef();
+  let ref _: const Cpp.C = Cpp.ReturnConstCRef();
 
-  var _: i32* = Cpp.ReturnIntRef();
-  var _: i32* = Cpp.ReturnIntRRef();
-  var _: const i32* = Cpp.ReturnConstIntRef();
+  let ref _: i32 = Cpp.ReturnIntRef();
+  let ref _: i32 = Cpp.ReturnIntRRef();
+  let ref _: const i32 = Cpp.ReturnConstIntRef();
 }
 
 // --- return_references_via_thunk.carbon
@@ -119,13 +119,13 @@ auto ReturnConstIntRef(ForceThunk = {}) -> const int&;
 ''';
 
 fn GetRefs() {
-  var _: Cpp.C* = Cpp.ReturnCRef();
-  var _: Cpp.C* = Cpp.ReturnCRRef();
-  var _: const Cpp.C* = Cpp.ReturnConstCRef();
+  let ref _: Cpp.C = Cpp.ReturnCRef();
+  let ref _: Cpp.C = Cpp.ReturnCRRef();
+  let ref _: const Cpp.C = Cpp.ReturnConstCRef();
 
-  var _: i32* = Cpp.ReturnIntRef();
-  var _: i32* = Cpp.ReturnIntRRef();
-  var _: const i32* = Cpp.ReturnConstIntRef();
+  let ref _: i32 = Cpp.ReturnIntRef();
+  let ref _: i32 = Cpp.ReturnIntRRef();
+  let ref _: const i32 = Cpp.ReturnConstIntRef();
 }
 
 // CHECK:STDOUT: ; ModuleID = 'pass_references.carbon'
@@ -438,31 +438,13 @@ fn GetRefs() {
 // CHECK:STDOUT: ; Function Attrs: nounwind
 // CHECK:STDOUT: define void @_CGetRefs.Main() #0 !dbg !12 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %_.var.loc17 = alloca ptr, align 8, !dbg !15
-// CHECK:STDOUT:   %_.var.loc18 = alloca ptr, align 8, !dbg !16
-// CHECK:STDOUT:   %_.var.loc19 = alloca ptr, align 8, !dbg !17
-// CHECK:STDOUT:   %_.var.loc21 = alloca ptr, align 8, !dbg !18
-// CHECK:STDOUT:   %_.var.loc22 = alloca ptr, align 8, !dbg !19
-// CHECK:STDOUT:   %_.var.loc23 = alloca ptr, align 8, !dbg !20
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc17), !dbg !15
-// CHECK:STDOUT:   %ReturnCRef.call = call ptr @_Z10ReturnCRefv(), !dbg !21
-// CHECK:STDOUT:   store ptr %ReturnCRef.call, ptr %_.var.loc17, align 8, !dbg !15
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc18), !dbg !16
-// CHECK:STDOUT:   %ReturnCRRef.call = call ptr @_Z11ReturnCRRefv(), !dbg !22
-// CHECK:STDOUT:   store ptr %ReturnCRRef.call, ptr %_.var.loc18, align 8, !dbg !16
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc19), !dbg !17
-// CHECK:STDOUT:   %ReturnConstCRef.call = call ptr @_Z15ReturnConstCRefv(), !dbg !23
-// CHECK:STDOUT:   store ptr %ReturnConstCRef.call, ptr %_.var.loc19, align 8, !dbg !17
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc21), !dbg !18
-// CHECK:STDOUT:   %ReturnIntRef.call = call ptr @_Z12ReturnIntRefv(), !dbg !24
-// CHECK:STDOUT:   store ptr %ReturnIntRef.call, ptr %_.var.loc21, align 8, !dbg !18
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc22), !dbg !19
-// CHECK:STDOUT:   %ReturnIntRRef.call = call ptr @_Z13ReturnIntRRefv(), !dbg !25
-// CHECK:STDOUT:   store ptr %ReturnIntRRef.call, ptr %_.var.loc22, align 8, !dbg !19
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc23), !dbg !20
-// CHECK:STDOUT:   %ReturnConstIntRef.call = call ptr @_Z17ReturnConstIntRefv(), !dbg !26
-// CHECK:STDOUT:   store ptr %ReturnConstIntRef.call, ptr %_.var.loc23, align 8, !dbg !20
-// CHECK:STDOUT:   ret void, !dbg !27
+// CHECK:STDOUT:   %ReturnCRef.call = call ptr @_Z10ReturnCRefv(), !dbg !15
+// CHECK:STDOUT:   %ReturnCRRef.call = call ptr @_Z11ReturnCRRefv(), !dbg !16
+// CHECK:STDOUT:   %ReturnConstCRef.call = call ptr @_Z15ReturnConstCRefv(), !dbg !17
+// CHECK:STDOUT:   %ReturnIntRef.call = call ptr @_Z12ReturnIntRefv(), !dbg !18
+// CHECK:STDOUT:   %ReturnIntRRef.call = call ptr @_Z13ReturnIntRRefv(), !dbg !19
+// CHECK:STDOUT:   %ReturnConstIntRef.call = call ptr @_Z17ReturnConstIntRefv(), !dbg !20
+// CHECK:STDOUT:   ret void, !dbg !21
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: declare ptr @_Z10ReturnCRefv()
@@ -477,14 +459,7 @@ fn GetRefs() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: declare ptr @_Z17ReturnConstIntRefv()
 // CHECK:STDOUT:
-// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
-// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
-// CHECK:STDOUT:
-// CHECK:STDOUT: ; uselistorder directives
-// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 5, 4, 3, 2, 1, 0 }
-// CHECK:STDOUT:
 // CHECK:STDOUT: attributes #0 = { nounwind }
-// CHECK:STDOUT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
 // CHECK:STDOUT: !llvm.dbg.cu = !{!6}
@@ -505,19 +480,13 @@ fn GetRefs() {
 // CHECK:STDOUT: !12 = distinct !DISubprogram(name: "GetRefs", linkageName: "_CGetRefs.Main", scope: null, file: !7, line: 16, type: !13, spFlags: DISPFlagDefinition, unit: !6)
 // CHECK:STDOUT: !13 = !DISubroutineType(types: !14)
 // CHECK:STDOUT: !14 = !{null}
-// CHECK:STDOUT: !15 = !DILocation(line: 17, column: 3, scope: !12)
-// CHECK:STDOUT: !16 = !DILocation(line: 18, column: 3, scope: !12)
-// CHECK:STDOUT: !17 = !DILocation(line: 19, column: 3, scope: !12)
-// CHECK:STDOUT: !18 = !DILocation(line: 21, column: 3, scope: !12)
-// CHECK:STDOUT: !19 = !DILocation(line: 22, column: 3, scope: !12)
-// CHECK:STDOUT: !20 = !DILocation(line: 23, column: 3, scope: !12)
-// CHECK:STDOUT: !21 = !DILocation(line: 17, column: 19, scope: !12)
-// CHECK:STDOUT: !22 = !DILocation(line: 18, column: 19, scope: !12)
-// CHECK:STDOUT: !23 = !DILocation(line: 19, column: 25, scope: !12)
-// CHECK:STDOUT: !24 = !DILocation(line: 21, column: 17, scope: !12)
-// CHECK:STDOUT: !25 = !DILocation(line: 22, column: 17, scope: !12)
-// CHECK:STDOUT: !26 = !DILocation(line: 23, column: 23, scope: !12)
-// CHECK:STDOUT: !27 = !DILocation(line: 16, column: 1, scope: !12)
+// CHECK:STDOUT: !15 = !DILocation(line: 17, column: 22, scope: !12)
+// CHECK:STDOUT: !16 = !DILocation(line: 18, column: 22, scope: !12)
+// CHECK:STDOUT: !17 = !DILocation(line: 19, column: 28, scope: !12)
+// CHECK:STDOUT: !18 = !DILocation(line: 21, column: 20, scope: !12)
+// CHECK:STDOUT: !19 = !DILocation(line: 22, column: 20, scope: !12)
+// CHECK:STDOUT: !20 = !DILocation(line: 23, column: 26, scope: !12)
+// CHECK:STDOUT: !21 = !DILocation(line: 16, column: 1, scope: !12)
 // CHECK:STDOUT: ; ModuleID = 'return_references_via_thunk.carbon'
 // CHECK:STDOUT: source_filename = "return_references_via_thunk.carbon"
 // CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
@@ -528,103 +497,78 @@ fn GetRefs() {
 // CHECK:STDOUT: ; Function Attrs: nounwind
 // CHECK:STDOUT: define void @_CGetRefs.Main() #0 !dbg !12 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %_.var.loc18 = alloca ptr, align 8, !dbg !15
-// CHECK:STDOUT:   %_.var.loc19 = alloca ptr, align 8, !dbg !16
-// CHECK:STDOUT:   %_.var.loc20 = alloca ptr, align 8, !dbg !17
-// CHECK:STDOUT:   %_.var.loc22 = alloca ptr, align 8, !dbg !18
-// CHECK:STDOUT:   %_.var.loc23 = alloca ptr, align 8, !dbg !19
-// CHECK:STDOUT:   %_.var.loc24 = alloca ptr, align 8, !dbg !20
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc18), !dbg !15
-// CHECK:STDOUT:   %ReturnCRef__carbon_thunk.call = call ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk0(), !dbg !21
-// CHECK:STDOUT:   store ptr %ReturnCRef__carbon_thunk.call, ptr %_.var.loc18, align 8, !dbg !15
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc19), !dbg !16
-// CHECK:STDOUT:   %ReturnCRRef__carbon_thunk.call = call ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk0(), !dbg !22
-// CHECK:STDOUT:   store ptr %ReturnCRRef__carbon_thunk.call, ptr %_.var.loc19, align 8, !dbg !16
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc20), !dbg !17
-// CHECK:STDOUT:   %ReturnConstCRef__carbon_thunk.call = call ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk0(), !dbg !23
-// CHECK:STDOUT:   store ptr %ReturnConstCRef__carbon_thunk.call, ptr %_.var.loc20, align 8, !dbg !17
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc22), !dbg !18
-// CHECK:STDOUT:   %ReturnIntRef__carbon_thunk.call = call ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk0(), !dbg !24
-// CHECK:STDOUT:   store ptr %ReturnIntRef__carbon_thunk.call, ptr %_.var.loc22, align 8, !dbg !18
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc23), !dbg !19
-// CHECK:STDOUT:   %ReturnIntRRef__carbon_thunk.call = call ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk0(), !dbg !25
-// CHECK:STDOUT:   store ptr %ReturnIntRRef__carbon_thunk.call, ptr %_.var.loc23, align 8, !dbg !19
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var.loc24), !dbg !20
-// CHECK:STDOUT:   %ReturnConstIntRef__carbon_thunk.call = call ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk0(), !dbg !26
-// CHECK:STDOUT:   store ptr %ReturnConstIntRef__carbon_thunk.call, ptr %_.var.loc24, align 8, !dbg !20
-// CHECK:STDOUT:   ret void, !dbg !27
+// CHECK:STDOUT:   %ReturnCRef__carbon_thunk.call = call ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk0(), !dbg !15
+// CHECK:STDOUT:   %ReturnCRRef__carbon_thunk.call = call ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk0(), !dbg !16
+// CHECK:STDOUT:   %ReturnConstCRef__carbon_thunk.call = call ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk0(), !dbg !17
+// CHECK:STDOUT:   %ReturnIntRef__carbon_thunk.call = call ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk0(), !dbg !18
+// CHECK:STDOUT:   %ReturnIntRRef__carbon_thunk.call = call ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk0(), !dbg !19
+// CHECK:STDOUT:   %ReturnConstIntRef__carbon_thunk.call = call ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk0(), !dbg !20
+// CHECK:STDOUT:   ret void, !dbg !21
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
-// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
-// CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
-// CHECK:STDOUT: define dso_local noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk0() #2 {
+// CHECK:STDOUT: define dso_local noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk0() #1 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %agg.tmp = alloca %class.ForceThunk, align 1
 // CHECK:STDOUT:   %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk()
 // CHECK:STDOUT:   ret ptr %call
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: declare noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk() #3
+// CHECK:STDOUT: declare noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk() #2
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
-// CHECK:STDOUT: define dso_local noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk0() #2 {
+// CHECK:STDOUT: define dso_local noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk0() #1 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %agg.tmp = alloca %class.ForceThunk, align 1
 // CHECK:STDOUT:   %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk()
 // CHECK:STDOUT:   ret ptr %call
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: declare noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk() #3
+// CHECK:STDOUT: declare noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk() #2
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
-// CHECK:STDOUT: define dso_local noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk0() #2 {
+// CHECK:STDOUT: define dso_local noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk0() #1 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %agg.tmp = alloca %class.ForceThunk, align 1
 // CHECK:STDOUT:   %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk()
 // CHECK:STDOUT:   ret ptr %call
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: declare noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk() #3
+// CHECK:STDOUT: declare noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk() #2
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
-// CHECK:STDOUT: define dso_local noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk0() #2 {
+// CHECK:STDOUT: define dso_local noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk0() #1 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %agg.tmp = alloca %class.ForceThunk, align 1
 // CHECK:STDOUT:   %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk()
 // CHECK:STDOUT:   ret ptr %call
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: declare noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk() #3
+// CHECK:STDOUT: declare noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk() #2
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
-// CHECK:STDOUT: define dso_local noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk0() #2 {
+// CHECK:STDOUT: define dso_local noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk0() #1 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %agg.tmp = alloca %class.ForceThunk, align 1
 // CHECK:STDOUT:   %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk()
 // CHECK:STDOUT:   ret ptr %call
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: declare noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk() #3
+// CHECK:STDOUT: declare noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk() #2
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
-// CHECK:STDOUT: define dso_local noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk0() #2 {
+// CHECK:STDOUT: define dso_local noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk0() #1 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %agg.tmp = alloca %class.ForceThunk, align 1
 // CHECK:STDOUT:   %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk()
 // CHECK:STDOUT:   ret ptr %call
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: declare noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk() #3
-// CHECK:STDOUT:
-// CHECK:STDOUT: ; uselistorder directives
-// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 5, 4, 3, 2, 1, 0 }
+// CHECK:STDOUT: declare noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk() #2
 // CHECK:STDOUT:
 // CHECK:STDOUT: attributes #0 = { nounwind }
-// CHECK:STDOUT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
-// CHECK:STDOUT: attributes #2 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-// CHECK:STDOUT: attributes #3 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+// CHECK:STDOUT: attributes #2 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
 // CHECK:STDOUT: !llvm.dbg.cu = !{!6}
@@ -645,16 +589,10 @@ fn GetRefs() {
 // CHECK:STDOUT: !12 = distinct !DISubprogram(name: "GetRefs", linkageName: "_CGetRefs.Main", scope: null, file: !7, line: 17, type: !13, spFlags: DISPFlagDefinition, unit: !6)
 // CHECK:STDOUT: !13 = !DISubroutineType(types: !14)
 // CHECK:STDOUT: !14 = !{null}
-// CHECK:STDOUT: !15 = !DILocation(line: 18, column: 3, scope: !12)
-// CHECK:STDOUT: !16 = !DILocation(line: 19, column: 3, scope: !12)
-// CHECK:STDOUT: !17 = !DILocation(line: 20, column: 3, scope: !12)
-// CHECK:STDOUT: !18 = !DILocation(line: 22, column: 3, scope: !12)
-// CHECK:STDOUT: !19 = !DILocation(line: 23, column: 3, scope: !12)
-// CHECK:STDOUT: !20 = !DILocation(line: 24, column: 3, scope: !12)
-// CHECK:STDOUT: !21 = !DILocation(line: 18, column: 19, scope: !12)
-// CHECK:STDOUT: !22 = !DILocation(line: 19, column: 19, scope: !12)
-// CHECK:STDOUT: !23 = !DILocation(line: 20, column: 25, scope: !12)
-// CHECK:STDOUT: !24 = !DILocation(line: 22, column: 17, scope: !12)
-// CHECK:STDOUT: !25 = !DILocation(line: 23, column: 17, scope: !12)
-// CHECK:STDOUT: !26 = !DILocation(line: 24, column: 23, scope: !12)
-// CHECK:STDOUT: !27 = !DILocation(line: 17, column: 1, scope: !12)
+// CHECK:STDOUT: !15 = !DILocation(line: 18, column: 22, scope: !12)
+// CHECK:STDOUT: !16 = !DILocation(line: 19, column: 22, scope: !12)
+// CHECK:STDOUT: !17 = !DILocation(line: 20, column: 28, scope: !12)
+// CHECK:STDOUT: !18 = !DILocation(line: 22, column: 20, scope: !12)
+// CHECK:STDOUT: !19 = !DILocation(line: 23, column: 20, scope: !12)
+// CHECK:STDOUT: !20 = !DILocation(line: 24, column: 26, scope: !12)
+// CHECK:STDOUT: !21 = !DILocation(line: 17, column: 1, scope: !12)