From efbe1d24890dbfa42bf399401084a6fa1aa9c894 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 23 Sep 2026 01:19:28 +0000 Subject: [PATCH] Add `default fn`s and `final fn`s to the eval block for a generic impl (#7817) When a generic impl uses a default or final fn, it picks the specific function value out of the interface to put in the witness table. However, because this is done by modifying an existing instruction block, the generics machinery has no hook to convert the function constant into an attached constant, and because it was found in a specific for a different generic, the constant inst will be unattached. Fix this by manually mapping to an attached constant inst in the current generic when building the witness table. --- toolchain/check/impl.cpp | 6 +- .../testdata/interface/default_fn.carbon | 361 ++++++++++++++---- .../testdata/interface/default_fn.carbon | 114 ++++++ 3 files changed, 401 insertions(+), 80 deletions(-) create mode 100644 toolchain/lower/testdata/interface/default_fn.carbon diff --git a/toolchain/check/impl.cpp b/toolchain/check/impl.cpp index aceff1a2f20e..acc907fc819b 100644 --- a/toolchain/check/impl.cpp +++ b/toolchain/check/impl.cpp @@ -736,7 +736,11 @@ auto FinishImplWitness(Context& context, const SemIR::Impl& impl) -> void { } if (fn.interface_modifier != InterfaceModifier::None) { - witness_value = decl_id; + // We are updating the impl witness table in-place, and we pulled this + // instruction out of a constant value in a different generic, so + // manually ensure the new value gets added to the eval block. + witness_value = + GetOrAddInstWithSpecificConstantValue(context, decl_id); break; } else { CARBON_DIAGNOSTIC( diff --git a/toolchain/check/testdata/interface/default_fn.carbon b/toolchain/check/testdata/interface/default_fn.carbon index 887a08a5a433..2e86d5cef68e 100644 --- a/toolchain/check/testdata/interface/default_fn.carbon +++ b/toolchain/check/testdata/interface/default_fn.carbon @@ -3,8 +3,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon -// TODO: Add ranges and switch to "--dump-sem-ir-ranges=only". -// EXTRA-ARGS: --dump-sem-ir-ranges=if-present // // AUTOUPDATE // TIP: To test this file alone, run: @@ -12,23 +10,46 @@ // TIP: To dump output, run: // TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interface/default_fn.carbon +// --- parsed_in_class_scope.carbon +library "[[@TEST_NAME]]"; + class C { + //@dump-sem-ir-begin interface I { // TODO: Use `default` here. - fn F(unused self) { + default fn F(unused self) { // I and F are both complete here, and the impl below is in scope. var c: C = {}; c.(I.F)(); } } + //@dump-sem-ir-end - impl C as I { - fn F(unused self) {} - } + // The fact that `F` has a default is visible here. + //@dump-sem-ir-begin + impl C as I {} + //@dump-sem-ir-end } +// --- generic_impl.carbon +library "[[@TEST_NAME]]"; -// CHECK:STDOUT: --- default_fn.carbon +interface I { + fn F(); + //@dump-sem-ir-begin + default fn G() { Self.F(); } + //@dump-sem-ir-end +} + +//@dump-sem-ir-begin +impl forall [T: type] T as I { + fn F() {} +} +//@dump-sem-ir-end + +fn Call() { ().(I.G)(); } + +// CHECK:STDOUT: --- parsed_in_class_scope.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: type: type = facet_type [concrete] @@ -46,62 +67,41 @@ class C { // CHECK:STDOUT: %assoc0.08d: %I.assoc_type = assoc_entity element0, @I.WithSelf.%I.WithSelf.F.decl [concrete] // CHECK:STDOUT: %.c3e: = impl_self_witness %C, @I [concrete] // CHECK:STDOUT: %I.impl_witness: = impl_witness @C.as.I.impl.%I.impl_witness_table [concrete] -// CHECK:STDOUT: %pattern_type.98b: type = pattern_type %C [concrete] -// CHECK:STDOUT: %self.param_patt.303: %pattern_type.98b = value_param_pattern [concrete] -// CHECK:STDOUT: %self.patt.36a3f7.1: %pattern_type.98b = wrapper_binding_pattern self, %self.param_patt.303 [concrete] -// CHECK:STDOUT: %C.as.I.impl.F.type: type = fn_type @C.as.I.impl.F [concrete] -// CHECK:STDOUT: %C.as.I.impl.F: %C.as.I.impl.F.type = struct_value () [concrete] // CHECK:STDOUT: %I.facet: %I.type = facet_value %C, (%I.impl_witness) [concrete] // CHECK:STDOUT: %I.WithSelf.F.type.684: type = fn_type @I.WithSelf.F, @I.WithSelf(%I.facet) [concrete] // CHECK:STDOUT: %I.WithSelf.F.ee1: %I.WithSelf.F.type.684 = struct_value () [concrete] -// CHECK:STDOUT: %self.patt.36a3f7.2: %pattern_type.98b = wrapper_binding_pattern self, %self.param_patt.303 [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] // CHECK:STDOUT: %require_complete: = require_complete_type %Self.as_type.0fa [symbolic] +// CHECK:STDOUT: %pattern_type.98b: type = pattern_type %C [concrete] // CHECK:STDOUT: %c.patt: %pattern_type.98b = ref_binding_pattern c [concrete] // CHECK:STDOUT: %c.var_patt: %pattern_type.98b = var_pattern %c.patt [concrete] // CHECK:STDOUT: %empty_struct: %empty_struct_type = struct_value () [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %.938: type = fn_type_with_self_type %I.WithSelf.F.type.684, %I.facet [concrete] -// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete] -// CHECK:STDOUT: %Destroy.WithSelf.Op.type.ef016f.2: type = fn_type @Destroy.WithSelf.Op.loc20_7.2 [concrete] +// CHECK:STDOUT: %self.param_patt.303: %pattern_type.98b = value_param_pattern [concrete] +// CHECK:STDOUT: %self.patt.36a: %pattern_type.98b = wrapper_binding_pattern self, %self.param_patt.303 [concrete] +// CHECK:STDOUT: %I.WithSelf.F.specific_fn: = specific_function %I.WithSelf.F.ee1, @I.WithSelf.F(%I.facet) [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.type.ef016f.2: type = fn_type @Destroy.WithSelf.Op.loc9_7.2 [concrete] // CHECK:STDOUT: %Destroy.WithSelf.Op.403171.2: %Destroy.WithSelf.Op.type.ef016f.2 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { -// CHECK:STDOUT: .Destroy = %Core.Destroy -// CHECK:STDOUT: import Core//prelude -// CHECK:STDOUT: import Core//prelude/... -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/parts/destroy, Destroy, loaded [concrete = constants.%Destroy.type] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: file { -// CHECK:STDOUT: package: = namespace [concrete] { -// CHECK:STDOUT: .Core = imports.%Core -// CHECK:STDOUT: .C = %C.decl -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core.import = import Core -// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: interface @I { // CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = constants.%Self.4e9] // CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I [concrete] // CHECK:STDOUT: // CHECK:STDOUT: !with Self: // CHECK:STDOUT: %I.WithSelf.F.decl: @I.WithSelf.%I.WithSelf.F.type (%I.WithSelf.F.type.933) = fn_decl @I.WithSelf.F [symbolic = @I.WithSelf.%I.WithSelf.F (constants.%I.WithSelf.F.02a)] { -// CHECK:STDOUT: %self.param_patt.loc18_17.1: @I.WithSelf.F.%pattern_type (%pattern_type.492) = value_param_pattern [symbolic = %self.param_patt.loc18_17.2 (constants.%self.param_patt.55d)] -// CHECK:STDOUT: %self.patt.loc18_17.1: @I.WithSelf.F.%pattern_type (%pattern_type.492) = wrapper_binding_pattern self, %self.param_patt.loc18_17.1 [symbolic = %self.patt.loc18_17.2 (constants.%self.patt.ce2)] +// CHECK:STDOUT: %self.param_patt.loc7_25.1: @I.WithSelf.F.%pattern_type (%pattern_type.492) = value_param_pattern [symbolic = %self.param_patt.loc7_25.2 (constants.%self.param_patt.55d)] +// CHECK:STDOUT: %self.patt.loc7_25.1: @I.WithSelf.F.%pattern_type (%pattern_type.492) = wrapper_binding_pattern self, %self.param_patt.loc7_25.1 [symbolic = %self.patt.loc7_25.2 (constants.%self.patt.ce2)] // CHECK:STDOUT: } { -// CHECK:STDOUT: %self.param: @I.WithSelf.F.%Self.as_type.loc18_17.1 (%Self.as_type.0fa) = value_param call_param0 -// CHECK:STDOUT: %.loc18_17.1: type = splice_block %.loc18_17.2 [symbolic = %Self.as_type.loc18_17.1 (constants.%Self.as_type.0fa)] { +// CHECK:STDOUT: %self.param: @I.WithSelf.F.%Self.as_type.loc7_25.1 (%Self.as_type.0fa) = value_param call_param0 +// CHECK:STDOUT: %.loc7_25.1: type = splice_block %.loc7_25.2 [symbolic = %Self.as_type.loc7_25.1 (constants.%Self.as_type.0fa)] { // CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self.4e9)] -// CHECK:STDOUT: %Self.as_type.loc18_17.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc18_17.1 (constants.%Self.as_type.0fa)] -// CHECK:STDOUT: %.loc18_17.2: type = converted %Self.ref, %Self.as_type.loc18_17.2 [symbolic = %Self.as_type.loc18_17.1 (constants.%Self.as_type.0fa)] +// CHECK:STDOUT: %Self.as_type.loc7_25.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc7_25.1 (constants.%Self.as_type.0fa)] +// CHECK:STDOUT: %.loc7_25.2: type = converted %Self.ref, %Self.as_type.loc7_25.2 [symbolic = %Self.as_type.loc7_25.1 (constants.%Self.as_type.0fa)] // CHECK:STDOUT: } -// CHECK:STDOUT: %self: @I.WithSelf.F.%Self.as_type.loc18_17.1 (%Self.as_type.0fa) = wrapper_binding self, %self.param +// CHECK:STDOUT: %self: @I.WithSelf.F.%Self.as_type.loc7_25.1 (%Self.as_type.0fa) = wrapper_binding self, %self.param // CHECK:STDOUT: } // CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %I.WithSelf.F.decl [concrete = constants.%assoc0.08d] // CHECK:STDOUT: @@ -118,19 +118,11 @@ class C { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: impl @C.as.I.impl: %C.ref as %I.ref { -// CHECK:STDOUT: %C.as.I.impl.F.decl: %C.as.I.impl.F.type = fn_decl @C.as.I.impl.F [concrete = constants.%C.as.I.impl.F] { -// CHECK:STDOUT: %self.param_patt: %pattern_type.98b = value_param_pattern [concrete = constants.%self.param_patt.303] -// CHECK:STDOUT: %self.patt: %pattern_type.98b = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.36a3f7.1] -// CHECK:STDOUT: } { -// CHECK:STDOUT: %self.param: %C = value_param call_param0 -// CHECK:STDOUT: %Self.ref: type = name_ref Self, @C.as.I.impl.%C.ref [concrete = constants.%C] -// CHECK:STDOUT: %self: %C = wrapper_binding self, %self.param -// CHECK:STDOUT: } -// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (%C.as.I.impl.F.decl), @C.as.I.impl [concrete] +// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (constants.%I.WithSelf.F.ee1), @C.as.I.impl [concrete] // CHECK:STDOUT: %I.impl_witness: = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness] // CHECK:STDOUT: // CHECK:STDOUT: !members: -// CHECK:STDOUT: .F = %C.as.I.impl.F.decl +// CHECK:STDOUT: .F = // CHECK:STDOUT: extend %I.ref // CHECK:STDOUT: witness = %I.impl_witness // CHECK:STDOUT: } @@ -141,8 +133,8 @@ class C { // CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C] // CHECK:STDOUT: %I.ref: type = name_ref I, @C.%I.decl [concrete = constants.%I.type] // CHECK:STDOUT: } -// CHECK:STDOUT: %.loc25: = impl_self_witness @C.as.I.impl.%C.ref, @I [concrete = constants.%.c3e] -// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: %.loc17: = impl_self_witness @C.as.I.impl.%C.ref, @I [concrete = constants.%.c3e] +// CHECK:STDOUT: // CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: @@ -153,21 +145,21 @@ class C { // CHECK:STDOUT: // CHECK:STDOUT: generic fn @I.WithSelf.F(@I.%Self: %I.type) { // CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.4e9)] -// CHECK:STDOUT: %Self.as_type.loc18_17.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc18_17.1 (constants.%Self.as_type.0fa)] -// CHECK:STDOUT: %pattern_type: type = pattern_type %Self.as_type.loc18_17.1 [symbolic = %pattern_type (constants.%pattern_type.492)] -// CHECK:STDOUT: %self.param_patt.loc18_17.2: @I.WithSelf.F.%pattern_type (%pattern_type.492) = value_param_pattern [symbolic = %self.param_patt.loc18_17.2 (constants.%self.param_patt.55d)] -// CHECK:STDOUT: %self.patt.loc18_17.2: @I.WithSelf.F.%pattern_type (%pattern_type.492) = wrapper_binding_pattern self, %self.param_patt.loc18_17.2 [symbolic = %self.patt.loc18_17.2 (constants.%self.patt.ce2)] +// CHECK:STDOUT: %Self.as_type.loc7_25.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc7_25.1 (constants.%Self.as_type.0fa)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %Self.as_type.loc7_25.1 [symbolic = %pattern_type (constants.%pattern_type.492)] +// CHECK:STDOUT: %self.param_patt.loc7_25.2: @I.WithSelf.F.%pattern_type (%pattern_type.492) = value_param_pattern [symbolic = %self.param_patt.loc7_25.2 (constants.%self.param_patt.55d)] +// CHECK:STDOUT: %self.patt.loc7_25.2: @I.WithSelf.F.%pattern_type (%pattern_type.492) = wrapper_binding_pattern self, %self.param_patt.loc7_25.2 [symbolic = %self.patt.loc7_25.2 (constants.%self.patt.ce2)] // CHECK:STDOUT: // CHECK:STDOUT: !definition: -// CHECK:STDOUT: %require_complete: = require_complete_type %Self.as_type.loc18_17.1 [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: %require_complete: = require_complete_type %Self.as_type.loc7_25.1 [symbolic = %require_complete (constants.%require_complete)] // CHECK:STDOUT: -// CHECK:STDOUT: fn(%self.param: @I.WithSelf.F.%Self.as_type.loc18_17.1 (%Self.as_type.0fa)) { +// CHECK:STDOUT: fn(%self.param: @I.WithSelf.F.%Self.as_type.loc7_25.1 (%Self.as_type.0fa)) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %c.var: ref %C = var_storage %c.var_patt -// CHECK:STDOUT: %.loc20_19.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] -// CHECK:STDOUT: %.loc20_19.2: init %C to %c.var = class_init () [concrete = constants.%C.val] -// CHECK:STDOUT: %.loc20_7: init %C = converted %.loc20_19.1, %.loc20_19.2 [concrete = constants.%C.val] -// CHECK:STDOUT: assign %c.var, %.loc20_7 +// CHECK:STDOUT: %.loc9_19.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.loc9_19.2: init %C to %c.var = class_init () [concrete = constants.%C.val] +// CHECK:STDOUT: %.loc9_7: init %C = converted %.loc9_19.1, %.loc9_19.2 [concrete = constants.%C.val] +// CHECK:STDOUT: assign %c.var, %.loc9_7 // CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C] // CHECK:STDOUT: %c: ref %C = wrapper_binding c, %c.var // CHECK:STDOUT: name_binding_decl { @@ -177,24 +169,25 @@ class C { // CHECK:STDOUT: %c.ref: ref %C = name_ref c, %c // CHECK:STDOUT: %I.ref: type = name_ref I, @C.%I.decl [concrete = constants.%I.type] // CHECK:STDOUT: %F.ref: %I.assoc_type = name_ref F, @I.WithSelf.%assoc0 [concrete = constants.%assoc0.08d] -// CHECK:STDOUT: %impl.elem0: %.938 = impl_witness_access constants.%I.impl_witness, element0 [concrete = constants.%C.as.I.impl.F] -// CHECK:STDOUT: %bound_method: = bound_method %c.ref, %impl.elem0 -// CHECK:STDOUT: %.loc21: %C = acquire_value %c.ref -// CHECK:STDOUT: %C.as.I.impl.F.call: init %empty_tuple.type = call %bound_method(%.loc21) +// CHECK:STDOUT: %impl.elem0: %.938 = impl_witness_access constants.%I.impl_witness, element0 [concrete = constants.%I.WithSelf.F.ee1] +// CHECK:STDOUT: %bound_method.loc10_8: = bound_method %c.ref, %impl.elem0 +// CHECK:STDOUT: %I.facet.loc10_15.1: %I.type = facet_value constants.%C, (constants.%I.impl_witness) [concrete = constants.%I.facet] +// CHECK:STDOUT: %.loc10_15.1: %I.type = converted constants.%C, %I.facet.loc10_15.1 [concrete = constants.%I.facet] +// CHECK:STDOUT: %I.facet.loc10_15.2: %I.type = facet_value constants.%C, (constants.%I.impl_witness) [concrete = constants.%I.facet] +// CHECK:STDOUT: %.loc10_15.2: %I.type = converted constants.%C, %I.facet.loc10_15.2 [concrete = constants.%I.facet] +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @I.WithSelf.F(constants.%I.facet) [concrete = constants.%I.WithSelf.F.specific_fn] +// CHECK:STDOUT: %bound_method.loc10_15: = bound_method %c.ref, %specific_fn +// CHECK:STDOUT: %.loc10_7: %C = acquire_value %c.ref +// CHECK:STDOUT: %I.WithSelf.F.call: init %empty_tuple.type = call %bound_method.loc10_15(%.loc10_7) // CHECK:STDOUT: %Destroy.WithSelf.Op.bound: = bound_method %c.var, constants.%Destroy.WithSelf.Op.403171.2 // CHECK:STDOUT: %Destroy.WithSelf.Op.call: init %empty_tuple.type = call %Destroy.WithSelf.Op.bound(%c.var) // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @C.as.I.impl.F(%self.param: %C) { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: return -// CHECK:STDOUT: } +// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc9_7.1(%self.param: ref %empty_struct_type) = "no_op"; // CHECK:STDOUT: -// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc20_7.1(%self.param: ref %empty_struct_type) = "no_op"; -// CHECK:STDOUT: -// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc20_7.2(%self.param: ref %C) { +// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc9_7.2(%self.param: ref %C) { // CHECK:STDOUT: !entry: // CHECK:STDOUT: return // CHECK:STDOUT: } @@ -208,10 +201,10 @@ class C { // CHECK:STDOUT: // CHECK:STDOUT: specific @I.WithSelf.F(constants.%Self.4e9) { // CHECK:STDOUT: %Self => constants.%Self.4e9 -// CHECK:STDOUT: %Self.as_type.loc18_17.1 => constants.%Self.as_type.0fa +// CHECK:STDOUT: %Self.as_type.loc7_25.1 => constants.%Self.as_type.0fa // CHECK:STDOUT: %pattern_type => constants.%pattern_type.492 -// CHECK:STDOUT: %self.param_patt.loc18_17.2 => constants.%self.param_patt.55d -// CHECK:STDOUT: %self.patt.loc18_17.2 => constants.%self.patt.ce2 +// CHECK:STDOUT: %self.param_patt.loc7_25.2 => constants.%self.param_patt.55d +// CHECK:STDOUT: %self.patt.loc7_25.2 => constants.%self.patt.ce2 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @I.WithSelf(constants.%I.facet) { @@ -223,9 +216,219 @@ class C { // CHECK:STDOUT: // CHECK:STDOUT: specific @I.WithSelf.F(constants.%I.facet) { // CHECK:STDOUT: %Self => constants.%I.facet -// CHECK:STDOUT: %Self.as_type.loc18_17.1 => constants.%C +// CHECK:STDOUT: %Self.as_type.loc7_25.1 => constants.%C // CHECK:STDOUT: %pattern_type => constants.%pattern_type.98b -// CHECK:STDOUT: %self.param_patt.loc18_17.2 => constants.%self.param_patt.303 -// CHECK:STDOUT: %self.patt.loc18_17.2 => constants.%self.patt.36a3f7.2 +// CHECK:STDOUT: %self.param_patt.loc7_25.2 => constants.%self.param_patt.303 +// CHECK:STDOUT: %self.patt.loc7_25.2 => constants.%self.patt.36a +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- generic_impl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete] +// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %I.WithSelf.F.type.dcc: type = fn_type @I.WithSelf.F, @I.WithSelf(%Self) [symbolic] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %I.WithSelf.F.ec6: %I.WithSelf.F.type.dcc = struct_value () [symbolic] +// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @I [concrete] +// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, @I.WithSelf.%I.WithSelf.F.decl [concrete] +// CHECK:STDOUT: %I.WithSelf.G.type.d1f: type = fn_type @I.WithSelf.G, @I.WithSelf(%Self) [symbolic] +// CHECK:STDOUT: %I.WithSelf.G.44c: %I.WithSelf.G.type.d1f = struct_value () [symbolic] +// CHECK:STDOUT: %assoc1: %I.assoc_type = assoc_entity element1, @I.WithSelf.%I.WithSelf.G.decl [concrete] +// CHECK:STDOUT: %Self.as_type: type = facet_access_type %Self [symbolic] +// CHECK:STDOUT: %I.lookup_impl_witness: = lookup_impl_witness %Self, @I [symbolic] +// CHECK:STDOUT: %.6ad: type = fn_type_with_self_type %I.WithSelf.F.type.dcc, %Self [symbolic] +// CHECK:STDOUT: %impl.elem0: %.6ad = impl_witness_access %I.lookup_impl_witness, element0 [symbolic] +// CHECK:STDOUT: %specific_impl_fn: = specific_impl_function %impl.elem0, @I.WithSelf.F(%Self) [symbolic] +// CHECK:STDOUT: %.Self.frozen: type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %pattern_type: type = pattern_type type [concrete] +// CHECK:STDOUT: %T.patt: %pattern_type = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %T: type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %.917: = impl_self_witness %T, @I [symbolic] +// CHECK:STDOUT: %I.impl_witness.92f: = impl_witness @T.as.I.impl.%I.impl_witness_table, @T.as.I.impl(%T) [symbolic] +// CHECK:STDOUT: %T.as.I.impl.F.type.d46: type = fn_type @T.as.I.impl.F, @T.as.I.impl(%T) [symbolic] +// CHECK:STDOUT: %T.as.I.impl.F.ca4: %T.as.I.impl.F.type.d46 = struct_value () [symbolic] +// CHECK:STDOUT: %I.facet.1b7: %I.type = facet_value %T, (%I.impl_witness.92f) [symbolic] +// CHECK:STDOUT: %I.WithSelf.F.type.424: type = fn_type @I.WithSelf.F, @I.WithSelf(%I.facet.1b7) [symbolic] +// CHECK:STDOUT: %I.WithSelf.F.2d3: %I.WithSelf.F.type.424 = struct_value () [symbolic] +// CHECK:STDOUT: %I.WithSelf.G.type.33c: type = fn_type @I.WithSelf.G, @I.WithSelf(%I.facet.1b7) [symbolic] +// CHECK:STDOUT: %I.WithSelf.G.a95: %I.WithSelf.G.type.33c = struct_value () [symbolic] +// CHECK:STDOUT: %.2ef: = impl_self_witness %empty_tuple.type, @I [concrete] +// CHECK:STDOUT: %I.impl_witness.cf7: = impl_witness @T.as.I.impl.%I.impl_witness_table, @T.as.I.impl(%empty_tuple.type) [concrete] +// CHECK:STDOUT: %T.as.I.impl.F.type.3a0: type = fn_type @T.as.I.impl.F, @T.as.I.impl(%empty_tuple.type) [concrete] +// CHECK:STDOUT: %T.as.I.impl.F.38f: %T.as.I.impl.F.type.3a0 = struct_value () [concrete] +// CHECK:STDOUT: %I.facet.e87: %I.type = facet_value %empty_tuple.type, (%I.impl_witness.cf7) [concrete] +// CHECK:STDOUT: %I.WithSelf.G.type.0af: type = fn_type @I.WithSelf.G, @I.WithSelf(%I.facet.e87) [concrete] +// CHECK:STDOUT: %I.WithSelf.G.da9: %I.WithSelf.G.type.0af = struct_value () [concrete] +// CHECK:STDOUT: %I.WithSelf.F.type.65a: type = fn_type @I.WithSelf.F, @I.WithSelf(%I.facet.e87) [concrete] +// CHECK:STDOUT: %I.WithSelf.F.b11: %I.WithSelf.F.type.65a = struct_value () [concrete] +// CHECK:STDOUT: %.763: type = fn_type_with_self_type %I.WithSelf.F.type.65a, %I.facet.e87 [concrete] +// CHECK:STDOUT: %T.as.I.impl.F.specific_fn: = specific_function %T.as.I.impl.F.38f, @T.as.I.impl.F(%empty_tuple.type) [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: impl_decl @T.as.I.impl [concrete] { +// CHECK:STDOUT: %T.patt.loc11_15.1: %pattern_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc11_15.2 (constants.%T.patt)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %T.ref: type = name_ref T, %T.loc11_15.2 [symbolic = %T.loc11_15.1 (constants.%T)] +// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type] +// CHECK:STDOUT: %.loc11_17.1: type = splice_block %.loc11_17.2 [concrete = type] { +// CHECK:STDOUT: %.Self.frozen: type = symbolic_binding .Self [symbolic_self = constants.%.Self.frozen] +// CHECK:STDOUT: %.loc11_17.2: type = type_literal type [concrete = type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %T.loc11_15.2: type = symbolic_binding T, 0 [symbolic = %T.loc11_15.1 (constants.%T)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc11: = impl_self_witness @T.as.I.impl.%T.ref, @I [symbolic = @T.as.I.impl.%.loc11_30 (constants.%.917)] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: +// CHECK:STDOUT: +// CHECK:STDOUT: !with Self: +// CHECK:STDOUT: +// CHECK:STDOUT: %I.WithSelf.G.decl: @I.WithSelf.%I.WithSelf.G.type (%I.WithSelf.G.type.d1f) = fn_decl @I.WithSelf.G [symbolic = @I.WithSelf.%I.WithSelf.G (constants.%I.WithSelf.G.44c)] {} {} +// CHECK:STDOUT: %assoc1: %I.assoc_type = assoc_entity element1, %I.WithSelf.G.decl [concrete = constants.%assoc1] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .F = @I.WithSelf.%assoc0 +// CHECK:STDOUT: .G = @I.WithSelf.%assoc1 +// CHECK:STDOUT: witness = (@I.WithSelf.%I.WithSelf.F.decl, @I.WithSelf.%I.WithSelf.G.decl) +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic impl @T.as.I.impl(%T.loc11_15.2: type) { +// CHECK:STDOUT: %T.patt.loc11_15.2: %pattern_type = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc11_15.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.loc11_15.1: type = symbolic_binding T, 0 [symbolic = %T.loc11_15.1 (constants.%T)] +// CHECK:STDOUT: %.loc11_30: = impl_self_witness %T.loc11_15.1, @I [symbolic = %.loc11_30 (constants.%.917)] +// CHECK:STDOUT: %I.impl_witness.loc11_30.2: = impl_witness %I.impl_witness_table, @T.as.I.impl(%T.loc11_15.1) [symbolic = %I.impl_witness.loc11_30.2 (constants.%I.impl_witness.92f)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %T.as.I.impl.F.type: type = fn_type @T.as.I.impl.F, @T.as.I.impl(%T.loc11_15.1) [symbolic = %T.as.I.impl.F.type (constants.%T.as.I.impl.F.type.d46)] +// CHECK:STDOUT: %T.as.I.impl.F: @T.as.I.impl.%T.as.I.impl.F.type (%T.as.I.impl.F.type.d46) = struct_value () [symbolic = %T.as.I.impl.F (constants.%T.as.I.impl.F.ca4)] +// CHECK:STDOUT: +// CHECK:STDOUT: +// CHECK:STDOUT: impl: %T.ref as %I.ref { +// CHECK:STDOUT: %T.as.I.impl.F.decl: @T.as.I.impl.%T.as.I.impl.F.type (%T.as.I.impl.F.type.d46) = fn_decl @T.as.I.impl.F [symbolic = @T.as.I.impl.%T.as.I.impl.F (constants.%T.as.I.impl.F.ca4)] {} {} +// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (%T.as.I.impl.F.decl, %I.WithSelf.G), @T.as.I.impl [concrete] +// CHECK:STDOUT: %I.impl_witness.loc11_30.1: = impl_witness %I.impl_witness_table, @T.as.I.impl(constants.%T) [symbolic = %I.impl_witness.loc11_30.2 (constants.%I.impl_witness.92f)] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .F = %T.as.I.impl.F.decl +// CHECK:STDOUT: .G = +// CHECK:STDOUT: extend %I.ref +// CHECK:STDOUT: witness = %I.impl_witness.loc11_30.1 +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @I.WithSelf.G(@I.%Self: %I.type) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %Self.as_type.loc6_24.2: type = facet_access_type %Self [symbolic = %Self.as_type.loc6_24.2 (constants.%Self.as_type)] +// CHECK:STDOUT: %I.WithSelf.F.type: type = fn_type @I.WithSelf.F, @I.WithSelf(%Self) [symbolic = %I.WithSelf.F.type (constants.%I.WithSelf.F.type.dcc)] +// CHECK:STDOUT: %.loc6_24.2: type = fn_type_with_self_type %I.WithSelf.F.type, %Self [symbolic = %.loc6_24.2 (constants.%.6ad)] +// CHECK:STDOUT: %I.lookup_impl_witness: = lookup_impl_witness %Self, @I [symbolic = %I.lookup_impl_witness (constants.%I.lookup_impl_witness)] +// CHECK:STDOUT: %impl.elem0.loc6_24.2: @I.WithSelf.G.%.loc6_24.2 (%.6ad) = impl_witness_access %I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc6_24.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %specific_impl_fn.loc6_24.2: = specific_impl_function %impl.elem0.loc6_24.2, @I.WithSelf.F(%Self) [symbolic = %specific_impl_fn.loc6_24.2 (constants.%specific_impl_fn)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self)] +// CHECK:STDOUT: %Self.as_type.loc6_24.1: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc6_24.2 (constants.%Self.as_type)] +// CHECK:STDOUT: %.loc6_24.1: type = converted %Self.ref, %Self.as_type.loc6_24.1 [symbolic = %Self.as_type.loc6_24.2 (constants.%Self.as_type)] +// CHECK:STDOUT: %F.ref: %I.assoc_type = name_ref F, @I.WithSelf.%assoc0 [concrete = constants.%assoc0] +// CHECK:STDOUT: %impl.elem0.loc6_24.1: @I.WithSelf.G.%.loc6_24.2 (%.6ad) = impl_witness_access constants.%I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc6_24.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %specific_impl_fn.loc6_24.1: = specific_impl_function %impl.elem0.loc6_24.1, @I.WithSelf.F(constants.%Self) [symbolic = %specific_impl_fn.loc6_24.2 (constants.%specific_impl_fn)] +// CHECK:STDOUT: %I.WithSelf.F.call: init %empty_tuple.type = call %specific_impl_fn.loc6_24.1() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @T.as.I.impl.F(@T.as.I.impl.%T.loc11_15.2: type) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: +// CHECK:STDOUT: fn() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf(constants.%Self) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%Self +// CHECK:STDOUT: %I.WithSelf.F.type => constants.%I.WithSelf.F.type.dcc +// CHECK:STDOUT: %I.WithSelf.F => constants.%I.WithSelf.F.ec6 +// CHECK:STDOUT: %I.WithSelf.G.type => constants.%I.WithSelf.G.type.d1f +// CHECK:STDOUT: %I.WithSelf.G => constants.%I.WithSelf.G.44c +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf.G(constants.%Self) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @T.as.I.impl(constants.%T) { +// CHECK:STDOUT: %T.patt.loc11_15.2 => constants.%T.patt +// CHECK:STDOUT: %T.loc11_15.1 => constants.%T +// CHECK:STDOUT: %.loc11_30 => constants.%.917 +// CHECK:STDOUT: %I.impl_witness.loc11_30.2 => constants.%I.impl_witness.92f +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %T.as.I.impl.F.type => constants.%T.as.I.impl.F.type.d46 +// CHECK:STDOUT: %T.as.I.impl.F => constants.%T.as.I.impl.F.ca4 +// CHECK:STDOUT: %I.facet => constants.%I.facet.1b7 +// CHECK:STDOUT: %I.WithSelf.G.type => constants.%I.WithSelf.G.type.33c +// CHECK:STDOUT: %I.WithSelf.G => constants.%I.WithSelf.G.a95 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @T.as.I.impl.F(constants.%T) {} +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf(constants.%I.facet.1b7) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%I.facet.1b7 +// CHECK:STDOUT: %I.WithSelf.F.type => constants.%I.WithSelf.F.type.424 +// CHECK:STDOUT: %I.WithSelf.F => constants.%I.WithSelf.F.2d3 +// CHECK:STDOUT: %I.WithSelf.G.type => constants.%I.WithSelf.G.type.33c +// CHECK:STDOUT: %I.WithSelf.G => constants.%I.WithSelf.G.a95 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @T.as.I.impl(constants.%empty_tuple.type) { +// CHECK:STDOUT: %T.patt.loc11_15.2 => constants.%T.patt +// CHECK:STDOUT: %T.loc11_15.1 => constants.%empty_tuple.type +// CHECK:STDOUT: %.loc11_30 => constants.%.2ef +// CHECK:STDOUT: %I.impl_witness.loc11_30.2 => constants.%I.impl_witness.cf7 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %T.as.I.impl.F.type => constants.%T.as.I.impl.F.type.3a0 +// CHECK:STDOUT: %T.as.I.impl.F => constants.%T.as.I.impl.F.38f +// CHECK:STDOUT: %I.facet => constants.%I.facet.e87 +// CHECK:STDOUT: %I.WithSelf.G.type => constants.%I.WithSelf.G.type.0af +// CHECK:STDOUT: %I.WithSelf.G => constants.%I.WithSelf.G.da9 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf(constants.%I.facet.e87) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%I.facet.e87 +// CHECK:STDOUT: %I.WithSelf.F.type => constants.%I.WithSelf.F.type.65a +// CHECK:STDOUT: %I.WithSelf.F => constants.%I.WithSelf.F.b11 +// CHECK:STDOUT: %I.WithSelf.G.type => constants.%I.WithSelf.G.type.0af +// CHECK:STDOUT: %I.WithSelf.G => constants.%I.WithSelf.G.da9 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf.G(constants.%I.facet.e87) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%I.facet.e87 +// CHECK:STDOUT: %Self.as_type.loc6_24.2 => constants.%empty_tuple.type +// CHECK:STDOUT: %I.WithSelf.F.type => constants.%I.WithSelf.F.type.65a +// CHECK:STDOUT: %.loc6_24.2 => constants.%.763 +// CHECK:STDOUT: %I.lookup_impl_witness => constants.%I.impl_witness.cf7 +// CHECK:STDOUT: %impl.elem0.loc6_24.2 => constants.%T.as.I.impl.F.38f +// CHECK:STDOUT: %specific_impl_fn.loc6_24.2 => constants.%T.as.I.impl.F.specific_fn +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @T.as.I.impl.F(constants.%empty_tuple.type) { +// CHECK:STDOUT: !definition: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/testdata/interface/default_fn.carbon b/toolchain/lower/testdata/interface/default_fn.carbon new file mode 100644 index 000000000000..dbaca27bac53 --- /dev/null +++ b/toolchain/lower/testdata/interface/default_fn.carbon @@ -0,0 +1,114 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interface/default_fn.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interface/default_fn.carbon + +// --- use_self.carbon + +interface I { + fn G(); + default fn F() { + Self.G(); + } +} + +interface J { + fn H(); +} + +impl forall [T: J] T as I { + fn G() { T.H(); } +} + +fn Success(); + +impl () as J { + fn H() { + // Should be called by Test below. + Success(); + } +} + +fn CallF[T: I](x: T) { + x.F(); +} + +fn Test() { + CallF(()); +} + +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'use_self.carbon' +// CHECK:STDOUT: source_filename = "use_self.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_CSuccess.Main() +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @"_CH.61ea2aba74ab3bf1:J.Main"() #0 !dbg !18 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CSuccess.Main(), !dbg !19 +// CHECK:STDOUT: ret void, !dbg !20 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CTest.Main() #0 !dbg !21 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CCallF.Main.09b4c7e3e8092f9c(), !dbg !22 +// CHECK:STDOUT: ret void, !dbg !23 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define linkonce_odr void @_CCallF.Main.09b4c7e3e8092f9c() #0 !dbg !24 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CF.I.Main.09b4c7e3e8092f9c(), !dbg !26 +// CHECK:STDOUT: ret void, !dbg !27 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define linkonce_odr void @_CF.I.Main.09b4c7e3e8092f9c() #0 !dbg !28 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_CG.d90909b043297e37:I.Main.a9d0daf36987b80b"(), !dbg !29 +// CHECK:STDOUT: ret void, !dbg !30 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define linkonce_odr void @"_CG.d90909b043297e37:I.Main.a9d0daf36987b80b"() #0 !dbg !31 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_CH.61ea2aba74ab3bf1:J.Main"(), !dbg !32 +// CHECK:STDOUT: ret void, !dbg !33 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!15} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3} +// CHECK:STDOUT: +// CHECK:STDOUT: !2 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !3 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !14 = !DIFile(filename: "use_self.carbon", directory: "") +// CHECK:STDOUT: !15 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !14, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !16 = !{null} +// CHECK:STDOUT: !17 = !DISubroutineType(types: !16) +// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "H", linkageName: "_CH.61ea2aba74ab3bf1:J.Main", scope: null, file: !14, line: 20, type: !17, spFlags: DISPFlagDefinition, unit: !15) +// CHECK:STDOUT: !19 = !DILocation(line: 22, column: 5, scope: !18) +// CHECK:STDOUT: !20 = !DILocation(line: 20, column: 3, scope: !18) +// CHECK:STDOUT: !21 = distinct !DISubprogram(name: "Test", linkageName: "_CTest.Main", scope: null, file: !14, line: 30, type: !17, spFlags: DISPFlagDefinition, unit: !15) +// CHECK:STDOUT: !22 = !DILocation(line: 31, column: 3, scope: !21) +// CHECK:STDOUT: !23 = !DILocation(line: 30, column: 1, scope: !21) +// CHECK:STDOUT: !24 = distinct !DISubprogram(name: "CallF", linkageName: "_CCallF.Main.09b4c7e3e8092f9c", scope: null, file: !14, line: 26, type: !17, spFlags: DISPFlagDefinition, unit: !15) +// CHECK:STDOUT: !26 = !DILocation(line: 27, column: 3, scope: !24) +// CHECK:STDOUT: !27 = !DILocation(line: 26, column: 1, scope: !24) +// CHECK:STDOUT: !28 = distinct !DISubprogram(name: "F", linkageName: "_CF.I.Main.09b4c7e3e8092f9c", scope: null, file: !14, line: 4, type: !17, spFlags: DISPFlagDefinition, unit: !15) +// CHECK:STDOUT: !29 = !DILocation(line: 5, column: 5, scope: !28) +// CHECK:STDOUT: !30 = !DILocation(line: 4, column: 3, scope: !28) +// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "G", linkageName: "_CG.d90909b043297e37:I.Main.a9d0daf36987b80b", scope: null, file: !14, line: 14, type: !17, spFlags: DISPFlagDefinition, unit: !15) +// CHECK:STDOUT: !32 = !DILocation(line: 14, column: 12, scope: !31) +// CHECK:STDOUT: !33 = !DILocation(line: 14, column: 3, scope: !31) +// CHECK:STDOUT: