Files
carbon-lang/toolchain/check/handle_loop_statement.cpp
T
Jon Ross-PerkinsandRichard Smith 5bb318cae6 Switch AddInst struct init style. (#4012)
Trying to conform with #4009. Changes SemIR::LocIdAndInst construction
to root out struct init cases with AddInst and related functions. I'm
using templating of AddInst functions in order to avoid `AddInst(loc_id,
InstName{...})` and instead have `AddInst<InstName>(loc_id, {...})` with
I think similar readability results. There are a couple cases where inst
construction is templated and so designated initializers couldn't be
used, so this may be better for those in particular due to the extra
type enforcement.

This probably doesn't clean up every last case, but I was trying to get
the bulk at once without bleeding over into less related changes.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
2024-05-31 22:49:44 +00:00

144 lines
4.5 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/check/context.h"
#include "toolchain/check/convert.h"
namespace Carbon::Check {
// `while`
// -------
auto HandleWhileConditionStart(Context& context,
Parse::WhileConditionStartId node_id) -> bool {
// Branch to the loop header block. Note that we create a new block here even
// if the current block is empty; this ensures that the loop always has a
// preheader block.
auto loop_header_id = context.AddDominatedBlockAndBranch(node_id);
context.inst_block_stack().Pop();
// Start emitting the loop header block.
context.inst_block_stack().Push(loop_header_id);
context.AddCurrentCodeBlockToFunction();
context.node_stack().Push(node_id, loop_header_id);
return true;
}
auto HandleWhileCondition(Context& context, Parse::WhileConditionId node_id)
-> bool {
auto cond_value_id = context.node_stack().PopExpr();
auto loop_header_id =
context.node_stack().Peek<Parse::NodeKind::WhileConditionStart>();
cond_value_id = ConvertToBoolValue(context, node_id, cond_value_id);
// Branch to either the loop body or the loop exit block.
auto loop_body_id =
context.AddDominatedBlockAndBranchIf(node_id, cond_value_id);
auto loop_exit_id = context.AddDominatedBlockAndBranch(node_id);
context.inst_block_stack().Pop();
// Start emitting the loop body.
context.inst_block_stack().Push(loop_body_id);
context.AddCurrentCodeBlockToFunction();
context.break_continue_stack().push_back(
{.break_target = loop_exit_id, .continue_target = loop_header_id});
context.node_stack().Push(node_id, loop_exit_id);
return true;
}
auto HandleWhileStatement(Context& context, Parse::WhileStatementId node_id)
-> bool {
auto loop_exit_id =
context.node_stack().Pop<Parse::NodeKind::WhileCondition>();
auto loop_header_id =
context.node_stack().Pop<Parse::NodeKind::WhileConditionStart>();
context.break_continue_stack().pop_back();
// Add the loop backedge.
context.AddInst<SemIR::Branch>(node_id, {.target_id = loop_header_id});
context.inst_block_stack().Pop();
// Start emitting the loop exit block.
context.inst_block_stack().Push(loop_exit_id);
context.AddCurrentCodeBlockToFunction();
return true;
}
// `for`
// -----
auto HandleForHeaderStart(Context& context, Parse::ForHeaderStartId node_id)
-> bool {
return context.TODO(node_id, "HandleForHeaderStart");
}
auto HandleForIn(Context& context, Parse::ForInId node_id) -> bool {
context.decl_state_stack().Pop(DeclState::Var);
return context.TODO(node_id, "HandleForIn");
}
auto HandleForHeader(Context& context, Parse::ForHeaderId node_id) -> bool {
return context.TODO(node_id, "HandleForHeader");
}
auto HandleForStatement(Context& context, Parse::ForStatementId node_id)
-> bool {
return context.TODO(node_id, "HandleForStatement");
}
// `break`
// -------
auto HandleBreakStatementStart(Context& context,
Parse::BreakStatementStartId node_id) -> bool {
auto& stack = context.break_continue_stack();
if (stack.empty()) {
CARBON_DIAGNOSTIC(BreakOutsideLoop, Error,
"`break` can only be used in a loop.");
context.emitter().Emit(node_id, BreakOutsideLoop);
} else {
context.AddInst<SemIR::Branch>(node_id,
{.target_id = stack.back().break_target});
}
context.inst_block_stack().Pop();
context.inst_block_stack().PushUnreachable();
return true;
}
auto HandleBreakStatement(Context& /*context*/,
Parse::BreakStatementId /*node_id*/) -> bool {
return true;
}
// `continue`
// ----------
auto HandleContinueStatementStart(Context& context,
Parse::ContinueStatementStartId node_id)
-> bool {
auto& stack = context.break_continue_stack();
if (stack.empty()) {
CARBON_DIAGNOSTIC(ContinueOutsideLoop, Error,
"`continue` can only be used in a loop.");
context.emitter().Emit(node_id, ContinueOutsideLoop);
} else {
context.AddInst<SemIR::Branch>(node_id,
{.target_id = stack.back().continue_target});
}
context.inst_block_stack().Pop();
context.inst_block_stack().PushUnreachable();
return true;
}
auto HandleContinueStatement(Context& /*context*/,
Parse::ContinueStatementId /*node_id*/) -> bool {
return true;
}
} // namespace Carbon::Check