@@ -55,6 +55,21 @@ static auto MarkInitializerFor(SemIR::File& sem_ir, SemIR::InstId init_id,
55
55
}
56
56
}
57
57
58
+ // For a value or initializing expression using a copy value representation,
59
+ // copy the value into a temporary object.
60
+ static auto CopyValueToTemporary (Context& context, SemIR::InstId init_id)
61
+ -> SemIR::InstId {
62
+ // TODO: Consider using `None` to mean that we immediately materialize and
63
+ // initialize a temporary, rather than two separate instructions.
64
+ auto init = context.sem_ir ().insts ().Get (init_id);
65
+ auto temporary_id = AddInstWithCleanup<SemIR::TemporaryStorage>(
66
+ context, SemIR::LocId (init_id), {.type_id = init.type_id ()});
67
+ return AddInst<SemIR::Temporary>(context, SemIR::LocId (init_id),
68
+ {.type_id = init.type_id (),
69
+ .storage_id = temporary_id,
70
+ .init_id = init_id});
71
+ }
72
+
58
73
// Commits to using a temporary to store the result of the initializing
59
74
// expression described by `init_id`, and returns the location of the
60
75
// temporary. If `discarded` is `true`, the result is discarded, and no
@@ -85,15 +100,7 @@ static auto FinalizeTemporary(Context& context, SemIR::InstId init_id,
85
100
86
101
// The initializer has no return slot, but we want to produce a temporary
87
102
// object. Materialize one now.
88
- // TODO: Consider using `None` to mean that we immediately materialize and
89
- // initialize a temporary, rather than two separate instructions.
90
- auto init = sem_ir.insts ().Get (init_id);
91
- auto temporary_id = AddInstWithCleanup<SemIR::TemporaryStorage>(
92
- context, SemIR::LocId (init_id), {.type_id = init.type_id ()});
93
- return AddInst<SemIR::Temporary>(context, SemIR::LocId (init_id),
94
- {.type_id = init.type_id (),
95
- .storage_id = temporary_id,
96
- .init_id = init_id});
103
+ return CopyValueToTemporary (context, init_id);
97
104
}
98
105
99
106
// Materialize a temporary to hold the result of the given expression if it is
@@ -717,6 +724,8 @@ static auto IsValidExprCategoryForConversionTarget(
717
724
category == SemIR::ExprCategory::Initializing;
718
725
case ConversionTarget::DurableRef:
719
726
return category == SemIR::ExprCategory::DurableRef;
727
+ case ConversionTarget::CppThunkRef:
728
+ return category == SemIR::ExprCategory::EphemeralRef;
720
729
case ConversionTarget::ExplicitAs:
721
730
return true ;
722
731
case ConversionTarget::Initializer:
@@ -1173,6 +1182,34 @@ static auto PerformCopy(Context& context, SemIR::InstId expr_id, bool diagnose)
1173
1182
return SemIR::ErrorInst::InstId;
1174
1183
}
1175
1184
1185
+ // Convert a value expression so that it can be used to initialize a C++ thunk
1186
+ // parameter.
1187
+ static auto ConvertValueForCppThunkRef (Context& context, SemIR::InstId expr_id,
1188
+ bool diagnose) -> SemIR::InstId {
1189
+ auto expr = context.insts ().Get (expr_id);
1190
+
1191
+ // If the expression has a pointer value representation, extract that and use
1192
+ // it directly.
1193
+ if (SemIR::ValueRepr::ForType (context.sem_ir (), expr.type_id ()).kind ==
1194
+ SemIR::ValueRepr::Pointer) {
1195
+ return AddInst<SemIR::ValueAsRef>(
1196
+ context, SemIR::LocId (expr_id),
1197
+ {.type_id = expr.type_id (), .value_id = expr_id});
1198
+ }
1199
+
1200
+ // Otherwise, we need a temporary to pass as the thunk argument. Create a copy
1201
+ // and initialize a temporary from it.
1202
+ expr_id = PerformCopy (context, expr_id, diagnose);
1203
+ if (SemIR::GetExprCategory (context.sem_ir (), expr_id) ==
1204
+ SemIR::ExprCategory::Value) {
1205
+ // If we still have a value expression, then it's a value expression
1206
+ // whose value is being used directly to initialize the object. Copy
1207
+ // it into a temporary to form an ephemeral reference.
1208
+ expr_id = CopyValueToTemporary (context, expr_id);
1209
+ }
1210
+ return expr_id;
1211
+ }
1212
+
1176
1213
auto PerformAction (Context& context, SemIR::LocId loc_id,
1177
1214
SemIR::ConvertToValueAction action) -> SemIR::InstId {
1178
1215
return Convert (context, loc_id, action.inst_id ,
@@ -1377,7 +1414,8 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
1377
1414
case SemIR::ExprCategory::EphemeralRef:
1378
1415
// If a reference expression is an acceptable result, we're done.
1379
1416
if (target.kind == ConversionTarget::ValueOrRef ||
1380
- target.kind == ConversionTarget::Discarded) {
1417
+ target.kind == ConversionTarget::Discarded ||
1418
+ target.kind == ConversionTarget::CppThunkRef) {
1381
1419
break ;
1382
1420
}
1383
1421
@@ -1406,6 +1444,13 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
1406
1444
if (target.is_initializer ()) {
1407
1445
expr_id = PerformCopy (context, expr_id, target.diagnose );
1408
1446
}
1447
+
1448
+ // When initializing a C++ thunk parameter, form a reference, creating a
1449
+ // temporary if needed.
1450
+ if (target.kind == ConversionTarget::CppThunkRef) {
1451
+ expr_id = ConvertValueForCppThunkRef (context, expr_id, target.diagnose );
1452
+ }
1453
+
1409
1454
break ;
1410
1455
}
1411
1456
0 commit comments