Skip to content

Commit db4cdea

Browse files
committed
Add a test that deomnstrates that const non nullable pointers are wrongly mapped to nullable (optional) pointers
1 parent 53ea894 commit db4cdea

File tree

2 files changed

+129
-5
lines changed

2 files changed

+129
-5
lines changed

toolchain/check/cpp/import.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,9 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
14071407
// The parameter type is decayed but hasn't necessarily had its qualifiers
14081408
// removed.
14091409
// TODO: The presence of qualifiers here is probably a Clang bug.
1410+
// TODO: For const non nullable pointers (`C* _Nonnull const`), this removes
1411+
// both the const and the non-nullable attribute. We should probably
1412+
// preserve the non-nullable attribute.
14101413
clang::QualType param_type = orig_param_type.getUnqualifiedType();
14111414

14121415
bool is_ref_param = param_type->isLValueReferenceType();

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

Lines changed: 126 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,20 @@ fn F() {
5858
}
5959

6060
// ============================================================================
61-
// Const pointer as a parameter type
61+
// Const value pointer as a parameter type
6262
// ============================================================================
6363

64-
// --- const_pointer_param.h
64+
// --- const_value_pointer_param.h
6565

6666
struct S {};
6767

6868
auto foo(const S* _Nonnull) -> void;
6969

70-
// --- import_const_pointer_param.carbon
70+
// --- import_const_value_pointer_param.carbon
7171

7272
library "[[@TEST_NAME]]";
7373

74-
import Cpp library "const_pointer_param.h";
74+
import Cpp library "const_value_pointer_param.h";
7575

7676
fn G() -> const Cpp.S;
7777

@@ -82,6 +82,42 @@ fn F() {
8282
//@dump-sem-ir-end
8383
}
8484

