@@ -42,8 +42,8 @@ namespace Carbon::Check {
42
42
43
43
// Marks the initializer `init_id` as initializing `target_id`.
44
44
static auto MarkInitializerFor(SemIR::File& sem_ir, SemIR::InstId init_id,
45
- SemIR::InstId target_id,
46
- PendingBlock& target_block) -> void {
45
+ ConversionTarget& target) -> void {
46
+ CARBON_CHECK(target.is_initializer());
47
47
auto return_slot_arg_id = FindReturnSlotArgForInitializer(sem_ir, init_id);
48
48
if (return_slot_arg_id.has_value()) {
49
49
// Replace the temporary in the return slot with a reference to our target.
@@ -52,7 +52,8 @@ static auto MarkInitializerFor(SemIR::File& sem_ir, SemIR::InstId init_id,
52
52
"Return slot for initializer does not contain a temporary; "
53
53
"initialized multiple times? Have {0}",
54
54
sem_ir.insts().Get(return_slot_arg_id));
55
- target_block.MergeReplacing(return_slot_arg_id, target_id);
55
+ target.init_id =
56
+ target.init_block->MergeReplacing(return_slot_arg_id, target.init_id);
56
57
}
57
58
}
58
59
@@ -146,6 +147,29 @@ static auto MakeElementAccessInst(Context& context, SemIR::LocId loc_id,
146
147
}
147
148
}
148
149
150
+ // Get the conversion target kind to use when initializing an element of an
151
+ // aggregate.
152
+ static auto GetAggregateElementConversionTargetKind(SemIR::File& sem_ir,
153
+ ConversionTarget target)
154
+ -> ConversionTarget::Kind {
155
+ // If we're forming an initializer, then we want an initializer for each
156
+ // element.
157
+ if (target.is_initializer()) {
158
+ // Perform a final destination store if we're performing an in-place
159
+ // initialization.
160
+ auto init_repr = SemIR::InitRepr::ForType(sem_ir, target.type_id);
161
+ CARBON_CHECK(init_repr.kind != SemIR::InitRepr::Dependent,
162
+ "Aggregate should not have dependent init kind");
163
+ if (init_repr.kind == SemIR::InitRepr::InPlace) {
164
+ return ConversionTarget::FullInitializer;
165
+ }
166
+ return ConversionTarget::Initializer;
167
+ }
168
+
169
+ // Otherwise, we want a value representation for each element.
170
+ return ConversionTarget::Value;
171
+ }
172
+
149
173
// Converts an element of one aggregate so that it can be used as an element of
150
174
// another aggregate.
151
175
//
@@ -336,17 +360,8 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
336
360
return SemIR::ErrorInst::InstId;
337
361
}
338
362
339
- // If we're forming an initializer, then we want an initializer for each
340
- // element. Otherwise, we want a value representation for each element.
341
- // Perform a final destination store if we're performing an in-place
342
- // initialization.
343
- bool is_init = target.is_initializer();
344
363
ConversionTarget::Kind inner_kind =
345
- !is_init ? ConversionTarget::Value
346
- : SemIR::InitRepr::ForType(sem_ir, target.type_id).kind ==
347
- SemIR::InitRepr::InPlace
348
- ? ConversionTarget::FullInitializer
349
- : ConversionTarget::Initializer;
364
+ GetAggregateElementConversionTargetKind(sem_ir, target);
350
365
351
366
// Initialize each element of the destination from the corresponding element
352
367
// of the source.
@@ -373,7 +388,7 @@ static auto ConvertTupleToTuple(Context& context, SemIR::TupleType src_type,
373
388
new_block.Set(i, init_id);
374
389
}
375
390
376
- if (is_init ) {
391
+ if (target.is_initializer() ) {
377
392
target.init_block->InsertHere();
378
393
return AddInst<SemIR::TupleInit>(context, value_loc_id,
379
394
{.type_id = target.type_id,
@@ -447,17 +462,8 @@ static auto ConvertStructToStructOrClass(
447
462
}
448
463
}
449
464
450
- // If we're forming an initializer, then we want an initializer for each
451
- // element. Otherwise, we want a value representation for each element.
452
- // Perform a final destination store if we're performing an in-place
453
- // initialization.
454
- bool is_init = target.is_initializer();
455
465
ConversionTarget::Kind inner_kind =
456
- !is_init ? ConversionTarget::Value
457
- : SemIR::InitRepr::ForType(sem_ir, target.type_id).kind ==
458
- SemIR::InitRepr::InPlace
459
- ? ConversionTarget::FullInitializer
460
- : ConversionTarget::Initializer;
466
+ GetAggregateElementConversionTargetKind(sem_ir, target);
461
467
462
468
// Initialize each element of the destination from the corresponding element
463
469
// of the source.
@@ -545,6 +551,7 @@ static auto ConvertStructToStructOrClass(
545
551
new_block.Set(i, init_id);
546
552
}
547
553
554
+ bool is_init = target.is_initializer();
548
555
if (ToClass) {
549
556
target.init_block->InsertHere();
550
557
CARBON_CHECK(is_init,
@@ -1282,30 +1289,33 @@ static auto IsCppEnum(Context& context, SemIR::TypeId type_id) -> bool {
1282
1289
}
1283
1290
1284
1291
// Given a value expression, form a corresponding initializer that copies from
1285
- // that value, if it is possible to do so.
1286
- static auto PerformCopy(Context& context, SemIR::InstId expr_id, bool diagnose)
1287
- -> SemIR::InstId {
1292
+ // that value to the specified target , if it is possible to do so.
1293
+ static auto PerformCopy(Context& context, SemIR::InstId expr_id,
1294
+ ConversionTarget& target) -> SemIR::InstId {
1288
1295
// TODO: We don't have a mechanism yet to generate `Copy` impls for each enum
1289
1296
// type imported from C++. For now we fake it by providing a direct copy.
1290
- if (IsCppEnum(context, context.insts().Get(expr_id).type_id())) {
1291
- return CopyValueToTemporary(context, expr_id);
1297
+ auto type_id = context.insts().Get(expr_id).type_id();
1298
+ if (IsCppEnum(context, type_id)) {
1299
+ return expr_id;
1292
1300
}
1293
1301
1294
- return BuildUnaryOperator(
1302
+ auto copy_id = BuildUnaryOperator(
1295
1303
context, SemIR::LocId(expr_id), {"Copy"}, expr_id, [&] {
1296
- if (!diagnose) {
1304
+ if (!target. diagnose) {
1297
1305
return context.emitter().BuildSuppressed();
1298
1306
}
1299
1307
CARBON_DIAGNOSTIC(CopyOfUncopyableType, Error,
1300
1308
"cannot copy value of type {0}", TypeOfInstId);
1301
1309
return context.emitter().Build(expr_id, CopyOfUncopyableType, expr_id);
1302
1310
});
1311
+ MarkInitializerFor(context.sem_ir(), copy_id, target);
1312
+ return copy_id;
1303
1313
}
1304
1314
1305
1315
// Convert a value expression so that it can be used to initialize a C++ thunk
1306
1316
// parameter.
1307
- static auto ConvertValueForCppThunkRef(Context& context, SemIR::InstId expr_id,
1308
- bool diagnose) -> SemIR::InstId {
1317
+ static auto ConvertValueForCppThunkRef(Context& context, SemIR::InstId expr_id)
1318
+ -> SemIR::InstId {
1309
1319
auto expr = context.insts().Get(expr_id);
1310
1320
1311
1321
// If the expression has a pointer value representation, extract that and use
@@ -1319,8 +1329,13 @@ static auto ConvertValueForCppThunkRef(Context& context, SemIR::InstId expr_id,
1319
1329
1320
1330
// Otherwise, we need a temporary to pass as the thunk argument. Create a copy
1321
1331
// and initialize a temporary from it.
1322
- expr_id = PerformCopy(context, expr_id, diagnose);
1323
- return MaterializeIfInitializing(context, expr_id);
1332
+ auto temporary_id = AddInst<SemIR::TemporaryStorage>(
1333
+ context, SemIR::LocId(expr_id), {.type_id = expr.type_id()});
1334
+ expr_id = Initialize(context, SemIR::LocId(expr_id), temporary_id, expr_id);
1335
+ return AddInstWithCleanup<SemIR::Temporary>(context, SemIR::LocId(expr_id),
1336
+ {.type_id = expr.type_id(),
1337
+ .storage_id = temporary_id,
1338
+ .init_id = expr_id});
1324
1339
}
1325
1340
1326
1341
// Returns the Core interface name to use for a given kind of conversion.
@@ -1524,8 +1539,7 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
1524
1539
// a conversion. In that case, we will have created it with the
1525
1540
// target already set.
1526
1541
// TODO: Find a better way to track whether we need to do this.
1527
- MarkInitializerFor(sem_ir, expr_id, target.init_id,
1528
- *target.init_block);
1542
+ MarkInitializerFor(sem_ir, expr_id, target);
1529
1543
}
1530
1544
break;
1531
1545
}
@@ -1577,13 +1591,13 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
1577
1591
1578
1592
// When initializing from a value, perform a copy.
1579
1593
if (target.is_initializer()) {
1580
- expr_id = PerformCopy(context, expr_id, target.diagnose );
1594
+ expr_id = PerformCopy(context, expr_id, target);
1581
1595
}
1582
1596
1583
1597
// When initializing a C++ thunk parameter, form a reference, creating a
1584
1598
// temporary if needed.
1585
1599
if (target.kind == ConversionTarget::CppThunkRef) {
1586
- expr_id = ConvertValueForCppThunkRef(context, expr_id, target.diagnose );
1600
+ expr_id = ConvertValueForCppThunkRef(context, expr_id);
1587
1601
}
1588
1602
1589
1603
break;
@@ -1592,7 +1606,7 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
1592
1606
// Perform a final destination store, if necessary.
1593
1607
if (target.kind == ConversionTarget::FullInitializer) {
1594
1608
if (auto init_rep = SemIR::InitRepr::ForType(sem_ir, target.type_id);
1595
- init_rep.kind == SemIR::InitRepr::ByCopy ) {
1609
+ init_rep.MightBeByCopy() ) {
1596
1610
target.init_block->InsertHere();
1597
1611
expr_id = AddInst<SemIR::InitializeFrom>(context, loc_id,
1598
1612
{.type_id = target.type_id,
0 commit comments