Skip to content

Commit a6acba9

Browse files
authored
Support for importing const-qualified types from C++. (#5794)
Incidentally also supports import of pointers-to-pointers. Imported const-qualified types aren't especially useful just yet, because on the Carbon side we don't yet permit conversions from non-const to const types, so most of the tests still fail, but for different reasons now.
1 parent 27be097 commit a6acba9

File tree

7 files changed

+215
-118
lines changed

7 files changed

+215
-118
lines changed

toolchain/check/import_cpp.cpp

Lines changed: 68 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -702,17 +702,11 @@ static auto MapRecordType(Context& context, SemIR::LocId loc_id,
702702
.type_id = context.types().GetTypeIdForTypeInstId(record_type_inst_id)};
703703
}
704704

705-
// Maps a C++ non-pointer type to a Carbon type.
705+
// Maps a C++ type that is not a wrapper type such as a pointer to a Carbon
706+
// type.
706707
// TODO: Support more types.
707-
static auto MapNonPointerType(Context& context, SemIR::LocId loc_id,
708+
static auto MapNonWrapperType(Context& context, SemIR::LocId loc_id,
708709
clang::QualType type) -> TypeExpr {
709-
if (type.hasQualifiers()) {
710-
// TODO: Support type qualifiers.
711-
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
712-
}
713-
714-
CARBON_CHECK(!type->isPointerType());
715-
716710
if (const auto* builtin_type = type->getAs<clang::BuiltinType>()) {
717711
return MapBuiltinType(context, *builtin_type);
718712
}
@@ -721,12 +715,40 @@ static auto MapNonPointerType(Context& context, SemIR::LocId loc_id,
721715
return MapRecordType(context, loc_id, *record_type);
722716
}
723717

718+
CARBON_CHECK(!type.hasQualifiers() && !type->isPointerType(),
719+
"Should not see wrapper types here");
720+
724721
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
725722
}
726723

724+
// Maps a qualified C++ type to a Carbon type.
725+
static auto MapQualifiedType(Context& context, SemIR::LocId loc_id,
726+
clang::QualType type, TypeExpr type_expr)
727+
-> TypeExpr {
728+
auto quals = type.getQualifiers();
729+
730+
if (quals.hasConst()) {
731+
auto type_id = GetConstType(context, type_expr.inst_id);
732+
type_expr = {.inst_id = context.types().GetInstId(type_id),
733+
.type_id = type_id};
734+
quals.removeConst();
735+
}
736+
737+
// TODO: Support other qualifiers.
738+
if (!quals.empty()) {
739+
context.TODO(loc_id, llvm::formatv("Unsupported: qualified type: {0}",
740+
type.getAsString()));
741+
return {.inst_id = SemIR::ErrorInst::TypeInstId,
742+
.type_id = SemIR::ErrorInst::TypeId};
743+
}
744+
745+
return type_expr;
746+
}
747+
727748
// Maps a C++ pointer type to a Carbon pointer type.
728749
static auto MapPointerType(Context& context, SemIR::LocId loc_id,
729-
clang::QualType type) -> TypeExpr {
750+
clang::QualType type, TypeExpr pointee_type_expr)
751+
-> TypeExpr {
730752
CARBON_CHECK(type->isPointerType());
731753

732754
if (auto nullability = type->getNullability();
@@ -738,21 +760,6 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id,
738760
.type_id = SemIR::ErrorInst::TypeId};
739761
}
740762

741-
clang::QualType pointee_type = type->getPointeeType();
742-
743-
if (pointee_type->isAnyPointerType()) {
744-
context.TODO(loc_id,
745-
llvm::formatv("Unsupported: pointer to pointer type: {0}",
746-
pointee_type.getAsString()));
747-
return {.inst_id = SemIR::ErrorInst::TypeInstId,
748-
.type_id = SemIR::ErrorInst::TypeId};
749-
}
750-
751-
TypeExpr pointee_type_expr = MapNonPointerType(context, loc_id, pointee_type);
752-
if (!pointee_type_expr.inst_id.has_value()) {
753-
return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None};
754-
}
755-
756763
SemIR::TypeId pointer_type_id =
757764
GetPointerType(context, pointee_type_expr.inst_id);
758765
return {.inst_id = context.types().GetInstId(pointer_type_id),
@@ -764,10 +771,38 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id,
764771
// canonicalization.
765772
static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
766773
-> TypeExpr {
767-
if (type->isPointerType()) {
768-
return MapPointerType(context, loc_id, type);
774+
// Unwrap any type modifiers and wrappers.
775+
llvm::SmallVector<clang::QualType> wrapper_types;
776+
while (true) {
777+
clang::QualType orig_type = type;
778+
if (type.hasQualifiers()) {
779+
type = type.getUnqualifiedType();
780+
} else if (type->isPointerType()) {
781+
type = type->getPointeeType();
782+
} else {
783+
break;
784+
}
785+
wrapper_types.push_back(orig_type);
769786
}
770-
return MapNonPointerType(context, loc_id, type);
787+
788+
auto mapped = MapNonWrapperType(context, loc_id, type);
789+
790+
for (auto wrapper : llvm::reverse(wrapper_types)) {
791+
if (!mapped.inst_id.has_value() ||
792+
mapped.type_id == SemIR::ErrorInst::TypeId) {
793+
break;
794+
}
795+
796+
if (wrapper.hasQualifiers()) {
797+
mapped = MapQualifiedType(context, loc_id, wrapper, mapped);
798+
} else if (wrapper->isPointerType()) {
799+
mapped = MapPointerType(context, loc_id, wrapper, mapped);
800+
} else {
801+
CARBON_FATAL("Unexpected wrapper type {0}", wrapper.getAsString());
802+
}
803+
}
804+
805+
return mapped;
771806
}
772807

773808
// Returns a block id for the explicit parameters of the given function
@@ -785,6 +820,11 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
785820
llvm::SmallVector<SemIR::InstId> params;
786821
params.reserve(clang_decl.parameters().size());
787822
for (const clang::ParmVarDecl* param : clang_decl.parameters()) {
823+
// TODO: Get the parameter type from the function, not from the
824+
// `ParmVarDecl`. The type of the `ParmVarDecl` is the type within the
825+
// function, and isn't in general the same as the type that's exposed to
826+
// callers. In particular, the parameter type exposed to callers will never
827+
// be cv-qualified.
788828
clang::QualType param_type = param->getType();
789829

790830
// Mark the start of a region of insts, needed for the type expression

toolchain/check/testdata/interop/cpp/function/param_int16.carbon

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,13 @@ import Cpp library "const_short.h";
203203

204204
fn F() {
205205
//@dump-sem-ir-begin
206-
// CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const short` [SemanticsTodo]
206+
// CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `i16` to `const i16` [ConversionFailure]
207207
// CHECK:STDERR: Cpp.foo(1 as i16);
208-
// CHECK:STDERR: ^~~~~~~
209-
// CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
208+
// CHECK:STDERR: ^~~~~~~~
209+
// CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+5]]:11: note: type `i16` does not implement interface `Core.ImplicitAs(const i16)` [MissingImplInMemberAccessNote]
210210
// CHECK:STDERR: Cpp.foo(1 as i16);
211-
// CHECK:STDERR: ^~~~~~~
211+
// CHECK:STDERR: ^~~~~~~~
212+
// CHECK:STDERR: fail_todo_import_const_short.carbon: note: initializing function parameter [InCallToFunctionParam]
212213
// CHECK:STDERR:
213214
Cpp.foo(1 as i16);
214215
//@dump-sem-ir-end
@@ -308,12 +309,13 @@ import Cpp library "const_short_pointer.h";
308309
fn F() {
309310
var a: i16 = 1;
310311
//@dump-sem-ir-begin
311-
// CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const short * _Nonnull` [SemanticsTodo]
312+
// CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `i16*` to `const i16*` [ConversionFailure]
312313
// CHECK:STDERR: Cpp.foo(&a);
313-
// CHECK:STDERR: ^~~~~~~
314-
// CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
314+
// CHECK:STDERR: ^~
315+
// CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+5]]:11: note: type `i16*` does not implement interface `Core.ImplicitAs(const i16*)` [MissingImplInMemberAccessNote]
315316
// CHECK:STDERR: Cpp.foo(&a);
316-
// CHECK:STDERR: ^~~~~~~
317+
// CHECK:STDERR: ^~
318+
// CHECK:STDERR: fail_todo_import_const_short_pointer.carbon: note: initializing function parameter [InCallToFunctionParam]
317319
// CHECK:STDERR:
318320
Cpp.foo(&a);
319321
//@dump-sem-ir-end
@@ -734,9 +736,13 @@ fn F() {
734736
// CHECK:STDOUT: --- fail_todo_import_const_short.carbon
735737
// CHECK:STDOUT:
736738
// CHECK:STDOUT: constants {
737-
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
739+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
738740
// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete]
739741
// CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete]
742+
// CHECK:STDOUT: %const: type = const_type %i16 [concrete]
743+
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
744+
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
745+
// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete]
740746
// CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete]
741747
// CHECK:STDOUT: %Convert.type.be5: type = fn_type @Convert.1, @As(%i16) [concrete]
742748
// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic]
@@ -755,27 +761,34 @@ fn F() {
755761
// CHECK:STDOUT:
756762
// CHECK:STDOUT: imports {
757763
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
758-
// CHECK:STDOUT: .foo = <error>
764+
// CHECK:STDOUT: .foo = %foo.decl
759765
// CHECK:STDOUT: import Cpp//...
760766
// CHECK:STDOUT: }
767+
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
768+
// CHECK:STDOUT: <elided>
769+
// CHECK:STDOUT: } {
770+
// CHECK:STDOUT: <elided>
771+
// CHECK:STDOUT: }
761772
// CHECK:STDOUT: %Core.import_ref.78a: @As.impl.686.%Convert.type (%Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @As.impl.686.%Convert (constants.%Convert.527)]
762773
// CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @As.impl.686 [concrete]
763774
// CHECK:STDOUT: }
764775
// CHECK:STDOUT:
765776
// CHECK:STDOUT: fn @F() {
766777
// CHECK:STDOUT: !entry:
767778
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
768-
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
779+
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
769780
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8]
770781
// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16]
771782
// CHECK:STDOUT: %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16]
772783
// CHECK:STDOUT: %impl.elem0: %.91d = impl_witness_access constants.%As.impl_witness.0ef, element0 [concrete = constants.%Convert.489]
773-
// CHECK:STDOUT: %bound_method.loc15_13.1: <bound method> = bound_method %int_1, %impl.elem0 [concrete = constants.%Convert.bound]
784+
// CHECK:STDOUT: %bound_method.loc16_13.1: <bound method> = bound_method %int_1, %impl.elem0 [concrete = constants.%Convert.bound]
774785
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Convert.5(constants.%int_16) [concrete = constants.%Convert.specific_fn]
775-
// CHECK:STDOUT: %bound_method.loc15_13.2: <bound method> = bound_method %int_1, %specific_fn [concrete = constants.%bound_method]
776-
// CHECK:STDOUT: %int.convert_checked: init %i16 = call %bound_method.loc15_13.2(%int_1) [concrete = constants.%int_1.f90]
777-
// CHECK:STDOUT: %.loc15_13.1: %i16 = value_of_initializer %int.convert_checked [concrete = constants.%int_1.f90]
778-
// CHECK:STDOUT: %.loc15_13.2: %i16 = converted %int_1, %.loc15_13.1 [concrete = constants.%int_1.f90]
786+
// CHECK:STDOUT: %bound_method.loc16_13.2: <bound method> = bound_method %int_1, %specific_fn [concrete = constants.%bound_method]
787+
// CHECK:STDOUT: %int.convert_checked: init %i16 = call %bound_method.loc16_13.2(%int_1) [concrete = constants.%int_1.f90]
788+
// CHECK:STDOUT: %.loc16_13.1: %i16 = value_of_initializer %int.convert_checked [concrete = constants.%int_1.f90]
789+
// CHECK:STDOUT: %.loc16_13.2: %i16 = converted %int_1, %.loc16_13.1 [concrete = constants.%int_1.f90]
790+
// CHECK:STDOUT: %.loc16_13.3: %const = converted %.loc16_13.2, <error> [concrete = <error>]
791+
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(<error>)
779792
// CHECK:STDOUT: <elided>
780793
// CHECK:STDOUT: }
781794
// CHECK:STDOUT:
@@ -862,25 +875,37 @@ fn F() {
862875
// CHECK:STDOUT: --- fail_todo_import_const_short_pointer.carbon
863876
// CHECK:STDOUT:
864877
// CHECK:STDOUT: constants {
878+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
865879
// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete]
866880
// CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete]
881+
// CHECK:STDOUT: %const: type = const_type %i16 [concrete]
882+
// CHECK:STDOUT: %ptr.758: type = ptr_type %const [concrete]
883+
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
884+
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
867885
// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [concrete]
868886
// CHECK:STDOUT: }
869887
// CHECK:STDOUT:
870888
// CHECK:STDOUT: imports {
871889
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
872-
// CHECK:STDOUT: .foo = <error>
890+
// CHECK:STDOUT: .foo = %foo.decl
873891
// CHECK:STDOUT: import Cpp//...
874892
// CHECK:STDOUT: }
893+
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
894+
// CHECK:STDOUT: <elided>
895+
// CHECK:STDOUT: } {
896+
// CHECK:STDOUT: <elided>
897+
// CHECK:STDOUT: }
875898
// CHECK:STDOUT: }
876899
// CHECK:STDOUT:
877900
// CHECK:STDOUT: fn @F() {
878901
// CHECK:STDOUT: !entry:
879902
// CHECK:STDOUT: <elided>
880903
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
881-
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
904+
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
882905
// CHECK:STDOUT: %a.ref: ref %i16 = name_ref a, %a
883-
// CHECK:STDOUT: %addr.loc16: %ptr.251 = addr_of %a.ref
906+
// CHECK:STDOUT: %addr.loc17: %ptr.251 = addr_of %a.ref
907+
// CHECK:STDOUT: %.loc17: %ptr.758 = converted %addr.loc17, <error> [concrete = <error>]
908+
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(<error>)
884909
// CHECK:STDOUT: <elided>
885910
// CHECK:STDOUT: }
886911
// CHECK:STDOUT:

toolchain/check/testdata/interop/cpp/function/param_int32.carbon

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,13 @@ import Cpp library "const_int.h";
263263

264264
fn F() {
265265
//@dump-sem-ir-begin
266-
// CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const int` [SemanticsTodo]
266+
// CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `Core.IntLiteral` to `const i32` [ConversionFailure]
267267
// CHECK:STDERR: Cpp.foo(1);
268-
// CHECK:STDERR: ^~~~~~~
269-
// CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
268+
// CHECK:STDERR: ^
269+
// CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+5]]:11: note: type `Core.IntLiteral` does not implement interface `Core.ImplicitAs(const i32)` [MissingImplInMemberAccessNote]
270270
// CHECK:STDERR: Cpp.foo(1);
271-
// CHECK:STDERR: ^~~~~~~
271+
// CHECK:STDERR: ^
272+
// CHECK:STDERR: fail_todo_import_const_int.carbon: note: initializing function parameter [InCallToFunctionParam]
272273
// CHECK:STDERR:
273274
Cpp.foo(1);
274275
//@dump-sem-ir-end
@@ -368,12 +369,13 @@ import Cpp library "const_int_pointer.h";
368369
fn F() {
369370
var a : i32 = 1;
370371
//@dump-sem-ir-begin
371-
// CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const int * _Nonnull` [SemanticsTodo]
372+
// CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `i32*` to `const i32*` [ConversionFailure]
372373
// CHECK:STDERR: Cpp.foo(&a);
373-
// CHECK:STDERR: ^~~~~~~
374-
// CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
374+
// CHECK:STDERR: ^~
375+
// CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+5]]:11: note: type `i32*` does not implement interface `Core.ImplicitAs(const i32*)` [MissingImplInMemberAccessNote]
375376
// CHECK:STDERR: Cpp.foo(&a);
376-
// CHECK:STDERR: ^~~~~~~
377+
// CHECK:STDERR: ^~
378+
// CHECK:STDERR: fail_todo_import_const_int_pointer.carbon: note: initializing function parameter [InCallToFunctionParam]
377379
// CHECK:STDERR:
378380
Cpp.foo(&a);
379381
//@dump-sem-ir-end
@@ -979,21 +981,34 @@ fn F() {
979981
// CHECK:STDOUT: --- fail_todo_import_const_int.carbon
980982
// CHECK:STDOUT:
981983
// CHECK:STDOUT: constants {
984+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
985+
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
986+
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
987+
// CHECK:STDOUT: %const: type = const_type %i32 [concrete]
988+
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
989+
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
982990
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete]
983991
// CHECK:STDOUT: }
984992
// CHECK:STDOUT:
985993
// CHECK:STDOUT: imports {
986994
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
987-
// CHECK:STDOUT: .foo = <error>
995+
// CHECK:STDOUT: .foo = %foo.decl
988996
// CHECK:STDOUT: import Cpp//...
989997
// CHECK:STDOUT: }
998+
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
999+
// CHECK:STDOUT: <elided>
1000+
// CHECK:STDOUT: } {
1001+
// CHECK:STDOUT: <elided>
1002+
// CHECK:STDOUT: }
9901003
// CHECK:STDOUT: }
9911004
// CHECK:STDOUT:
9921005
// CHECK:STDOUT: fn @F() {
9931006
// CHECK:STDOUT: !entry:
9941007
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
995-
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
1008+
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
9961009
// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1]
1010+
// CHECK:STDOUT: %.loc16: %const = converted %int_1, <error> [concrete = <error>]
1011+
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(<error>)
9971012
// CHECK:STDOUT: <elided>
9981013
// CHECK:STDOUT: }
9991014
// CHECK:STDOUT:
@@ -1082,23 +1097,34 @@ fn F() {
10821097
// CHECK:STDOUT: constants {
10831098
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
10841099
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
1100+
// CHECK:STDOUT: %const: type = const_type %i32 [concrete]
1101+
// CHECK:STDOUT: %ptr.36b: type = ptr_type %const [concrete]
1102+
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
1103+
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
10851104
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
10861105
// CHECK:STDOUT: }
10871106
// CHECK:STDOUT:
10881107
// CHECK:STDOUT: imports {
10891108
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
1090-
// CHECK:STDOUT: .foo = <error>
1109+
// CHECK:STDOUT: .foo = %foo.decl
10911110
// CHECK:STDOUT: import Cpp//...
10921111
// CHECK:STDOUT: }
1112+
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
1113+
// CHECK:STDOUT: <elided>
1114+
// CHECK:STDOUT: } {
1115+
// CHECK:STDOUT: <elided>
1116+
// CHECK:STDOUT: }
10931117
// CHECK:STDOUT: }
10941118
// CHECK:STDOUT:
10951119
// CHECK:STDOUT: fn @F() {
10961120
// CHECK:STDOUT: !entry:
10971121
// CHECK:STDOUT: <elided>
10981122
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
1099-
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
1123+
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
11001124
// CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a
1101-
// CHECK:STDOUT: %addr.loc16: %ptr.235 = addr_of %a.ref
1125+
// CHECK:STDOUT: %addr.loc17: %ptr.235 = addr_of %a.ref
1126+
// CHECK:STDOUT: %.loc17: %ptr.36b = converted %addr.loc17, <error> [concrete = <error>]
1127+
// CHECK:STDOUT: %foo.call: init %i32 = call %foo.ref(<error>)
11021128
// CHECK:STDOUT: <elided>
11031129
// CHECK:STDOUT: }
11041130
// CHECK:STDOUT:

0 commit comments

Comments
 (0)