Skip to content

Commit 1ac1d11

Browse files
authored
C++ Interop: Support reference types in fields and globals (#6187)
Implemented by generalizing the reference type support for parameters and return values to other use cases. The changes to the `method.carbon` test are due to to supporting the reference types but not supporting the necessary conversions. C++ Interop Demo: ```c++ // global.h struct C { int member = 0; int& member_ref = member; }; extern C& global; ``` ```c++ // global.cpp #include "global.h" static C static_c; C& global= static_c; ``` ```carbon // main.carbon library "Main"; import Core library "io"; import Cpp library "global.h"; fn Run() -> i32 { Core.Print(Cpp.global->member); ++(*Cpp.global->member_ref); Core.Print(Cpp.global->member); ++(*Cpp.global->member_ref); Core.Print(Cpp.global->member); return 0; } ``` ```shell $ clang++ -stdlib=libc++ -c global.cpp $ bazel build toolchain:carbon && bazel-bin/toolchain/carbon compile main.carbon $ bazel-bin/toolchain/carbon link global.o main.o --output=demo $ ./demo 0 1 2 ``` **Without this change**: ```shell main.carbon:10:14: error: semantics TODO: `Unsupported: var type: C &`   Core.Print(Cpp.global->member);              ^~~~~~~~~~ main.carbon:10:14: note: in `Cpp` name lookup for `global`   Core.Print(Cpp.global->member);              ^~~~~~~~~~ ``` Part of #6006 and #6186.
1 parent 0365467 commit 1ac1d11

File tree

4 files changed

+132
-65
lines changed

4 files changed

+132
-65
lines changed

toolchain/check/cpp/import.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,23 @@ static auto MapPointerType(Context& context, clang::QualType type,
12431243
.type_id = pointer_type_id};
12441244
}
12451245

1246+
// Maps a C++ reference type to a Carbon type.
1247+
// We map `T&` to `T*`, and `T&&` to `T`.
1248+
// TODO: Revisit this and decide what we really want to do here.
1249+
static auto MapReferenceType(Context& context, clang::QualType type,
1250+
TypeExpr referenced_type_expr) -> TypeExpr {
1251+
CARBON_CHECK(type->isReferenceType());
1252+
1253+
if (!type->isLValueReferenceType()) {
1254+
return referenced_type_expr;
1255+
}
1256+
1257+
SemIR::TypeId pointer_type_id =
1258+
GetPointerType(context, referenced_type_expr.inst_id);
1259+
return {.inst_id = context.types().GetInstId(pointer_type_id),
1260+
.type_id = pointer_type_id};
1261+
}
1262+
12461263
// Maps a C++ type to a Carbon type. `type` should not be canonicalized because
12471264
// we check for pointer nullability and nullability will be lost by
12481265
// canonicalization.
@@ -1256,6 +1273,8 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
12561273
type = type.getUnqualifiedType();
12571274
} else if (type->isPointerType()) {
12581275
type = type->getPointeeType();
1276+
} else if (type->isReferenceType()) {
1277+
type = type.getNonReferenceType();
12591278
} else {
12601279
break;
12611280
}
@@ -1274,6 +1293,8 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
12741293
mapped = MapQualifiedType(context, wrapper, mapped);
12751294
} else if (wrapper->isPointerType()) {
12761295
mapped = MapPointerType(context, wrapper, mapped);
1296+
} else if (wrapper->isReferenceType()) {
1297+
mapped = MapReferenceType(context, wrapper, mapped);
12771298
} else {
12781299
CARBON_FATAL("Unexpected wrapper type {0}", wrapper.getAsString());
12791300
}
@@ -1373,11 +1394,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
13731394
// TODO: The presence of qualifiers here is probably a Clang bug.
13741395
clang::QualType param_type = orig_param_type.getUnqualifiedType();
13751396

1376-
// We map `T&` parameters to `addr param: T*`, and `T&&` parameters to
1377-
// `param: T`.
1378-
// TODO: Revisit this and decide what we really want to do here.
13791397
bool is_ref_param = param_type->isLValueReferenceType();
1380-
param_type = param_type.getNonReferenceType();
13811398

13821399
// Mark the start of a region of insts, needed for the type expression
13831400
// created later with the call of `EndSubpatternAsExpr()`.
@@ -1395,10 +1412,6 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
13951412
return SemIR::InstBlockId::None;
13961413
}
13971414