85+
// ============================================================================
86+
// Const pointer as a parameter type
87+
// ============================================================================
88+
89+
// --- const_pointer_param.h
90+
91+
struct S {};
92+
93+
auto foo(S* _Nonnull const) -> void;
94+
95+
// --- fail_todo_import_const_pointer_param.carbon
96+
97+
library "[[@TEST_NAME]]";
98+
99+
import Cpp library "const_pointer_param.h";
100+
101+
fn G() -> const (Cpp.S*);
102+
103+
fn F() {
104+
//@dump-sem-ir-begin
105+
var p: const (Cpp.S*) = G();
106+
// CHECK:STDERR: fail_todo_import_const_pointer_param.carbon:[[@LINE+11]]:11: error: cannot implicitly convert expression of type `const (Cpp.S*)` to `Core.Optional(Cpp.S* as Core.OptionalStorage)` [ConversionFailure]
107+
// CHECK:STDERR: Cpp.foo(p);
108+
// CHECK:STDERR: ^
109+
// CHECK:STDERR: fail_todo_import_const_pointer_param.carbon:[[@LINE+8]]:11: note: type `const (Cpp.S*)` does not implement interface `Core.ImplicitAs(Core.Optional(Cpp.S* as Core.OptionalStorage))` [MissingImplInMemberAccessNote]
110+
// CHECK:STDERR: Cpp.foo(p);
111+
// CHECK:STDERR: ^
112+
// CHECK:STDERR: fail_todo_import_const_pointer_param.carbon:[[@LINE-13]]:10: in file included here [InCppInclude]
113+
// CHECK:STDERR: ./const_pointer_param.h:4:27: note: initializing function parameter [InCallToFunctionParam]
114+
// CHECK:STDERR: auto foo(S* _Nonnull const) -> void;
115+
// CHECK:STDERR: ^
116+
// CHECK:STDERR:
117+
Cpp.foo(p);
118+
//@dump-sem-ir-end
119+
}
120+
85121
// ============================================================================
86122
// Pointer as a return value
87123
// ============================================================================
@@ -443,7 +479,7 @@ fn F() {
443479
// CHECK:STDOUT: <elided>
444480
// CHECK:STDOUT: }
445481
// CHECK:STDOUT:
446-
// CHECK:STDOUT: --- import_const_pointer_param.carbon
482+
// CHECK:STDOUT: --- import_const_value_pointer_param.carbon
447483
// CHECK:STDOUT:
448484
// CHECK:STDOUT: constants {
449485
// CHECK:STDOUT: %S: type = class_type @S [concrete]
@@ -508,6 +544,91 @@ fn F() {
508544
// CHECK:STDOUT: <elided>
509545
// CHECK:STDOUT: }
510546
// CHECK:STDOUT:
547+
// CHECK:STDOUT: --- fail_todo_import_const_pointer_param.carbon
548+
// CHECK:STDOUT:
549+
// CHECK:STDOUT: constants {
550+
// CHECK:STDOUT: %S: type = class_type @S [concrete]
551+
// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete]
552+
// CHECK:STDOUT: %const.b9a: type = const_type %ptr.5c7 [concrete]
553+
// CHECK:STDOUT: %pattern_type.f25: type = pattern_type %const.b9a [concrete]
554+
// CHECK:STDOUT: %G.type: type = fn_type @G [concrete]
555+
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
556+
// CHECK:STDOUT: %G: %G.type = struct_value () [concrete]
557+
// CHECK:STDOUT: %foo.cpp_overload_set.type: type = cpp_overload_set_type @foo.cpp_overload_set [concrete]
558+
// CHECK:STDOUT: %foo.cpp_overload_set.value: %foo.cpp_overload_set.type = cpp_overload_set_value @foo.cpp_overload_set [concrete]
559+
// CHECK:STDOUT: %OptionalStorage.type: type = facet_type <@OptionalStorage> [concrete]
560+
// CHECK:STDOUT: %T.8b3: type = bind_symbolic_name T, 0 [symbolic]
561+
// CHECK:STDOUT: %ptr.79f: type = ptr_type %T.8b3 [symbolic]
562+
// CHECK:STDOUT: %MaybeUnformed.94c: type = class_type @MaybeUnformed, @MaybeUnformed(%ptr.79f) [symbolic]
563+
// CHECK:STDOUT: %OptionalStorage.impl_witness.1a6: <witness> = impl_witness imports.%OptionalStorage.impl_witness_table.cc0, @ptr.as.OptionalStorage.impl(%S) [concrete]
564+
// CHECK:STDOUT: %OptionalStorage.facet.547: %OptionalStorage.type = facet_value %ptr.5c7, (%OptionalStorage.impl_witness.1a6) [concrete]
565+
// CHECK:STDOUT: %Optional.764: type = class_type @Optional, @Optional(%OptionalStorage.facet.547) [concrete]
566+
// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete]
567+
// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete]
568+
// CHECK:STDOUT: %type_where: type = facet_type <type where .Self impls <CanDestroy>> [concrete]
569+
// CHECK:STDOUT: %facet_value: %type_where = facet_value %const.b9a, () [concrete]
570+
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.2b3: type = fn_type @DestroyT.binding.as_type.as.Destroy.impl.Op, @DestroyT.binding.as_type.as.Destroy.impl(%facet_value) [concrete]
571+
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.b8d: %DestroyT.binding.as_type.as.Destroy.impl.Op.type.2b3 = struct_value () [concrete]
572+
// CHECK:STDOUT: %ptr.6c1: type = ptr_type %const.b9a [concrete]
573+
// CHECK:STDOUT: }
574+
// CHECK:STDOUT:
575+
// CHECK:STDOUT: imports {
576+
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
577+
// CHECK:STDOUT: .S = %S.decl
578+
// CHECK:STDOUT: .foo = %foo.cpp_overload_set.value
579+
// CHECK:STDOUT: import Cpp//...
580+
// CHECK:STDOUT: }
581+
// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
582+
// CHECK:STDOUT: %foo.cpp_overload_set.value: %foo.cpp_overload_set.type = cpp_overload_set_value @foo.cpp_overload_set [concrete = constants.%foo.cpp_overload_set.value]
583+
// CHECK:STDOUT: %Core.import_ref.8c0: type = import_ref Core//prelude/types/optional, loc{{\d+_\d+}}, loaded [symbolic = @ptr.as.OptionalStorage.impl.%MaybeUnformed (constants.%MaybeUnformed.94c)]
584+
// CHECK:STDOUT: %Core.import_ref.566 = import_ref Core//prelude/types/optional, loc{{\d+_\d+}}, unloaded
585+
// CHECK:STDOUT: %Core.import_ref.cd4 = import_ref Core//prelude/types/optional, loc{{\d+_\d+}}, unloaded
586+
// CHECK:STDOUT: %Core.import_ref.6db = import_ref Core//prelude/types/optional, loc{{\d+_\d+}}, unloaded
587+
// CHECK:STDOUT: %Core.import_ref.5a7 = import_ref Core//prelude/types/optional, loc{{\d+_\d+}}, unloaded
588+
// CHECK:STDOUT: %OptionalStorage.impl_witness_table.cc0 = impl_witness_table (%Core.import_ref.8c0, %Core.import_ref.566, %Core.import_ref.cd4, %Core.import_ref.6db, %Core.import_ref.5a7), @ptr.as.OptionalStorage.impl [concrete]
589+
// CHECK:STDOUT: %foo__carbon_thunk.decl: %foo__carbon_thunk.type = fn_decl @foo__carbon_thunk [concrete = constants.%foo__carbon_thunk] {
590+
// CHECK:STDOUT: <elided>
591+
// CHECK:STDOUT: } {
592+
// CHECK:STDOUT: <elided>
593+
// CHECK:STDOUT: %.loc22_12.1: type = splice_block %Optional [concrete = constants.%Optional.764] {
594+
// CHECK:STDOUT: %OptionalStorage.facet: %OptionalStorage.type = facet_value constants.%ptr.5c7, (constants.%OptionalStorage.impl_witness.1a6) [concrete = constants.%OptionalStorage.facet.547]
595+
// CHECK:STDOUT: %.loc22_12.2: %OptionalStorage.type = converted constants.%ptr.5c7, %OptionalStorage.facet [concrete = constants.%OptionalStorage.facet.547]
596+
// CHECK:STDOUT: %Optional: type = class_type @Optional, @Optional(constants.%OptionalStorage.facet.547) [concrete = constants.%Optional.764]
597+
// CHECK:STDOUT: }
598+
// CHECK:STDOUT: <elided>
599+
// CHECK:STDOUT: }
600+
// CHECK:STDOUT: }
601+
// CHECK:STDOUT:
602+
// CHECK:STDOUT: fn @F() {
603+
// CHECK:STDOUT: !entry:
604+
// CHECK:STDOUT: name_binding_decl {
605+
// CHECK:STDOUT: %p.patt: %pattern_type.f25 = ref_binding_pattern p [concrete]
606+
// CHECK:STDOUT: %p.var_patt: %pattern_type.f25 = var_pattern %p.patt [concrete]
607+
// CHECK:STDOUT: }
608+
// CHECK:STDOUT: %p.var: ref %const.b9a = var %p.var_patt
609+
// CHECK:STDOUT: %G.ref: %G.type = name_ref G, file.%G.decl [concrete = constants.%G]
610+
// CHECK:STDOUT: %G.call: init %const.b9a = call %G.ref()
611+
// CHECK:STDOUT: assign %p.var, %G.call
612+
// CHECK:STDOUT: %.loc10: type = splice_block %const [concrete = constants.%const.b9a] {
613+
// CHECK:STDOUT: %Cpp.ref.loc10: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
614+
// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S]
615+
// CHECK:STDOUT: %ptr: type = ptr_type %S.ref [concrete = constants.%ptr.5c7]
616+
// CHECK:STDOUT: %const: type = const_type %ptr [concrete = constants.%const.b9a]
617+
// CHECK:STDOUT: }
618+
// CHECK:STDOUT: %p: ref %const.b9a = ref_binding p, %p.var
619+
// CHECK:STDOUT: %Cpp.ref.loc22: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
620+
// CHECK:STDOUT: %foo.ref: %foo.cpp_overload_set.type = name_ref foo, imports.%foo.cpp_overload_set.value [concrete = constants.%foo.cpp_overload_set.value]
621+
// CHECK:STDOUT: %p.ref: ref %const.b9a = name_ref p, %p
622+
// CHECK:STDOUT: %.loc22: %Optional.764 = converted %p.ref, <error> [concrete = <error>]
623+
// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(<error>)
624+
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.bound: <bound method> = bound_method %p.var, constants.%DestroyT.binding.as_type.as.Destroy.impl.Op.b8d
625+
// CHECK:STDOUT: <elided>
626+
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %p.var, %DestroyT.binding.as_type.as.Destroy.impl.Op.specific_fn
627+
// CHECK:STDOUT: %addr: %ptr.6c1 = addr_of %p.var
628+
// CHECK:STDOUT: %DestroyT.binding.as_type.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr)
629+
// CHECK:STDOUT: <elided>
630+
// CHECK:STDOUT: }
631+
// CHECK:STDOUT:
511632
// CHECK:STDOUT: --- import_pointer_return.carbon
512633
// CHECK:STDOUT:
513634
// CHECK:STDOUT: constants {

0 commit comments

Comments
 (0)