diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index fcbf942429eb..918f2b16a873 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -702,17 +702,11 @@ static auto MapRecordType(Context& context, SemIR::LocId loc_id, .type_id = context.types().GetTypeIdForTypeInstId(record_type_inst_id)}; } -// Maps a C++ non-pointer type to a Carbon type. +// Maps a C++ type that is not a wrapper type such as a pointer to a Carbon +// type. // TODO: Support more types. -static auto MapNonPointerType(Context& context, SemIR::LocId loc_id, +static auto MapNonWrapperType(Context& context, SemIR::LocId loc_id, clang::QualType type) -> TypeExpr { - if (type.hasQualifiers()) { - // TODO: Support type qualifiers. - return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None}; - } - - CARBON_CHECK(!type->isPointerType()); - if (const auto* builtin_type = type->getAs()) { return MapBuiltinType(context, *builtin_type); } @@ -721,12 +715,40 @@ static auto MapNonPointerType(Context& context, SemIR::LocId loc_id, return MapRecordType(context, loc_id, *record_type); } + CARBON_CHECK(!type.hasQualifiers() && !type->isPointerType(), + "Should not see wrapper types here"); + return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None}; } +// Maps a qualified C++ type to a Carbon type. +static auto MapQualifiedType(Context& context, SemIR::LocId loc_id, + clang::QualType type, TypeExpr type_expr) + -> TypeExpr { + auto quals = type.getQualifiers(); + + if (quals.hasConst()) { + auto type_id = GetConstType(context, type_expr.inst_id); + type_expr = {.inst_id = context.types().GetInstId(type_id), + .type_id = type_id}; + quals.removeConst(); + } + + // TODO: Support other qualifiers. + if (!quals.empty()) { + context.TODO(loc_id, llvm::formatv("Unsupported: qualified type: {0}", + type.getAsString())); + return {.inst_id = SemIR::ErrorInst::TypeInstId, + .type_id = SemIR::ErrorInst::TypeId}; + } + + return type_expr; +} + // Maps a C++ pointer type to a Carbon pointer type. static auto MapPointerType(Context& context, SemIR::LocId loc_id, - clang::QualType type) -> TypeExpr { + clang::QualType type, TypeExpr pointee_type_expr) + -> TypeExpr { CARBON_CHECK(type->isPointerType()); if (auto nullability = type->getNullability(); @@ -738,21 +760,6 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id, .type_id = SemIR::ErrorInst::TypeId}; } - clang::QualType pointee_type = type->getPointeeType(); - - if (pointee_type->isAnyPointerType()) { - context.TODO(loc_id, - llvm::formatv("Unsupported: pointer to pointer type: {0}", - pointee_type.getAsString())); - return {.inst_id = SemIR::ErrorInst::TypeInstId, - .type_id = SemIR::ErrorInst::TypeId}; - } - - TypeExpr pointee_type_expr = MapNonPointerType(context, loc_id, pointee_type); - if (!pointee_type_expr.inst_id.has_value()) { - return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None}; - } - SemIR::TypeId pointer_type_id = GetPointerType(context, pointee_type_expr.inst_id); return {.inst_id = context.types().GetInstId(pointer_type_id), @@ -764,10 +771,38 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id, // canonicalization. static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) -> TypeExpr { - if (type->isPointerType()) { - return MapPointerType(context, loc_id, type); + // Unwrap any type modifiers and wrappers. + llvm::SmallVector wrapper_types; + while (true) { + clang::QualType orig_type = type; + if (type.hasQualifiers()) { + type = type.getUnqualifiedType(); + } else if (type->isPointerType()) { + type = type->getPointeeType(); + } else { + break; + } + wrapper_types.push_back(orig_type); } - return MapNonPointerType(context, loc_id, type); + + auto mapped = MapNonWrapperType(context, loc_id, type); + + for (auto wrapper : llvm::reverse(wrapper_types)) { + if (!mapped.inst_id.has_value() || + mapped.type_id == SemIR::ErrorInst::TypeId) { + break; + } + + if (wrapper.hasQualifiers()) { + mapped = MapQualifiedType(context, loc_id, wrapper, mapped); + } else if (wrapper->isPointerType()) { + mapped = MapPointerType(context, loc_id, wrapper, mapped); + } else { + CARBON_FATAL("Unexpected wrapper type {0}", wrapper.getAsString()); + } + } + + return mapped; } // 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, llvm::SmallVector params; params.reserve(clang_decl.parameters().size()); for (const clang::ParmVarDecl* param : clang_decl.parameters()) { + // TODO: Get the parameter type from the function, not from the + // `ParmVarDecl`. The type of the `ParmVarDecl` is the type within the + // function, and isn't in general the same as the type that's exposed to + // callers. In particular, the parameter type exposed to callers will never + // be cv-qualified. clang::QualType param_type = param->getType(); // Mark the start of a region of insts, needed for the type expression diff --git a/toolchain/check/testdata/interop/cpp/function/param_int16.carbon b/toolchain/check/testdata/interop/cpp/function/param_int16.carbon index db89ae314e6f..b407fdf8cee1 100644 --- a/toolchain/check/testdata/interop/cpp/function/param_int16.carbon +++ b/toolchain/check/testdata/interop/cpp/function/param_int16.carbon @@ -203,12 +203,13 @@ import Cpp library "const_short.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const short` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `i16` to `const i16` [ConversionFailure] // CHECK:STDERR: Cpp.foo(1 as i16); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_todo_import_const_short.carbon:[[@LINE+5]]:11: note: type `i16` does not implement interface `Core.ImplicitAs(const i16)` [MissingImplInMemberAccessNote] // CHECK:STDERR: Cpp.foo(1 as i16); - // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_todo_import_const_short.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo(1 as i16); //@dump-sem-ir-end @@ -308,12 +309,13 @@ import Cpp library "const_short_pointer.h"; fn F() { var a: i16 = 1; //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const short * _Nonnull` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `i16*` to `const i16*` [ConversionFailure] // CHECK:STDERR: Cpp.foo(&a); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_const_short_pointer.carbon:[[@LINE+5]]:11: note: type `i16*` does not implement interface `Core.ImplicitAs(const i16*)` [MissingImplInMemberAccessNote] // CHECK:STDERR: Cpp.foo(&a); - // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_const_short_pointer.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo(&a); //@dump-sem-ir-end @@ -734,9 +736,13 @@ fn F() { // CHECK:STDOUT: --- fail_todo_import_const_short.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { -// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete] // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] +// CHECK:STDOUT: %const: type = const_type %i16 [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %Convert.type.be5: type = fn_type @Convert.1, @As(%i16) [concrete] // CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] @@ -755,9 +761,14 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // 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)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @As.impl.686 [concrete] // CHECK:STDOUT: } @@ -765,17 +776,19 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] // CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16] // CHECK:STDOUT: %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16] // CHECK:STDOUT: %impl.elem0: %.91d = impl_witness_access constants.%As.impl_witness.0ef, element0 [concrete = constants.%Convert.489] -// CHECK:STDOUT: %bound_method.loc15_13.1: = bound_method %int_1, %impl.elem0 [concrete = constants.%Convert.bound] +// CHECK:STDOUT: %bound_method.loc16_13.1: = bound_method %int_1, %impl.elem0 [concrete = constants.%Convert.bound] // CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Convert.5(constants.%int_16) [concrete = constants.%Convert.specific_fn] -// CHECK:STDOUT: %bound_method.loc15_13.2: = bound_method %int_1, %specific_fn [concrete = constants.%bound_method] -// CHECK:STDOUT: %int.convert_checked: init %i16 = call %bound_method.loc15_13.2(%int_1) [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %.loc15_13.1: %i16 = value_of_initializer %int.convert_checked [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %.loc15_13.2: %i16 = converted %int_1, %.loc15_13.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %bound_method.loc16_13.2: = bound_method %int_1, %specific_fn [concrete = constants.%bound_method] +// CHECK:STDOUT: %int.convert_checked: init %i16 = call %bound_method.loc16_13.2(%int_1) [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %.loc16_13.1: %i16 = value_of_initializer %int.convert_checked [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %.loc16_13.2: %i16 = converted %int_1, %.loc16_13.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %.loc16_13.3: %const = converted %.loc16_13.2, [concrete = ] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -862,25 +875,37 @@ fn F() { // CHECK:STDOUT: --- fail_todo_import_const_short_pointer.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete] // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] +// CHECK:STDOUT: %const: type = const_type %i16 [concrete] +// CHECK:STDOUT: %ptr.758: type = ptr_type %const [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %a.ref: ref %i16 = name_ref a, %a -// CHECK:STDOUT: %addr.loc16: %ptr.251 = addr_of %a.ref +// CHECK:STDOUT: %addr.loc17: %ptr.251 = addr_of %a.ref +// CHECK:STDOUT: %.loc17: %ptr.758 = converted %addr.loc17, [concrete = ] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/param_int32.carbon b/toolchain/check/testdata/interop/cpp/function/param_int32.carbon index 71e499c6b5c5..b14aa1ae6b02 100644 --- a/toolchain/check/testdata/interop/cpp/function/param_int32.carbon +++ b/toolchain/check/testdata/interop/cpp/function/param_int32.carbon @@ -263,12 +263,13 @@ import Cpp library "const_int.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const int` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `Core.IntLiteral` to `const i32` [ConversionFailure] // CHECK:STDERR: Cpp.foo(1); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_todo_import_const_int.carbon:[[@LINE+5]]:11: note: type `Core.IntLiteral` does not implement interface `Core.ImplicitAs(const i32)` [MissingImplInMemberAccessNote] // CHECK:STDERR: Cpp.foo(1); - // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_todo_import_const_int.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo(1); //@dump-sem-ir-end @@ -368,12 +369,13 @@ import Cpp library "const_int_pointer.h"; fn F() { var a : i32 = 1; //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const int * _Nonnull` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+8]]:11: error: cannot implicitly convert expression of type `i32*` to `const i32*` [ConversionFailure] // CHECK:STDERR: Cpp.foo(&a); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_const_int_pointer.carbon:[[@LINE+5]]:11: note: type `i32*` does not implement interface `Core.ImplicitAs(const i32*)` [MissingImplInMemberAccessNote] // CHECK:STDERR: Cpp.foo(&a); - // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_const_int_pointer.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo(&a); //@dump-sem-ir-end @@ -979,21 +981,34 @@ fn F() { // CHECK:STDOUT: --- fail_todo_import_const_int.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %const: type = const_type %i32 [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1] +// CHECK:STDOUT: %.loc16: %const = converted %int_1, [concrete = ] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1082,23 +1097,34 @@ fn F() { // CHECK:STDOUT: constants { // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %const: type = const_type %i32 [concrete] +// CHECK:STDOUT: %ptr.36b: type = ptr_type %const [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %a.ref: ref %i32 = name_ref a, %a -// CHECK:STDOUT: %addr.loc16: %ptr.235 = addr_of %a.ref +// CHECK:STDOUT: %addr.loc17: %ptr.235 = addr_of %a.ref +// CHECK:STDOUT: %.loc17: %ptr.36b = converted %addr.loc17, [concrete = ] +// CHECK:STDOUT: %foo.call: init %i32 = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/pointer.carbon b/toolchain/check/testdata/interop/cpp/function/pointer.carbon index 1c60bc9b63d8..9125fc8a693f 100644 --- a/toolchain/check/testdata/interop/cpp/function/pointer.carbon +++ b/toolchain/check/testdata/interop/cpp/function/pointer.carbon @@ -43,7 +43,7 @@ struct S {}; auto foo(S* _Nonnull * _Nonnull) -> void; -// --- fail_todo_import_double_pointer_param.carbon +// --- import_double_pointer_param.carbon library "[[@TEST_NAME]]"; @@ -53,13 +53,6 @@ fn F() { //@dump-sem-ir-begin var s: Cpp.S = {}; var p: Cpp.S* = &s; - // CHECK:STDERR: fail_todo_import_double_pointer_param.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: pointer to pointer type: S * _Nonnull` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo(&p); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_double_pointer_param.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo(&p); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo(&p); //@dump-sem-ir-end } @@ -74,7 +67,7 @@ struct S {}; auto foo(const S* _Nonnull) -> void; -// --- fail_todo_import_const_pointer_param.carbon +// --- import_const_pointer_param.carbon library "[[@TEST_NAME]]"; @@ -85,13 +78,6 @@ fn G() -> const Cpp.S; fn F() { //@dump-sem-ir-begin var s: const Cpp.S = G(); - // CHECK:STDERR: fail_todo_import_const_pointer_param.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: const S * _Nonnull` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo(&s); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_const_pointer_param.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo(&s); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo(&s); //@dump-sem-ir-end } @@ -131,7 +117,7 @@ struct S {}; auto foo() -> S* _Nonnull * _Nonnull; -// --- fail_todo_import_double_pointer_return.carbon +// --- import_double_pointer_return.carbon library "[[@TEST_NAME]]"; @@ -141,13 +127,6 @@ fn IngestDoublePointer(s: Cpp.S**); fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_double_pointer_return.carbon:[[@LINE+7]]:23: error: semantics TODO: `Unsupported: pointer to pointer type: S * _Nonnull` [SemanticsTodo] - // CHECK:STDERR: IngestDoublePointer(Cpp.foo()); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_double_pointer_return.carbon:[[@LINE+4]]:23: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: IngestDoublePointer(Cpp.foo()); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: IngestDoublePointer(Cpp.foo()); Cpp.foo(); //@dump-sem-ir-end @@ -163,7 +142,7 @@ struct S {}; auto foo() -> const S* _Nonnull; -// --- fail_todo_import_const_pointer_return.carbon +// --- import_const_pointer_return.carbon library "[[@TEST_NAME]]"; @@ -173,13 +152,6 @@ fn IngestConstPointer(s: const Cpp.S*); fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_const_pointer_return.carbon:[[@LINE+7]]:22: error: semantics TODO: `Unsupported: return type: const S * _Nonnull` [SemanticsTodo] - // CHECK:STDERR: IngestConstPointer(Cpp.foo()); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_const_pointer_return.carbon:[[@LINE+4]]:22: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: IngestConstPointer(Cpp.foo()); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: IngestConstPointer(Cpp.foo()); Cpp.foo(); //@dump-sem-ir-end @@ -274,7 +246,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_double_pointer_param.carbon +// CHECK:STDOUT: --- import_double_pointer_param.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] @@ -284,9 +256,9 @@ fn F() { // CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete] // CHECK:STDOUT: %pattern_type.259: type = pattern_type %ptr.5c7 [concrete] +// CHECK:STDOUT: %ptr.dfe: type = ptr_type %ptr.5c7 [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] -// CHECK:STDOUT: %ptr.dfe: type = ptr_type %ptr.5c7 [concrete] // CHECK:STDOUT: %Op.type.c07: type = fn_type @Op.2, @Destroy.impl(%ptr.5c7) [concrete] // CHECK:STDOUT: %Op.64b: %Op.type.c07 = struct_value () [concrete] // CHECK:STDOUT: %Op.type.642: type = fn_type @Op.2, @Destroy.impl(%S) [concrete] @@ -338,11 +310,11 @@ fn F() { // CHECK:STDOUT: %ptr: type = ptr_type %S.ref.loc9 [concrete = constants.%ptr.5c7] // CHECK:STDOUT: } // CHECK:STDOUT: %p: ref %ptr.5c7 = bind_name p, %p.var -// CHECK:STDOUT: %Cpp.ref.loc17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %p.ref: ref %ptr.5c7 = name_ref p, %p -// CHECK:STDOUT: %addr.loc17: %ptr.dfe = addr_of %p.ref -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %addr.loc10: %ptr.dfe = addr_of %p.ref +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%addr.loc10) // CHECK:STDOUT: %Op.bound.loc9: = bound_method %p.var, constants.%Op.64b // CHECK:STDOUT: // CHECK:STDOUT: %bound_method.loc9: = bound_method %p.var, %Op.specific_fn.1 @@ -356,7 +328,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_const_pointer_param.carbon +// CHECK:STDOUT: --- import_const_pointer_param.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %S: type = class_type @S [concrete] @@ -366,6 +338,8 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %G: %G.type = struct_value () [concrete] // CHECK:STDOUT: %ptr.ff5: type = ptr_type %const [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %Op.type.372: type = fn_type @Op.2, @Destroy.impl(%const) [concrete] // CHECK:STDOUT: %Op.af7: %Op.type.372 = struct_value () [concrete] // CHECK:STDOUT: } @@ -373,10 +347,15 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .S = %S.decl -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { @@ -396,10 +375,11 @@ fn F() { // CHECK:STDOUT: %const: type = const_type %S.ref [concrete = constants.%const] // CHECK:STDOUT: } // CHECK:STDOUT: %s: ref %const = bind_name s, %s.var -// CHECK:STDOUT: %Cpp.ref.loc18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %Cpp.ref.loc11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %s.ref: ref %const = name_ref s, %s -// CHECK:STDOUT: %addr.loc18: %ptr.ff5 = addr_of %s.ref +// CHECK:STDOUT: %addr.loc11: %ptr.ff5 = addr_of %s.ref +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%addr.loc11) // CHECK:STDOUT: %Op.bound.loc10_3.1: = bound_method %.loc10_3, constants.%Op.af7 // CHECK:STDOUT: // CHECK:STDOUT: %bound_method.loc10_3.1: = bound_method %.loc10_3, %Op.specific_fn.1 @@ -454,10 +434,12 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_double_pointer_return.carbon +// CHECK:STDOUT: --- import_double_pointer_return.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete] +// CHECK:STDOUT: %ptr.dfe: type = ptr_type %ptr.5c7 [concrete] // CHECK:STDOUT: %IngestDoublePointer.type: type = fn_type @IngestDoublePointer [concrete] // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %IngestDoublePointer: %IngestDoublePointer.type = struct_value () [concrete] @@ -482,42 +464,57 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %IngestDoublePointer.ref: %IngestDoublePointer.type = name_ref IngestDoublePointer, file.%IngestDoublePointer.decl [concrete = constants.%IngestDoublePointer] -// CHECK:STDOUT: %Cpp.ref.loc17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref.loc17: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %foo.call.loc17: init = call %foo.ref.loc17() -// CHECK:STDOUT: %IngestDoublePointer.call: init %empty_tuple.type = call %IngestDoublePointer.ref() -// CHECK:STDOUT: %Cpp.ref.loc18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref.loc18: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %foo.call.loc18: init = call %foo.ref.loc18() +// CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref.loc10: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %foo.call.loc10: init %ptr.dfe = call %foo.ref.loc10() +// CHECK:STDOUT: %.loc10_31.1: %ptr.dfe = value_of_initializer %foo.call.loc10 +// CHECK:STDOUT: %.loc10_31.2: %ptr.dfe = converted %foo.call.loc10, %.loc10_31.1 +// CHECK:STDOUT: %IngestDoublePointer.call: init %empty_tuple.type = call %IngestDoublePointer.ref(%.loc10_31.2) +// CHECK:STDOUT: %Cpp.ref.loc11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref.loc11: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %foo.call.loc11: init %ptr.dfe = call %foo.ref.loc11() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_const_pointer_return.carbon +// CHECK:STDOUT: --- import_const_pointer_return.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %const: type = const_type %S [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %const [concrete] // CHECK:STDOUT: %IngestConstPointer.type: type = fn_type @IngestConstPointer [concrete] // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %IngestConstPointer: %IngestConstPointer.type = struct_value () [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .S = %S.decl -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %IngestConstPointer.ref: %IngestConstPointer.type = name_ref IngestConstPointer, file.%IngestConstPointer.decl [concrete = constants.%IngestConstPointer] -// CHECK:STDOUT: %Cpp.ref.loc17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref.loc17: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %IngestConstPointer.call: init %empty_tuple.type = call %IngestConstPointer.ref() -// CHECK:STDOUT: %Cpp.ref.loc18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref.loc18: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref.loc10: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %foo.call.loc10: init %ptr = call %foo.ref.loc10() +// CHECK:STDOUT: %.loc10_30.1: %ptr = value_of_initializer %foo.call.loc10 +// CHECK:STDOUT: %.loc10_30.2: %ptr = converted %foo.call.loc10, %.loc10_30.1 +// CHECK:STDOUT: %IngestConstPointer.call: init %empty_tuple.type = call %IngestConstPointer.ref(%.loc10_30.2) +// CHECK:STDOUT: %Cpp.ref.loc11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref.loc11: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %foo.call.loc11: init %ptr = call %foo.ref.loc11() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/union.carbon b/toolchain/check/testdata/interop/cpp/function/union.carbon index 6e746983e3e0..b4127ed6f772 100644 --- a/toolchain/check/testdata/interop/cpp/function/union.carbon +++ b/toolchain/check/testdata/interop/cpp/function/union.carbon @@ -381,7 +381,7 @@ import Cpp library "decl_pointer_return_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: nullable pointer: U *` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] diff --git a/toolchain/check/type.cpp b/toolchain/check/type.cpp index 2905a8e41344..1cacd5bef6ae 100644 --- a/toolchain/check/type.cpp +++ b/toolchain/check/type.cpp @@ -105,6 +105,11 @@ auto GetAssociatedEntityType(Context& context, SemIR::InterfaceId interface_id, interface_specific_id); } +auto GetConstType(Context& context, SemIR::TypeInstId inner_type_id) + -> SemIR::TypeId { + return GetTypeImpl(context, inner_type_id); +} + auto GetSingletonType(Context& context, SemIR::TypeInstId singleton_id) -> SemIR::TypeId { CARBON_CHECK(SemIR::IsSingletonInstId(singleton_id)); diff --git a/toolchain/check/type.h b/toolchain/check/type.h index dffc638a379e..12b6ea1fbb0a 100644 --- a/toolchain/check/type.h +++ b/toolchain/check/type.h @@ -38,6 +38,10 @@ auto GetAssociatedEntityType(Context& context, SemIR::InterfaceId interface_id, auto GetSingletonType(Context& context, SemIR::TypeInstId singleton_id) -> SemIR::TypeId; +// Gets a const-qualified version of a type. +auto GetConstType(Context& context, SemIR::TypeInstId inner_type_id) + -> SemIR::TypeId; + // Gets a class type. auto GetClassType(Context& context, SemIR::ClassId class_id, SemIR::SpecificId specific_id) -> SemIR::TypeId;