1398-
if (is_ref_param) {
1399-
type_id = GetPointerType(context, orig_type_inst_id);
1400-
}
1401-
14021415
llvm::StringRef param_name = param->getName();
14031416
SemIR::NameId name_id =
14041417
param_name.empty()
@@ -1425,6 +1438,8 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
14251438
.subpattern_id = pattern_id,
14261439
.index = SemIR::CallParamIndex::None})});
14271440
if (is_ref_param) {
1441+
// We map `T&` parameters to `addr param: T*`.
1442+
// TODO: Revisit this and decide what we really want to do here.
14281443
pattern_id = AddPatternInst(
14291444
context, {param_loc_id,
14301445
SemIR::AddrPattern(
@@ -1446,23 +1461,14 @@ static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id,
14461461
clang::FunctionDecl* clang_decl) -> TypeExpr {
14471462
clang::QualType orig_ret_type = clang_decl->getReturnType();
14481463
if (!orig_ret_type->isVoidType()) {
1449-
// We map `T&` return type to `addr param: T*`, and `T&&` parameters to
1450-
// `param: T`.
1451-
// TODO: Revisit this and decide what we really want to do here.
1452-
clang::QualType ret_type = orig_ret_type.getNonReferenceType();
1453-
1454-
auto [orig_type_inst_id, type_id] = MapType(context, loc_id, ret_type);
1464+
auto [orig_type_inst_id, type_id] = MapType(context, loc_id, orig_ret_type);
14551465
if (!orig_type_inst_id.has_value()) {
14561466
context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
14571467
orig_ret_type.getAsString()));
14581468
return {.inst_id = SemIR::ErrorInst::TypeInstId,
14591469
.type_id = SemIR::ErrorInst::TypeId};
14601470
}
14611471

1462-
if (orig_ret_type->isLValueReferenceType()) {
1463-
type_id = GetPointerType(context, orig_type_inst_id);
1464-
}
1465-
14661472
return {orig_type_inst_id, type_id};
14671473
}
14681474

toolchain/check/testdata/interop/cpp/class/field.carbon

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct Struct {
1616
int a;
1717
int b;
1818
int* _Nonnull p;
19+
int& r;
1920
};
2021

2122
// --- use_struct_fields.carbon
@@ -24,9 +25,9 @@ library "[[@TEST_NAME]]";
2425

2526
import Cpp library "struct.h";
2627

27-
fn F(s: Cpp.Struct) -> (i32, i32, i32) {
28+
fn F(s: Cpp.Struct) -> (i32, i32, i32, i32) {
2829
//@dump-sem-ir-begin
29-
return (s.a, s.b, *s.p);
30+
return (s.a, s.b, *s.p, *s.r);
3031
//@dump-sem-ir-end
3132
}
3233

@@ -160,8 +161,6 @@ struct UnsupportedMembers {
160161
volatile int is_volatile;
161162
// Nullable pointers are not supported.
162163
int *is_nullable;
163-
// References are not supported.
164-
int &is_reference;
165164
// But this should be fine.
166165
int integer;
167166
};
@@ -202,21 +201,11 @@ fn Test(m: Cpp.UnsupportedMembers*) {
202201
// CHECK:STDERR: ^
203202
let a: i32 = m->is_volatile;
204203

205-
// CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE+8]]:17: note: in `Cpp` name lookup for `is_nullable` [InCppNameLookup]
204+
// CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE+4]]:17: note: in `Cpp` name lookup for `is_nullable` [InCppNameLookup]
206205
// CHECK:STDERR: let b: i32 = *m->is_nullable;
207206
// CHECK:STDERR: ^~~~~~~~~~~~~~
208207
// CHECK:STDERR:
209-
// CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE-17]]:10: in file included here [InCppInclude]
210-
// CHECK:STDERR: ./unsupported_members.h:8:8: error: semantics TODO: `Unsupported: field declaration has unhandled type or kind` [SemanticsTodo]
211-
// CHECK:STDERR: int &is_reference;
212-
// CHECK:STDERR: ^
213208
let b: i32 = *m->is_nullable;
214-
215-
// CHECK:STDERR: fail_use_unsupported_members.carbon:[[@LINE+4]]:16: note: in `Cpp` name lookup for `is_reference` [InCppNameLookup]
216-
// CHECK:STDERR: let c: i32 = m->is_reference;
217-
// CHECK:STDERR: ^~~~~~~~~~~~~~~
218-
// CHECK:STDERR:
219-
let c: i32 = m->is_reference;
220209
}
221210

222211
// CHECK:STDOUT: --- use_struct_fields.carbon
@@ -226,7 +215,7 @@ fn Test(m: Cpp.UnsupportedMembers*) {
226215
// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete]
227216
// CHECK:STDOUT: %N: Core.IntLiteral = bind_symbolic_name N, 0 [symbolic]
228217
// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete]
229-
// CHECK:STDOUT: %tuple.type.189: type = tuple_type (%i32, %i32, %i32) [concrete]
218+
// CHECK:STDOUT: %tuple.type.7ea: type = tuple_type (%i32, %i32, %i32, %i32) [concrete]
230219
// CHECK:STDOUT: %Struct.elem.86b: type = unbound_element_type %Struct, %i32 [concrete]
231220
// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete]
232221
// CHECK:STDOUT: %Struct.elem.765: type = unbound_element_type %Struct, %ptr.235 [concrete]
@@ -247,7 +236,7 @@ fn Test(m: Cpp.UnsupportedMembers*) {
247236
// CHECK:STDOUT: %Copy.impl_witness_table.1ed = impl_witness_table (%Core.import_ref.d0f6), @Int.as.Copy.impl [concrete]
248237
// CHECK:STDOUT: }
249238
// CHECK:STDOUT:
250-
// CHECK:STDOUT: fn @F(%s.param: %Struct) -> %return.param: %tuple.type.189 {
239+
// CHECK:STDOUT: fn @F(%s.param: %Struct) -> %return.param: %tuple.type.7ea {
251240
// CHECK:STDOUT: !entry:
252241
// CHECK:STDOUT: %s.ref.loc8_11: %Struct = name_ref s, %s
253242
// CHECK:STDOUT: %a.ref: %Struct.elem.86b = name_ref a, @Struct.%.1 [concrete = @Struct.%.1]
@@ -262,32 +251,45 @@ fn Test(m: Cpp.UnsupportedMembers*) {
262251
// CHECK:STDOUT: %.loc8_23.1: ref %ptr.235 = class_element_access %s.ref.loc8_22, element2
263252
// CHECK:STDOUT: %.loc8_23.2: %ptr.235 = bind_value %.loc8_23.1
264253
// CHECK:STDOUT: %.loc8_21.1: ref %i32 = deref %.loc8_23.2
265-
// CHECK:STDOUT: %.loc8_25.1: %tuple.type.189 = tuple_literal (%.loc8_12.2, %.loc8_17.2, %.loc8_21.1)
254+
// CHECK:STDOUT: %s.ref.loc8_28: %Struct = name_ref s, %s
255+
// CHECK:STDOUT: %r.ref: %Struct.elem.765 = name_ref r, @Struct.%.4 [concrete = @Struct.%.4]
256+
// CHECK:STDOUT: %.loc8_29.1: ref %ptr.235 = class_element_access %s.ref.loc8_28, element3
257+
// CHECK:STDOUT: %.loc8_29.2: %ptr.235 = bind_value %.loc8_29.1
258+
// CHECK:STDOUT: %.loc8_27.1: ref %i32 = deref %.loc8_29.2
259+
// CHECK:STDOUT: %.loc8_31.1: %tuple.type.7ea = tuple_literal (%.loc8_12.2, %.loc8_17.2, %.loc8_21.1, %.loc8_27.1)
266260
// CHECK:STDOUT: %impl.elem0.loc8_12: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59]
267261
// CHECK:STDOUT: %bound_method.loc8_12.1: <bound method> = bound_method %.loc8_12.2, %impl.elem0.loc8_12
268262
// CHECK:STDOUT: %specific_fn.loc8_12: <specific function> = specific_function %impl.elem0.loc8_12, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
269263
// CHECK:STDOUT: %bound_method.loc8_12.2: <bound method> = bound_method %.loc8_12.2, %specific_fn.loc8_12
270264
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_12: init %i32 = call %bound_method.loc8_12.2(%.loc8_12.2)
271265
// CHECK:STDOUT: %tuple.elem0: ref %i32 = tuple_access %return, element0
272-
// CHECK:STDOUT: %.loc8_25.2: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_12 to %tuple.elem0
266+
// CHECK:STDOUT: %.loc8_31.2: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_12 to %tuple.elem0
273267
// CHECK:STDOUT: %impl.elem0.loc8_17: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59]
274268
// CHECK:STDOUT: %bound_method.loc8_17.1: <bound method> = bound_method %.loc8_17.2, %impl.elem0.loc8_17
275269
// CHECK:STDOUT: %specific_fn.loc8_17: <specific function> = specific_function %impl.elem0.loc8_17, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
276270
// CHECK:STDOUT: %bound_method.loc8_17.2: <bound method> = bound_method %.loc8_17.2, %specific_fn.loc8_17
277271
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_17: init %i32 = call %bound_method.loc8_17.2(%.loc8_17.2)
278272
// CHECK:STDOUT: %tuple.elem1: ref %i32 = tuple_access %return, element1
279-
// CHECK:STDOUT: %.loc8_25.3: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_17 to %tuple.elem1
273+
// CHECK:STDOUT: %.loc8_31.3: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_17 to %tuple.elem1
280274
// CHECK:STDOUT: %.loc8_21.2: %i32 = bind_value %.loc8_21.1
281275
// CHECK:STDOUT: %impl.elem0.loc8_21: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59]
282276
// CHECK:STDOUT: %bound_method.loc8_21.1: <bound method> = bound_method %.loc8_21.2, %impl.elem0.loc8_21
283277
// CHECK:STDOUT: %specific_fn.loc8_21: <specific function> = specific_function %impl.elem0.loc8_21, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
284278
// CHECK:STDOUT: %bound_method.loc8_21.2: <bound method> = bound_method %.loc8_21.2, %specific_fn.loc8_21
285279
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_21: init %i32 = call %bound_method.loc8_21.2(%.loc8_21.2)
286280
// CHECK:STDOUT: %tuple.elem2: ref %i32 = tuple_access %return, element2
287-
// CHECK:STDOUT: %.loc8_25.4: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_21 to %tuple.elem2
288-
// CHECK:STDOUT: %.loc8_25.5: init %tuple.type.189 = tuple_init (%.loc8_25.2, %.loc8_25.3, %.loc8_25.4) to %return
289-
// CHECK:STDOUT: %.loc8_26: init %tuple.type.189 = converted %.loc8_25.1, %.loc8_25.5
290-
// CHECK:STDOUT: return %.loc8_26 to %return
281+
// CHECK:STDOUT: %.loc8_31.4: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_21 to %tuple.elem2
282+
// CHECK:STDOUT: %.loc8_27.2: %i32 = bind_value %.loc8_27.1
283+
// CHECK:STDOUT: %impl.elem0.loc8_27: %.7fa = impl_witness_access constants.%Copy.impl_witness.a32, element0 [concrete = constants.%Int.as.Copy.impl.Op.f59]
284+
// CHECK:STDOUT: %bound_method.loc8_27.1: <bound method> = bound_method %.loc8_27.2, %impl.elem0.loc8_27
285+
// CHECK:STDOUT: %specific_fn.loc8_27: <specific function> = specific_function %impl.elem0.loc8_27, @Int.as.Copy.impl.Op(constants.%int_32) [concrete = constants.%Int.as.Copy.impl.Op.specific_fn]
286+
// CHECK:STDOUT: %bound_method.loc8_27.2: <bound method> = bound_method %.loc8_27.2, %specific_fn.loc8_27
287+
// CHECK:STDOUT: %Int.as.Copy.impl.Op.call.loc8_27: init %i32 = call %bound_method.loc8_27.2(%.loc8_27.2)
288+
// CHECK:STDOUT: %tuple.elem3: ref %i32 = tuple_access %return, element3
289+
// CHECK:STDOUT: %.loc8_31.5: init %i32 = initialize_from %Int.as.Copy.impl.Op.call.loc8_27 to %tuple.elem3
290+
// 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
291+
// CHECK:STDOUT: %.loc8_32: init %tuple.type.7ea = converted %.loc8_31.1, %.loc8_31.6
292+
// CHECK:STDOUT: return %.loc8_32 to %return
291293
// CHECK:STDOUT: }
292294
// CHECK:STDOUT:
293295
// CHECK:STDOUT: --- use_union_fields.carbon

toolchain/check/testdata/interop/cpp/class/method.carbon

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,43 +47,67 @@ fn F(v: Cpp.HasQualifiers, p: Cpp.HasQualifiers*) {
4747

4848
library "[[@TEST_NAME]]";
4949

50+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+8]]:10: in file included here [InCppInclude]
51+
// 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]
52+
// CHECK:STDERR: 10 | void ref_ref_this() &&;
53+
// CHECK:STDERR: | ^
54+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:10: in file included here [InCppInclude]
55+
// CHECK:STDERR: ./object_param_qualifiers.h:10:8: note: 'ref_ref_this' declared here [CppInteropParseNote]
56+
// CHECK:STDERR: 10 | void ref_ref_this() &&;
57+
// CHECK:STDERR: | ^
5058
import Cpp library "object_param_qualifiers.h";
5159

5260
fn Value(v: Cpp.HasQualifiers) {
53-
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+5]]:3: error: `addr self` method cannot be invoked on a value [AddrSelfIsNonRef]
54-
// CHECK:STDERR: v.plain();
55-
// CHECK:STDERR: ^
56-
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon: note: initializing function parameter [InCallToFunctionParam]
57-
// CHECK:STDERR:
5861
v.plain();
5962

6063
// TODO: This should remain invalid once we support `volatile`.
61-
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:3: error: semantics TODO: `Unsupported: object parameter type: volatile struct HasQualifiers` [SemanticsTodo]
62-
// CHECK:STDERR: v.volatile_this();
63-
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
64-
// CHECK:STDERR:
6564
v.volatile_this();
6665

67-
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+8]]:14: error: no matching function for call to 'ref_this' [CppInteropParseError]
68-
// CHECK:STDERR: 29 | v.ref_this();
69-
// CHECK:STDERR: | ^
70-
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-20]]:10: in file included here [InCppInclude]
71-
// CHECK:STDERR: ./object_param_qualifiers.h:7:8: note: candidate function not viable: expects an lvalue for object argument [CppInteropParseNote]
72-
// CHECK:STDERR: 7 | void ref_this() &;
73-
// CHECK:STDERR: | ^
74-
// CHECK:STDERR:
7566
v.ref_this();
7667

