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.
This commit is contained in:
Richard Smith
2025-07-12 02:22:24 +00:00
committed by GitHub
parent 27be0973e7
commit a6acba9eab
7 changed files with 215 additions and 118 deletions
@@ -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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <error>
// 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: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
// 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> = bound_method %int_1, %impl.elem0 [concrete = constants.%Convert.bound]
// CHECK:STDOUT: %bound_method.loc16_13.1: <bound method> = bound_method %int_1, %impl.elem0 [concrete = constants.%Convert.bound]
// CHECK:STDOUT: %specific_fn: <specific function> = specific_function %impl.elem0, @Convert.5(constants.%int_16) [concrete = constants.%Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc15_13.2: <bound method> = 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> = 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, <error> [concrete = <error>]
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(<error>)
// CHECK:STDOUT: <elided>
// 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <error>
// 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: <elided>
// CHECK:STDOUT: } {
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
// 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, <error> [concrete = <error>]
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(<error>)
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT: