From a779cc37a035dbab3ff0ecdd86ddd899186f8b19 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 26 May 2026 13:38:49 -0700 Subject: [PATCH] Support converted `ref` arguments. (#7258) Allow a `ref`-tagged expression to be converted to match a reference parameter. Move the `ref` checks to the start of `Convert`. Remove the diagnostic for applying `ref` to a non-reference expression so that non-reference expressions that convert to a reference would be accepted (although we don't currently have any such conversions). Assisted-by: Gemini via Antigravity --- toolchain/check/convert.cpp | 66 +++++++------------ .../testdata/builtins/int/and_assign.carbon | 2 +- .../builtins/int/left_shift_assign.carbon | 4 +- .../testdata/builtins/int/or_assign.carbon | 2 +- .../builtins/int/right_shift_assign.carbon | 4 +- .../testdata/builtins/int/sdiv_assign.carbon | 2 +- .../testdata/builtins/int/smod_assign.carbon | 2 +- .../testdata/builtins/int/smul_assign.carbon | 2 +- .../testdata/builtins/int/ssub_assign.carbon | 2 +- .../testdata/builtins/int/uadd_assign.carbon | 2 +- .../testdata/builtins/int/udiv_assign.carbon | 2 +- .../testdata/builtins/int/umod_assign.carbon | 2 +- .../testdata/builtins/int/umul_assign.carbon | 2 +- .../testdata/builtins/int/usub_assign.carbon | 2 +- .../testdata/builtins/int/xor_assign.carbon | 2 +- .../check/testdata/function/call/form.carbon | 11 +--- .../check/testdata/function/call/ref.carbon | 16 ++++- .../cpp/function/import/reference.carbon | 64 ++++++++++++++---- toolchain/diagnostics/kind.def | 1 - 19 files changed, 108 insertions(+), 82 deletions(-) diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index dd6f4b6e8c56..5992c7cde20d 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -1735,6 +1735,8 @@ auto CategoryConverter::DoStep(const SemIR::InstId expr_id, case SemIR::ExprCategory::Pattern: CARBON_FATAL("Unexpected expression {0} after builtin conversions", sem_ir_.insts().Get(expr_id)); + case SemIR::ExprCategory::RefTagged: + CARBON_FATAL("Should have stripped ref tags already"); case SemIR::ExprCategory::Error: return Done{SemIR::ErrorInst::InstId}; @@ -1784,41 +1786,10 @@ auto CategoryConverter::DoStep(const SemIR::InstId expr_id, .category = SemIR::ExprCategory::EphemeralRef}; } - case SemIR::ExprCategory::RefTagged: { - auto tagged_expr_id = - sem_ir_.insts().GetAs(expr_id).expr_id; - auto tagged_expr_category = - SemIR::GetExprCategory(sem_ir_, tagged_expr_id); - if (target_.diagnose && - tagged_expr_category != SemIR::ExprCategory::DurableRef) { - CARBON_DIAGNOSTIC( - RefTagNotDurableRef, Error, - "expression tagged with `ref` is not a durable reference"); - context_.emitter().Emit(tagged_expr_id, RefTagNotDurableRef); - } - - if (target_.kind == ConversionTarget::RefParam) { - return Done{expr_id}; - } - - // If the target isn't a reference parameter, ignore the `ref` tag. - // Unnecessary `ref` tags are diagnosed earlier. - return NextStep{.expr_id = tagged_expr_id, - .category = tagged_expr_category}; - } - case SemIR::ExprCategory::DurableRef: if (target_.kind == ConversionTarget::DurableRef || - target_.kind == ConversionTarget::UnmarkedRefParam) { - return Done{expr_id}; - } - if (target_.kind == ConversionTarget::RefParam) { - if (target_.diagnose) { - CARBON_DIAGNOSTIC( - RefParamNoRefTag, Error, - "argument to `ref` parameter not marked with `ref`"); - context_.emitter().Emit(expr_id, RefParamNoRefTag); - } + target_.kind == ConversionTarget::UnmarkedRefParam || + target_.kind == ConversionTarget::RefParam) { return Done{expr_id}; } [[fallthrough]]; @@ -1946,14 +1917,27 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id, return expr_id; } - // Diagnose unnecessary `ref` tags early, so that they're not obscured by - // conversions. - if (starting_category == SemIR::ExprCategory::RefTagged && - target.kind != ConversionTarget::RefParam && target.diagnose) { - CARBON_DIAGNOSTIC(RefTagNoRefParam, Error, - "`ref` tag is not an argument to a `ref` parameter"); - context.emitter().Emit(expr_id, RefTagNoRefParam); + // Handle `ref`-tagged expressions. + if (starting_category == SemIR::ExprCategory::RefTagged) { + if (target.kind != ConversionTarget::RefParam) { + if (target.diagnose) { + CARBON_DIAGNOSTIC(RefTagNoRefParam, Error, + "`ref` tag is not an argument to a `ref` parameter"); + context.emitter().Emit(expr_id, RefTagNoRefParam); + } + return SemIR::ErrorInst::InstId; + } + expr_id = sem_ir.insts().GetAs(expr_id).expr_id; + starting_category = SemIR::GetExprCategory(sem_ir, expr_id); + } else if (target.kind == ConversionTarget::RefParam) { + if (target.diagnose) { + CARBON_DIAGNOSTIC(RefParamNoRefTag, Error, + "argument to `ref` parameter not marked with `ref`"); + context.emitter().Emit(expr_id, RefParamNoRefTag); + } + return SemIR::ErrorInst::InstId; } + auto original_inner_expr_id = expr_id; // TODO: Allow abstract but complete types if the conversion is just a // same-type value acqisition. @@ -2089,7 +2073,7 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id, } // Track that we performed a type conversion, if we did so. - if (orig_expr_id != expr_id) { + if (original_inner_expr_id != expr_id) { expr_id = AddInst(context, loc_id, {.type_id = target.type_id, .original_id = orig_expr_id, diff --git a/toolchain/check/testdata/builtins/int/and_assign.carbon b/toolchain/check/testdata/builtins/int/and_assign.carbon index 09ab67364534..c170e8fc51fa 100644 --- a/toolchain/check/testdata/builtins/int/and_assign.carbon +++ b/toolchain/check/testdata/builtins/int/and_assign.carbon @@ -70,7 +70,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.and_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/left_shift_assign.carbon b/toolchain/check/testdata/builtins/int/left_shift_assign.carbon index c55a08729c2a..7ecee532bb28 100644 --- a/toolchain/check/testdata/builtins/int/left_shift_assign.carbon +++ b/toolchain/check/testdata/builtins/int/left_shift_assign.carbon @@ -70,7 +70,7 @@ fn NotRef(a: i32, b: i32) = "int.left_shift_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -80,7 +80,7 @@ fn NotRef(a: i32, b: i32) = "int.left_shift_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc16: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i64 = name_ref b, %b -// CHECK:STDOUT: %MixedTypes.call: init %empty_tuple.type = call %MixedTypes.ref(%.loc16, %b.ref) +// CHECK:STDOUT: %MixedTypes.call: init %empty_tuple.type = call %MixedTypes.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/or_assign.carbon b/toolchain/check/testdata/builtins/int/or_assign.carbon index 06c87cc635c6..a97f235c20df 100644 --- a/toolchain/check/testdata/builtins/int/or_assign.carbon +++ b/toolchain/check/testdata/builtins/int/or_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.or_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/right_shift_assign.carbon b/toolchain/check/testdata/builtins/int/right_shift_assign.carbon index 3e0f27c52591..e00a9cbca3fc 100644 --- a/toolchain/check/testdata/builtins/int/right_shift_assign.carbon +++ b/toolchain/check/testdata/builtins/int/right_shift_assign.carbon @@ -70,7 +70,7 @@ fn NotRef(a: i32, b: i32) = "int.right_shift_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -80,7 +80,7 @@ fn NotRef(a: i32, b: i32) = "int.right_shift_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc16: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i64 = name_ref b, %b -// CHECK:STDOUT: %MixedTypes.call: init %empty_tuple.type = call %MixedTypes.ref(%.loc16, %b.ref) +// CHECK:STDOUT: %MixedTypes.call: init %empty_tuple.type = call %MixedTypes.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/sdiv_assign.carbon b/toolchain/check/testdata/builtins/int/sdiv_assign.carbon index 0f5f241ea432..0732a7c61c15 100644 --- a/toolchain/check/testdata/builtins/int/sdiv_assign.carbon +++ b/toolchain/check/testdata/builtins/int/sdiv_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.sdiv_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/smod_assign.carbon b/toolchain/check/testdata/builtins/int/smod_assign.carbon index 32c87faa4237..baa079f9f5e2 100644 --- a/toolchain/check/testdata/builtins/int/smod_assign.carbon +++ b/toolchain/check/testdata/builtins/int/smod_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.smod_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/smul_assign.carbon b/toolchain/check/testdata/builtins/int/smul_assign.carbon index ee3334c64877..7d812293eade 100644 --- a/toolchain/check/testdata/builtins/int/smul_assign.carbon +++ b/toolchain/check/testdata/builtins/int/smul_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.smul_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/ssub_assign.carbon b/toolchain/check/testdata/builtins/int/ssub_assign.carbon index 8c4f10d7e4ff..ab862c93df83 100644 --- a/toolchain/check/testdata/builtins/int/ssub_assign.carbon +++ b/toolchain/check/testdata/builtins/int/ssub_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.ssub_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/uadd_assign.carbon b/toolchain/check/testdata/builtins/int/uadd_assign.carbon index 9087c5b972f3..a6634e531c08 100644 --- a/toolchain/check/testdata/builtins/int/uadd_assign.carbon +++ b/toolchain/check/testdata/builtins/int/uadd_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.uadd_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/udiv_assign.carbon b/toolchain/check/testdata/builtins/int/udiv_assign.carbon index 131b646d9368..6e82b36e1691 100644 --- a/toolchain/check/testdata/builtins/int/udiv_assign.carbon +++ b/toolchain/check/testdata/builtins/int/udiv_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.udiv_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/umod_assign.carbon b/toolchain/check/testdata/builtins/int/umod_assign.carbon index 938c8653a367..17664e033f86 100644 --- a/toolchain/check/testdata/builtins/int/umod_assign.carbon +++ b/toolchain/check/testdata/builtins/int/umod_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.umod_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/umul_assign.carbon b/toolchain/check/testdata/builtins/int/umul_assign.carbon index 7cbd91550e9f..87e5dc081752 100644 --- a/toolchain/check/testdata/builtins/int/umul_assign.carbon +++ b/toolchain/check/testdata/builtins/int/umul_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.umul_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/usub_assign.carbon b/toolchain/check/testdata/builtins/int/usub_assign.carbon index 1d8581be66f4..06e31f1f28c8 100644 --- a/toolchain/check/testdata/builtins/int/usub_assign.carbon +++ b/toolchain/check/testdata/builtins/int/usub_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.usub_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/builtins/int/xor_assign.carbon b/toolchain/check/testdata/builtins/int/xor_assign.carbon index 63115a1e6de6..6649c728d970 100644 --- a/toolchain/check/testdata/builtins/int/xor_assign.carbon +++ b/toolchain/check/testdata/builtins/int/xor_assign.carbon @@ -64,7 +64,7 @@ fn MixedTypes(ref a: i32, b: i64) = "int.xor_assign"; // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a // CHECK:STDOUT: %.loc8: %i32 = ref_tag %a.ref // CHECK:STDOUT: %b.ref: %i32 = name_ref b, %b -// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%.loc8, %b.ref) +// CHECK:STDOUT: %Builtin.call: init %empty_tuple.type = call %Builtin.ref(%a.ref, %b.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/call/form.carbon b/toolchain/check/testdata/function/call/form.carbon index c9ae2e29562d..d1eb988eb990 100644 --- a/toolchain/check/testdata/function/call/form.carbon +++ b/toolchain/check/testdata/function/call/form.carbon @@ -193,14 +193,7 @@ library "[[@TEST_NAME]]"; // CHECK:STDERR: ^~~ // CHECK:STDERR: fn F() ->? i32; -// CHECK:STDERR: fail_return_form_not_form.carbon:[[@LINE+11]]:12: error: `ref` tag is not an argument to a `ref` parameter [RefTagNoRefParam] -// CHECK:STDERR: fn F() ->? ref i32; -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: -// CHECK:STDERR: fail_return_form_not_form.carbon:[[@LINE+7]]:12: error: cannot implicitly convert expression of type `type` to `Core.Form` [ConversionFailure] -// CHECK:STDERR: fn F() ->? ref i32; -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fail_return_form_not_form.carbon:[[@LINE+4]]:12: note: type `type` does not implement interface `Core.ImplicitAs(Core.Form)` [MissingImplInMemberAccessInContext] +// CHECK:STDERR: fail_return_form_not_form.carbon:[[@LINE+4]]:12: error: `ref` tag is not an argument to a `ref` parameter [RefTagNoRefParam] // CHECK:STDERR: fn F() ->? ref i32; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: @@ -247,7 +240,7 @@ fn F(Form:! Core.Form()) ->? Form; // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F] // CHECK:STDOUT: %y.ref: ref %i32 = name_ref y, %y // CHECK:STDOUT: %.loc10: %i32 = ref_tag %y.ref -// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.ref(%.loc10) +// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.ref(%y.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/function/call/ref.carbon b/toolchain/check/testdata/function/call/ref.carbon index cf766bfbcddf..a16e5b4aa201 100644 --- a/toolchain/check/testdata/function/call/ref.carbon +++ b/toolchain/check/testdata/function/call/ref.carbon @@ -49,9 +49,9 @@ fn F(ref x: i32); fn G() { let y: i32 = 0; - // CHECK:STDERR: fail_ref_not_durable_ref.carbon:[[@LINE+7]]:9: error: expression tagged with `ref` is not a durable reference [RefTagNotDurableRef] + // CHECK:STDERR: fail_ref_not_durable_ref.carbon:[[@LINE+7]]:5: error: value expression passed to reference parameter [ValueForRefParam] // CHECK:STDERR: F(ref y); - // CHECK:STDERR: ^ + // CHECK:STDERR: ^~~~~ // CHECK:STDERR: fail_ref_not_durable_ref.carbon:[[@LINE-7]]:6: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: fn F(ref x: i32); // CHECK:STDERR: ^~~~~~~~~~ @@ -101,6 +101,16 @@ fn G() { F(ref y); } +// --- converted_ref_arg.carbon + +library "[[@TEST_NAME]]"; + +base class C {} +class D { extend base: C; } + +fn F(ref c: C); +fn G(ref d: D) { F(ref d); } + // CHECK:STDOUT: --- basics.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -171,7 +181,7 @@ fn G() { // CHECK:STDOUT: %F.ref: %F.type = name_ref F, file.%F.decl [concrete = constants.%F] // CHECK:STDOUT: %y.ref: ref %i32 = name_ref y, %y // CHECK:STDOUT: %.loc10: %i32 = ref_tag %y.ref -// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.ref(%.loc10) +// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.ref(%y.ref) // CHECK:STDOUT: %Destroy.Op.bound: = bound_method %y.var, constants.%Destroy.Op.1dc86d.2 // CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %Destroy.Op.bound(%y.var) // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/interop/cpp/function/import/reference.carbon b/toolchain/check/testdata/interop/cpp/function/import/reference.carbon index dbd26dd0a3ad..3e8588f65529 100644 --- a/toolchain/check/testdata/interop/cpp/function/import/reference.carbon +++ b/toolchain/check/testdata/interop/cpp/function/import/reference.carbon @@ -88,6 +88,22 @@ fn F() { //@dump-sem-ir-end } +// --- derived_to_base.carbon + +library "[[@TEST_NAME]]"; + +import Cpp; + +inline Cpp ''' +struct Base { Base(const Base&) = delete; }; +struct Derived : Base {}; +void f(Base &b); +'''; + +fn F(ref r: Cpp.Derived) { + Cpp.f(ref r); +} + // ============================================================================ // Rvalue reference as a parameter type // ============================================================================ @@ -430,8 +446,6 @@ fn PassRef(ref x: X) { 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 } @@ -442,6 +456,32 @@ fn PassInit() { //@dump-sem-ir-end } +// --- fail_todo_forwarding_reference_by_ref.carbon + +library "[[@TEST_NAME]]"; + +import Cpp; + +class X {} + +inline Cpp '''c++ +template void TakeAnything_ExpectConstLRef(T&&) { + static_assert(__is_same(T, const Carbon::X&)); +} +'''; + +fn PassConstRef(ref x: const X) { + // CHECK:STDERR: fail_todo_forwarding_reference_by_ref.carbon:[[@LINE+7]]:36: error: `ref` tag is not an argument to a `ref` parameter [RefTagNoRefParam] + // CHECK:STDERR: Cpp.TakeAnything_ExpectConstLRef(ref x); + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: fail_todo_forwarding_reference_by_ref.carbon:[[@LINE-9]]:59: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: template void TakeAnything_ExpectConstLRef(T&&) { + // CHECK:STDERR: ^ + // CHECK:STDERR: + Cpp.TakeAnything_ExpectConstLRef(ref x); +} + + // CHECK:STDOUT: --- call_param_lvalue_ref.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -494,7 +534,7 @@ fn PassInit() { // CHECK:STDOUT: %TakesLValue.ref: %TakesLValue.cpp_overload_set.type = name_ref TakesLValue, imports.%TakesLValue.cpp_overload_set.value [concrete = constants.%TakesLValue.cpp_overload_set.value] // CHECK:STDOUT: %s.ref: ref %S = name_ref s, %s // CHECK:STDOUT: %.loc9: %S = ref_tag %s.ref -// CHECK:STDOUT: %TakesLValue.call: init %empty_tuple.type = call imports.%TakesLValue.decl(%.loc9) +// CHECK:STDOUT: %TakesLValue.call: init %empty_tuple.type = call imports.%TakesLValue.decl(%s.ref) // 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: @@ -1311,7 +1351,7 @@ fn PassInit() { // 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: %TakeAnything_ExpectLRef.call: init %empty_tuple.type = call imports.%TakeAnything_ExpectLRef.decl(%x.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1320,14 +1360,14 @@ fn PassInit() { // 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.f7a = addr_of %.loc42_36.4 -// CHECK:STDOUT: %.loc42_37.1: %ptr.16a = as_compatible %addr -// CHECK:STDOUT: %.loc42_37.2: %ptr.16a = 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: %.loc40_36.1: ref %X = as_compatible %x.ref +// CHECK:STDOUT: %.loc40_36.2: ref %X = converted %x.ref, %.loc40_36.1 +// CHECK:STDOUT: %.loc40_36.3: %X = acquire_value %.loc40_36.2 +// CHECK:STDOUT: %.loc40_36.4: ref %X = value_as_ref %.loc40_36.3 +// CHECK:STDOUT: %addr: %ptr.f7a = addr_of %.loc40_36.4 +// CHECK:STDOUT: %.loc40_37.1: %ptr.16a = as_compatible %addr +// CHECK:STDOUT: %.loc40_37.2: %ptr.16a = converted %addr, %.loc40_37.1 +// CHECK:STDOUT: %TakeAnything_ExpectConstLRef__carbon_thunk.call: init %empty_tuple.type = call imports.%TakeAnything_ExpectConstLRef__carbon_thunk.decl(%.loc40_37.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/diagnostics/kind.def b/toolchain/diagnostics/kind.def index 7e718abbbd40..382d96037739 100644 --- a/toolchain/diagnostics/kind.def +++ b/toolchain/diagnostics/kind.def @@ -273,7 +273,6 @@ CARBON_DIAGNOSTIC_KIND(InCallToFunctionParam) CARBON_DIAGNOSTIC_KIND(MissingObjectInMethodCall) CARBON_DIAGNOSTIC_KIND(RefParamNoRefTag) CARBON_DIAGNOSTIC_KIND(RefTagNoRefParam) -CARBON_DIAGNOSTIC_KIND(RefTagNotDurableRef) CARBON_DIAGNOSTIC_KIND(SelfParameterNotAllowed) CARBON_DIAGNOSTIC_KIND(ValueForRefParam)