77-
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:3: error: semantics TODO: `Unsupported: object parameter type: struct HasQualifiers &&` [SemanticsTodo]
68+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+12]]:3: note: in thunk for C++ function used here [InCppThunk]
7869
// CHECK:STDERR: v.ref_ref_this();
7970
// CHECK:STDERR: ^~~~~~~~~~~~~~~~
8071
// CHECK:STDERR:
72+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-14]]:10: in file included here [InCppInclude]
73+
// 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]
74+
// CHECK:STDERR: 11 | void const_ref_ref_this() const&&;
75+
// CHECK:STDERR: | ^
76+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-18]]:10: in file included here [InCppInclude]
77+
// CHECK:STDERR: ./object_param_qualifiers.h:11:8: note: 'const_ref_ref_this' declared here [CppInteropParseNote]
78+
// CHECK:STDERR: 11 | void const_ref_ref_this() const&&;
79+
// CHECK:STDERR: | ^
8180
v.ref_ref_this();
8281

83-
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+4]]:3: error: semantics TODO: `Unsupported: object parameter type: const struct HasQualifiers &&` [SemanticsTodo]
82+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE+29]]:3: note: in thunk for C++ function used here [InCppThunk]
8483
// CHECK:STDERR: v.const_ref_ref_this();
8584
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~
8685
// CHECK:STDERR:
86+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-25]]:3: error: `addr self` method cannot be invoked on a value [AddrSelfIsNonRef]
87+
// CHECK:STDERR: v.plain();
88+
// CHECK:STDERR: ^
89+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon: note: initializing function parameter [InCallToFunctionParam]
90+
// CHECK:STDERR:
91+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-27]]:3: error: semantics TODO: `Unsupported: object parameter type: volatile struct HasQualifiers` [SemanticsTodo]
92+
// CHECK:STDERR: v.volatile_this();
93+
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
94+
// CHECK:STDERR:
95+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-29]]:14: error: no matching function for call to 'ref_this' [CppInteropParseError]
96+
// CHECK:STDERR: 20 | v.ref_this();
97+
// CHECK:STDERR: | ^
98+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon:[[@LINE-40]]:10: in file included here [InCppInclude]
99+
// CHECK:STDERR: ./object_param_qualifiers.h:7:8: note: candidate function not viable: expects an lvalue for object argument [CppInteropParseNote]
100+
// CHECK:STDERR: 7 | void ref_this() &;
101+
// CHECK:STDERR: | ^
102+
// CHECK:STDERR:
103+
// 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]
104+
// CHECK:STDERR: v.const_ref_ref_this();
105+
// CHECK:STDERR: ^
106+
// 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]
107+
// CHECK:STDERR: v.const_ref_ref_this();
108+
// CHECK:STDERR: ^
109+
// CHECK:STDERR: fail_bad_object_param_qualifiers_by_value.carbon: note: initializing function parameter [InCallToFunctionParam]
110+
// CHECK:STDERR:
87111
v.const_ref_ref_this();
88112
}
89113

0 commit comments

Comments
 (0)