diff --git a/toolchain/check/cpp/import.cpp b/toolchain/check/cpp/import.cpp index 073a4b80afc2..e6d461f07969 100644 --- a/toolchain/check/cpp/import.cpp +++ b/toolchain/check/cpp/import.cpp @@ -1243,6 +1243,23 @@ static auto MapPointerType(Context& context, clang::QualType type, .type_id = pointer_type_id}; } +// Maps a C++ reference type to a Carbon type. +// We map `T&` to `T*`, and `T&&` to `T`. +// TODO: Revisit this and decide what we really want to do here. +static auto MapReferenceType(Context& context, clang::QualType type, + TypeExpr referenced_type_expr) -> TypeExpr { + CARBON_CHECK(type->isReferenceType()); + + if (!type->isLValueReferenceType()) { + return referenced_type_expr; + } + + SemIR::TypeId pointer_type_id = + GetPointerType(context, referenced_type_expr.inst_id); + return {.inst_id = context.types().GetInstId(pointer_type_id), + .type_id = pointer_type_id}; +} + // Maps a C++ type to a Carbon type. `type` should not be canonicalized because // we check for pointer nullability and nullability will be lost by // canonicalization. @@ -1256,6 +1273,8 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) type = type.getUnqualifiedType(); } else if (type->isPointerType()) { type = type->getPointeeType(); + } else if (type->isReferenceType()) { + type = type.getNonReferenceType(); } else { break; } @@ -1274,6 +1293,8 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) mapped = MapQualifiedType(context, wrapper, mapped); } else if (wrapper->isPointerType()) { mapped = MapPointerType(context, wrapper, mapped); + } else if (wrapper->isReferenceType()) { + mapped = MapReferenceType(context, wrapper, mapped); } else { CARBON_FATAL("Unexpected wrapper type {0}", wrapper.getAsString()); } @@ -1373,11 +1394,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, // TODO: The presence of qualifiers here is probably a Clang bug. clang::QualType param_type = orig_param_type.getUnqualifiedType(); - // We map `T&` parameters to `addr param: T*`, and `T&&` parameters to - // `param: T`. - // TODO: Revisit this and decide what we really want to do here. bool is_ref_param = param_type->isLValueReferenceType(); - param_type = param_type.getNonReferenceType(); // Mark the start of a region of insts, needed for the type expression // created later with the call of `EndSubpatternAsExpr()`. @@ -1395,10 +1412,6 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, return SemIR::InstBlockId::None; } - if (is_ref_param) { - type_id = GetPointerType(context, orig_type_inst_id); - } - llvm::StringRef param_name = param->getName(); SemIR::NameId name_id = param_name.empty() @@ -1425,6 +1438,8 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, .subpattern_id = pattern_id, .index = SemIR::CallParamIndex::None})}); if (is_ref_param) { + // We map `T&` parameters to `addr param: T*`. + // TODO: Revisit this and decide what we really want to do here. pattern_id = AddPatternInst( context, {param_loc_id, SemIR::AddrPattern( @@ -1446,12 +1461,7 @@ static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id, clang::FunctionDecl* clang_decl) -> TypeExpr { clang::QualType orig_ret_type = clang_decl->getReturnType(); if (!orig_ret_type->isVoidType()) { - // We map `T&` return type to `addr param: T*`, and `T&&` parameters to - // `param: T`. - // TODO: Revisit this and decide what we really want to do here. - clang::QualType ret_type = orig_ret_type.getNonReferenceType(); - - auto [orig_type_inst_id, type_id] = MapType(context, loc_id, ret_type); + auto [orig_type_inst_id, type_id] = MapType(context, loc_id, orig_ret_type); if (!orig_type_inst_id.has_value()) { context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}", orig_ret_type.getAsString())); @@ -1459,10 +1469,6 @@ static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id, .type_id = SemIR::ErrorInst::TypeId}; } - if (orig_ret_type->isLValueReferenceType()) { - type_id = GetPointerType(context, orig_type_inst_id); - } - return {orig_type_inst_id, type_id}; } diff --git a/toolchain/check/testdata/interop/cpp/class/field.carbon b/toolchain/check/testdata/interop/cpp/class/field.carbon index d5150df61661..fc29a876f667 100644 --- a/toolchain/check/testdata/interop/cpp/class/field.carbon +++ b/toolchain/check/testdata/interop/cpp/class/field.carbon @@ -16,6 +16,7 @@ struct Struct { int a; int b; int* _Nonnull p; + int& r; }; // --- use_struct_fields.carbon @@ -24,9 +25,9 @@ library "[[@TEST_NAME]]"; import Cpp library "struct.h"; -fn F(s: Cpp.Struct) -> (i32, i32, i32) { +fn F(s: Cpp.Struct) -> (i32, i32, i32, i32) { //@dump-sem-ir-begin - return (s.a, s.b, *s.p); + return (s.a, s.b, *s.p, *s.r); //@dump-sem-ir-end } @@ -160,8 +161,6 @@ struct UnsupportedMembers { volatile int is_volatile; // Nullable pointers are not supported. int *is_nullable; - // References are not supported. - int &is_reference; // But this should be fine. int integer; }; @@ -202,21 +201,11 @@ fn Test(m: Cpp.UnsupportedMembers*) { // CHECK:STDERR: ^ let a: i32 = m->is_volatile; - // CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE+8]]:17: note: in `Cpp` name lookup for `is_nullable` [InCppNameLookup] + // CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE+4]]:17: note: in `Cpp` name lookup for `is_nullable` [InCppNameLookup] // CHECK:STDERR: let b: i32 = *m->is_nullable; // CHECK:STDERR: ^~~~~~~~~~~~~~ // CHECK:STDERR: - // CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE-17]]:10: in file included here [InCppInclude] - // CHECK:STDERR: ./unsupported_members.h:8:8: error: semantics TODO: `Unsupported: field declaration has unhandled type or kind` [SemanticsTodo] - // CHECK:STDERR: int &is_reference; - // CHECK:STDERR: ^ let b: i32 = *m->is_nullable; - - // CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE+4]]:16: note: in `Cpp` name lookup for `is_reference` [InCppNameLookup] - // CHECK:STDERR: let c: i32 = m->is_reference; - // CHECK:STDERR: ^~~~~~~~~~~~~~~ - // CHECK:STDERR: - let c: i32 = m->is_reference; } // CHECK:STDOUT: --- use_struct_fields.carbon @@ -226,7 +215,7 @@ fn Test(m: Cpp.UnsupportedMembers*) { // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] // CHECK:STDOUT: %N: Core.IntLiteral = bind_symbolic_name N, 0 [symbolic] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] -// CHECK:STDOUT: %tuple.type.189: type = tuple_type (%i32, %i32, %i32) [concrete] +// CHECK:STDOUT: %tuple.type.7ea: type = tuple_type (%i32, %i32, %i32, %i32) [concrete] // CHECK:STDOUT: %Struct.elem.86b: type = unbound_element_type %Struct, %i32 [concrete] // CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete] // CHECK:STDOUT: %Struct.elem.765: type = unbound_element_type %Struct, %ptr.235 [concrete] @@ -247,7 +236,7 @@ fn Test(m: Cpp.UnsupportedMembers*) { // CHECK:STDOUT: %Copy.impl_witness_table.1ed = impl_witness_table (%Core.import_ref.d0f6), @Int.as.Copy.impl [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%s.param: %Struct) -> %return.param: %tuple.type.189 { +// CHECK:STDOUT: fn @F(%s.param: %Struct) -> %return.param: %tuple.type.7ea { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %s.ref.loc8_11: %Struct = name_ref s, %s // CHECK:STDOUT: %a.ref: %Struct.elem.86b = name_ref a, @Struct.%.1 [concrete = @Struct.%.1] @@ -262,21 +251,26 @@ fn Test(m: Cpp.UnsupportedMembers*) { // CHECK:STDOUT: %.loc8_23.1: ref %ptr.235 = class_element_access %s.ref.loc8_22, element2 // CHECK:STDOUT: %.loc8_23.2: %ptr.235 = bind_value %.loc8_23.1 // CHECK:STDOUT: %.loc8_21.1: ref %i32 = deref %.loc8_23.2 -// CHECK:STDOUT: %.loc8_25.1: %tuple.type.189 = tuple_literal (%.loc8_12.2, %.loc8_17.2, %.loc8_21.1) +// CHECK:STDOUT: %s.ref.loc8_28: %Struct = name_ref s, %s +// CHECK:STDOUT: %r.ref: %Struct.elem.765 = name_ref r, @Struct.%.4 [concrete = @Struct.%.4] +// CHECK:STDOUT: %.loc8_29.1: ref %ptr.235 = class_element_access %s.ref.loc8_28, element3 +// CHECK:STDOUT: %.loc8_29.2: %ptr.235 = bind_value %.loc8_29.1 +// CHECK:STDOUT: %.loc8_27.1: ref %i32 = deref %.loc8_29.2 +// CHECK:STDOUT: %.loc8_31.1: %tuple.type.7ea = tuple_literal (%.loc8_12.2, %.loc8_17.2, %.loc8_21.1, %.loc8_27.1) // CHECK:STDOUT: %impl.elem0.loc8_12: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59] // CHECK:STDOUT: %bound_method.loc8_12.1: = bound_method %.loc8_12.2, %impl.elem0.loc8_12 // CHECK:STDOUT: %specific_fn.loc8_12: = specific_function %impl.elem0.loc8_12, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn] // CHECK:STDOUT: %bound_method.loc8_12.2: = bound_method %.loc8_12.2, %specific_fn.loc8_12 // CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_12: init %i32 = call %bound_method.loc8_12.2(%.loc8_12.2) // CHECK:STDOUT: %tuple.elem0: ref %i32 = tuple_access %return, element0 -// CHECK:STDOUT: %.loc8_25.2: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_12 to %tuple.elem0 +// CHECK:STDOUT: %.loc8_31.2: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_12 to %tuple.elem0 // CHECK:STDOUT: %impl.elem0.loc8_17: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59] // CHECK:STDOUT: %bound_method.loc8_17.1: = bound_method %.loc8_17.2, %impl.elem0.loc8_17 // CHECK:STDOUT: %specific_fn.loc8_17: = specific_function %impl.elem0.loc8_17, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn] // CHECK:STDOUT: %bound_method.loc8_17.2: = bound_method %.loc8_17.2, %specific_fn.loc8_17 // CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_17: init %i32 = call %bound_method.loc8_17.2(%.loc8_17.2) // CHECK:STDOUT: %tuple.elem1: ref %i32 = tuple_access %return, element1 -// CHECK:STDOUT: %.loc8_25.3: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_17 to %tuple.elem1 +// CHECK:STDOUT: %.loc8_31.3: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_17 to %tuple.elem1 // CHECK:STDOUT: %.loc8_21.2: %i32 = bind_value %.loc8_21.1 // CHECK:STDOUT: %impl.elem0.loc8_21: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59] // CHECK:STDOUT: %bound_method.loc8_21.1: = bound_method %.loc8_21.2, %impl.elem0.loc8_21 @@ -284,10 +278,18 @@ fn Test(m: Cpp.UnsupportedMembers*) { // CHECK:STDOUT: %bound_method.loc8_21.2: = bound_method %.loc8_21.2, %specific_fn.loc8_21 // CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_21: init %i32 = call %bound_method.loc8_21.2(%.loc8_21.2) // CHECK:STDOUT: %tuple.elem2: ref %i32 = tuple_access %return, element2 -// CHECK:STDOUT: %.loc8_25.4: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_21 to %tuple.elem2 -// CHECK:STDOUT: %.loc8_25.5: init %tuple.type.189 = tuple_init (%.loc8_25.2, %.loc8_25.3, %.loc8_25.4) to %return -// CHECK:STDOUT: %.loc8_26: init %tuple.type.189 = converted %.loc8_25.1, %.loc8_25.5 -// CHECK:STDOUT: return %.loc8_26 to %return +// CHECK:STDOUT: %.loc8_31.4: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_21 to %tuple.elem2 +// CHECK:STDOUT: %.loc8_27.2: %i32 = bind_value %.loc8_27.1 +// CHECK:STDOUT: %impl.elem0.loc8_27: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59] +// CHECK:STDOUT: %bound_method.loc8_27.1: = bound_method %.loc8_27.2, %impl.elem0.loc8_27 +// CHECK:STDOUT: %specific_fn.loc8_27: = specific_function %impl.elem0.loc8_27, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_27.2: = bound_method %.loc8_27.2, %specific_fn.loc8_27 +// CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_27: init %i32 = call %bound_method.loc8_27.2(%.loc8_27.2) +// CHECK:STDOUT: %tuple.elem3: ref %i32 = tuple_access %return, element3 +// CHECK:STDOUT: %.loc8_31.5: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_27 to %tuple.elem3 +// CHECK:STDOUT: %.loc8_31.6: init %tuple.type.7ea = tuple_init (%.loc8_31.2, %.loc8_31.3, %.loc8_31.4, %.loc8_31.5) to %return +// CHECK:STDOUT: %.loc8_32: init %tuple.type.7ea = converted %.loc8_31.1, %.loc8_31.6 +// CHECK:STDOUT: return %.loc8_32 to %return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- use_union_fields.carbon diff --git a/toolchain/check/testdata/interop/cpp/class/method.carbon b/toolchain/check/testdata/interop/cpp/class/method.carbon index 72d710f95f77..5cf4e093fae0 100644 --- a/toolchain/check/testdata/interop/cpp/class/method.carbon +++ b/toolchain/check/testdata/interop/cpp/class/method.carbon @@ -47,42 +47,66 @@ fn F(v: Cpp.HasQualifiers, p: Cpp.HasQualifiers*) { library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./object_param_qualifiers.h:10:8: error: 'this' argument to member function 'ref_ref_this' is an lvalue, but function has rvalue ref-qualifier [CppInteropParseError] +// CHECK:STDERR: 10 | void ref_ref_this() &&; +// CHECK:STDERR: | ^ +// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./object_param_qualifiers.h:10:8: note: 'ref_ref_this' declared here [CppInteropParseNote] +// CHECK:STDERR: 10 | void ref_ref_this() &&; +// CHECK:STDERR: | ^ import Cpp library "object_param_qualifiers.h"; fn Value(v: Cpp.HasQualifiers) { - // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+5]]:3: error: `addr self` method cannot be invoked on a value [AddrSelfIsNonRef] + v.plain(); + + // TODO: This should remain invalid once we support `volatile`. + v.volatile_this(); + + v.ref_this(); + + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+12]]:3: note: in thunk for C++ function used here [InCppThunk] + // CHECK:STDERR: v.ref_ref_this(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-14]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./object_param_qualifiers.h:11:8: error: 'this' argument to member function 'const_ref_ref_this' is an lvalue, but function has rvalue ref-qualifier [CppInteropParseError] + // CHECK:STDERR: 11 | void const_ref_ref_this() const&&; + // CHECK:STDERR: | ^ + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-18]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./object_param_qualifiers.h:11:8: note: 'const_ref_ref_this' declared here [CppInteropParseNote] + // CHECK:STDERR: 11 | void const_ref_ref_this() const&&; + // CHECK:STDERR: | ^ + v.ref_ref_this(); + + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+29]]:3: note: in thunk for C++ function used here [InCppThunk] + // CHECK:STDERR: v.const_ref_ref_this(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-25]]:3: error: `addr self` method cannot be invoked on a value [AddrSelfIsNonRef] // CHECK:STDERR: v.plain(); // CHECK:STDERR: ^ // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: - v.plain(); - - // TODO: This should remain invalid once we support `volatile`. - // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:3: error: semantics TODO: `Unsupported: object parameter type: volatile struct HasQualifiers` [SemanticsTodo] + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-27]]:3: error: semantics TODO: `Unsupported: object parameter type: volatile struct HasQualifiers` [SemanticsTodo] // CHECK:STDERR: v.volatile_this(); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~ // CHECK:STDERR: - v.volatile_this(); - - // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+8]]:14: error: no matching function for call to 'ref_this' [CppInteropParseError] - // CHECK:STDERR: 29 | v.ref_this(); + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-29]]:14: error: no matching function for call to 'ref_this' [CppInteropParseError] + // CHECK:STDERR: 20 | v.ref_this(); // CHECK:STDERR: | ^ - // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-20]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-40]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./object_param_qualifiers.h:7:8: note: candidate function not viable: expects an lvalue for object argument [CppInteropParseNote] // CHECK:STDERR: 7 | void ref_this() &; // CHECK:STDERR: | ^ // CHECK:STDERR: - v.ref_this(); - - // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:3: error: semantics TODO: `Unsupported: object parameter type: struct HasQualifiers &&` [SemanticsTodo] - // CHECK:STDERR: v.ref_ref_this(); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~ - // CHECK:STDERR: - v.ref_ref_this(); - - // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:3: error: semantics TODO: `Unsupported: object parameter type: const struct HasQualifiers &&` [SemanticsTodo] + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+8]]:3: error: cannot implicitly convert expression of type `Cpp.HasQualifiers` to `const Cpp.HasQualifiers` [ConversionFailure] // CHECK:STDERR: v.const_ref_ref_this(); - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+5]]:3: note: type `Cpp.HasQualifiers` does not implement interface `Core.ImplicitAs(const Cpp.HasQualifiers)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: v.const_ref_ref_this(); + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: v.const_ref_ref_this(); } diff --git a/toolchain/check/testdata/interop/cpp/globals.carbon b/toolchain/check/testdata/interop/cpp/globals.carbon index f89bf31cd0c2..e21e11e3a9dc 100644 --- a/toolchain/check/testdata/interop/cpp/globals.carbon +++ b/toolchain/check/testdata/interop/cpp/globals.carbon @@ -19,6 +19,9 @@ class C {}; C global; +C* _Nonnull global_ptr = &global; +C& global_ref = global; + // --- import_global_scope.carbon @@ -28,6 +31,8 @@ import Cpp library "global_scope.h"; fn MyF() { let local: Cpp.C = Cpp.global; + let local_ptr: Cpp.C* = Cpp.global_ptr; + let local_ref: Cpp.C* = Cpp.global_ref; } // ============================================================================ @@ -93,7 +98,9 @@ fn MyF() { // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] -// CHECK:STDOUT: %pattern_type: type = pattern_type %C [concrete] +// CHECK:STDOUT: %pattern_type.217: type = pattern_type %C [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] +// CHECK:STDOUT: %pattern_type.a31: type = pattern_type %ptr.d9e [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -104,10 +111,14 @@ fn MyF() { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .C = %C.decl // CHECK:STDOUT: .global = %global.var +// CHECK:STDOUT: .global_ptr = %global_ptr.var +// CHECK:STDOUT: .global_ref = %global_ref.var // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} // CHECK:STDOUT: %global.var: ref %C = var %global.var_patt [concrete] +// CHECK:STDOUT: %global_ptr.var: ref %ptr.d9e = var %global_ptr.var_patt [concrete] +// CHECK:STDOUT: %global_ref.var: ref %ptr.d9e = var %global_ref.var_patt [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -135,16 +146,40 @@ fn MyF() { // CHECK:STDOUT: fn @MyF() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: name_binding_decl { -// CHECK:STDOUT: %local.patt: %pattern_type = binding_pattern local [concrete] +// CHECK:STDOUT: %local.patt: %pattern_type.217 = binding_pattern local [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: %Cpp.ref.loc7_22: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %global.ref: ref %C = name_ref global, imports.%global.var [concrete = imports.%global.var] -// CHECK:STDOUT: %.loc7_17: type = splice_block %C.ref [concrete = constants.%C] { +// CHECK:STDOUT: %.loc7_17: type = splice_block %C.ref.loc7 [concrete = constants.%C] { // CHECK:STDOUT: %Cpp.ref.loc7_14: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc7: type = name_ref C, imports.%C.decl [concrete = constants.%C] // CHECK:STDOUT: } // CHECK:STDOUT: %.loc7_25: %C = bind_value %global.ref // CHECK:STDOUT: %local: %C = bind_name local, %.loc7_25 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %local_ptr.patt: %pattern_type.a31 = binding_pattern local_ptr [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc8_27: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %global_ptr.ref: ref %ptr.d9e = name_ref global_ptr, imports.%global_ptr.var [concrete = imports.%global_ptr.var] +// CHECK:STDOUT: %.loc8_23: type = splice_block %ptr.loc8 [concrete = constants.%ptr.d9e] { +// CHECK:STDOUT: %Cpp.ref.loc8_18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %ptr.loc8: type = ptr_type %C.ref.loc8 [concrete = constants.%ptr.d9e] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_30: %ptr.d9e = bind_value %global_ptr.ref +// CHECK:STDOUT: %local_ptr: %ptr.d9e = bind_name local_ptr, %.loc8_30 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %local_ref.patt: %pattern_type.a31 = binding_pattern local_ref [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc9_27: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %global_ref.ref: ref %ptr.d9e = name_ref global_ref, imports.%global_ref.var [concrete = imports.%global_ref.var] +// CHECK:STDOUT: %.loc9_23: type = splice_block %ptr.loc9 [concrete = constants.%ptr.d9e] { +// CHECK:STDOUT: %Cpp.ref.loc9_18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc9: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %ptr.loc9: type = ptr_type %C.ref.loc9 [concrete = constants.%ptr.d9e] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc9_30: %ptr.d9e = bind_value %global_ref.ref +// CHECK:STDOUT: %local_ref: %ptr.d9e = bind_name local_ref, %.loc9_30 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: