@@ -472,121 +472,92 @@ auto Context::ConvertToValueOrReferenceExpression(SemIR::NodeId expr_id,
472
472
}
473
473
}
474
474
475
- auto Context::MarkInitializerFor (SemIR::NodeId init_id, SemIR::NodeId target_id)
476
- -> void {
477
- SemIR::Node init = semantics_ir (). GetNode (init_id);
478
- CARBON_CHECK (SemIR::GetExpressionCategory ( semantics_ir (), init_id) ==
479
- SemIR::ExpressionCategory::Initializing )
480
- << " initialization from non-initializing node " << init;
481
-
475
+ // Given an initializing expression, find its return slot. Returns `Invalid` if
476
+ // there is no return slot, because the initialization is not performed in
477
+ // place.
478
+ static auto FindReturnSlotForInitializer (SemIR::File& semantics_ir,
479
+ SemIR::NodeId init_id )
480
+ -> SemIR::NodeId {
481
+ SemIR::Node init = semantics_ir. GetNode (init_id);
482
482
switch (init.kind ()) {
483
483
default :
484
484
CARBON_FATAL () << " Initialization from unexpected node " << init;
485
485
486
486
case SemIR::NodeKind::StructInit:
487
487
case SemIR::NodeKind::TupleInit:
488
- case SemIR::NodeKind::InitializeFrom:
489
- CARBON_FATAL () << init << " should already have a destination" ;
488
+ // TODO: Track a return slot for these initializers.
489
+ CARBON_FATAL () << init
490
+ << " should be created with its return slot already "
491
+ " filled in properly" ;
492
+
493
+ case SemIR::NodeKind::InitializeFrom: {
494
+ auto [src_id, dest_id] = init.GetAsInitializeFrom ();
495
+ return dest_id;
496
+ }
490
497
491
498
case SemIR::NodeKind::Call: {
492
- // If the callee has a return slot, point it at our target.
493
499
auto [refs_id, callee_id] = init.GetAsCall ();
494
- if (semantics_ir ().GetFunction (callee_id).return_slot_id .is_valid ()) {
495
- // Replace the return slot with our given target, and remove the
496
- // tentatively-created temporary.
497
- auto temporary_id = std::exchange (
498
- semantics_ir ().GetNodeBlock (refs_id).back (), target_id);
499
- auto temporary = semantics_ir ().GetNode (temporary_id);
500
- CARBON_CHECK (temporary.kind () == SemIR::NodeKind::TemporaryStorage)
501
- << " Return slot for function call does not contain a temporary; "
502
- << " initialized multiple times? Have " << temporary;
503
- semantics_ir ().ReplaceNode (
504
- temporary_id, SemIR::Node::NoOp::Make (temporary.parse_node ()));
500
+ if (!semantics_ir.GetFunction (callee_id).return_slot_id .is_valid ()) {
501
+ return SemIR::NodeId::Invalid;
505
502
}
506
- return ;
503
+ return semantics_ir. GetNodeBlock (refs_id). back () ;
507
504
}
508
505
509
506
case SemIR::NodeKind::ArrayInit: {
510
- // Rewrite the return slot as a reference to our target. We can't just
511
- // update the index in `refs_id`, like we do for a Call, because there
512
- // will be other references to the return slot for the individual array
513
- // element initializers.
514
507
auto [src_id, refs_id] = init.GetAsArrayInit ();
515
- auto temporary_id = semantics_ir ().GetNodeBlock (refs_id).back ();
516
- CARBON_CHECK (semantics_ir ().GetNode (temporary_id).kind () ==
517
- SemIR::NodeKind::TemporaryStorage)
518
- << " Return slot for array init does not contain a temporary; "
519
- << " initialized multiple times? Have "
520
- << semantics_ir ().GetNode (temporary_id);
521
- semantics_ir ().ReplaceNode (
522
- temporary_id,
523
- SemIR::Node::StubReference::Make (
524
- init.parse_node (), semantics_ir ().GetNode (target_id).type_id (),
525
- target_id));
526
- return ;
508
+ return semantics_ir.GetNodeBlock (refs_id).back ();
527
509
}
528
510
}
529
511
}
530
512
513
+ auto Context::MarkInitializerFor (SemIR::NodeId init_id, SemIR::NodeId target_id)
514
+ -> void {
515
+ auto return_slot_id = FindReturnSlotForInitializer (semantics_ir (), init_id);
516
+ if (return_slot_id.is_valid ()) {
517
+ // Replace the temporary in the return slot with a reference to our target.
518
+ CARBON_CHECK (semantics_ir ().GetNode (return_slot_id).kind () ==
519
+ SemIR::NodeKind::TemporaryStorage)
520
+ << " Return slot for initializer does not contain a temporary; "
521
+ << " initialized multiple times? Have "
522
+ << semantics_ir ().GetNode (return_slot_id);
523
+ semantics_ir ().ReplaceNode (
524
+ return_slot_id,
525
+ SemIR::Node::StubReference::Make (
526
+ semantics_ir ().GetNode (init_id).parse_node (),
527
+ semantics_ir ().GetNode (target_id).type_id (), target_id));
528
+ }
529
+ }
530
+
531
531
auto Context::FinalizeTemporary (SemIR::NodeId init_id, bool discarded)
532
532
-> SemIR::NodeId {
533
- SemIR::Node init = semantics_ir ().GetNode (init_id);
534
- CARBON_CHECK (SemIR::GetExpressionCategory (semantics_ir (), init_id) ==
535
- SemIR::ExpressionCategory::Initializing)
536
- << " initialization from non-initializing node " << init;
537
-
538
- switch (init.kind ()) {
539
- default :
540
- CARBON_FATAL () << " Initialization from unexpected node " << init;
541
-
542
- case SemIR::NodeKind::StructInit:
543
- case SemIR::NodeKind::TupleInit:
544
- case SemIR::NodeKind::InitializeFrom:
545
- CARBON_FATAL () << init << " should already have a destination" ;
546
-
547
- case SemIR::NodeKind::Call: {
548
- auto [refs_id, callee_id] = init.GetAsCall ();
549
- if (semantics_ir ().GetFunction (callee_id).return_slot_id .is_valid ()) {
550
- // The return slot should have a materialized temporary in it.
551
- auto temporary_id = semantics_ir ().GetNodeBlock (refs_id).back ();
552
- CARBON_CHECK (semantics_ir ().GetNode (temporary_id).kind () ==
553
- SemIR::NodeKind::TemporaryStorage)
554
- << " Return slot for function call does not contain a temporary; "
555
- << " initialized multiple times? Have "
556
- << semantics_ir ().GetNode (temporary_id);
557
- return AddNode (SemIR::Node::Temporary::Make (
558
- init.parse_node (), init.type_id (), temporary_id, init_id));
559
- }
560
-
561
- if (discarded) {
562
- // Don't invent a temporary that we're going to discard.
563
- return SemIR::NodeId::Invalid;
564
- }
565
-
566
- // The function has no return slot, but we want to produce a temporary
567
- // object. Materialize one now.
568
- // TODO: Consider using an invalid ID to mean that we immediately
569
- // materialize and initialize a temporary, rather than two separate
570
- // nodes.
571
- auto temporary_id = AddNode (SemIR::Node::TemporaryStorage::Make (
572
- init.parse_node (), init.type_id ()));
573
- return AddNode (SemIR::Node::Temporary::Make (
574
- init.parse_node (), init.type_id (), temporary_id, init_id));
575
- }
576
-
577
- case SemIR::NodeKind::ArrayInit: {
578
- auto [src_id, refs_id] = init.GetAsArrayInit ();
579
- // The return slot should have a materialized temporary in it.
580
- auto temporary_id = semantics_ir ().GetNodeBlock (refs_id).back ();
581
- CARBON_CHECK (semantics_ir ().GetNode (temporary_id).kind () ==
582
- SemIR::NodeKind::TemporaryStorage)
583
- << " Return slot for array init does not contain a temporary; "
584
- << " initialized multiple times? Have "
585
- << semantics_ir ().GetNode (temporary_id);
586
- return AddNode (SemIR::Node::Temporary::Make (
587
- init.parse_node (), init.type_id (), temporary_id, init_id));
588
- }
589
- }
533
+ auto return_slot_id = FindReturnSlotForInitializer (semantics_ir (), init_id);
534
+ if (return_slot_id.is_valid ()) {
535
+ // The return slot should already have a materialized temporary in it.
536
+ CARBON_CHECK (semantics_ir ().GetNode (return_slot_id).kind () ==
537
+ SemIR::NodeKind::TemporaryStorage)
538
+ << " Return slot for initializer does not contain a temporary; "
539
+ << " initialized multiple times? Have "
540
+ << semantics_ir ().GetNode (return_slot_id);
541
+ auto init = semantics_ir ().GetNode (init_id);
542
+ return AddNode (SemIR::Node::Temporary::Make (
543
+ init.parse_node (), init.type_id (), return_slot_id, init_id));
544
+ }
545
+
546
+ if (discarded) {
547
+ // Don't invent a temporary that we're going to discard.
548
+ return SemIR::NodeId::Invalid;
549
+ }
550
+
551
+ // The initializer has no return slot, but we want to produce a temporary
552
+ // object. Materialize one now.
553
+ // TODO: Consider using an invalid ID to mean that we immediately
554
+ // materialize and initialize a temporary, rather than two separate
555
+ // nodes.
556
+ auto init = semantics_ir ().GetNode (init_id);
557
+ auto temporary_id = AddNode (
558
+ SemIR::Node::TemporaryStorage::Make (init.parse_node (), init.type_id ()));
559
+ return AddNode (SemIR::Node::Temporary::Make (init.parse_node (), init.type_id (),
560
+ temporary_id, init_id));
590
561
}
591
562
592
563
auto Context::HandleDiscardedExpression (SemIR::NodeId expr_id) -> void {
@@ -595,7 +566,6 @@ auto Context::HandleDiscardedExpression(SemIR::NodeId expr_id) -> void {
595
566
ConvertToValueOrReferenceExpression (expr_id, /* discarded=*/ true );
596
567
597
568
// TODO: This will eventually need to do some "do not discard" analysis.
598
- (void )expr_id;
599
569
}
600
570
601
571
auto Context::ImplicitAsForArgs (Parse::Node call_parse_node,
0 commit comments