Files
carbon-lang/toolchain/check/param_and_arg_refs_stack.h
T
Jon Ross-Perkins 65d6e3e221 Use verbose formatting of instructions on crash messages. (#4125)
Changes crash messages to start printing verbose forms of instructions,
rather than just the ID. Fixes some indentation issues with stacks. Also
switches unexpected inst formatting, because now there are lots, and
it'd be helpful to know where they are.

This uses a pimpl pattern for Formatter due to the number of member
functions on Formatter. Maybe we should refactor that, but this didn't
feel like a good place to do so.

Note, I have two concerns about this change... to note them here, to
make sure others are considering them when evaluating the
implementation:

1. Some instructions are very verbose to print, as evidenced by the
fn_decl printing (which includes function params) or scope printing
(which includes scope members).
- I'm not sure whether there's a way to simply reduce this, as it seems
essential to the requested printing of instructions.
- Long-term, we may at least want to limit the number of lines printed
here. However, I've already spent a fair amount of time here and I think
it's in a good state to evaluate.
2. Increased complexity in the crash handler may result in crash
messages failing to generate.
- For example, a crash in Formatter (and its deps, such as InstNamer or
location handling) prevents a stack from being printed. I'm pretty sure
I've written crashes in Formatter before.

Here's an example crash snippet (generated by adding a crash inside
`return` handling) before:

```
2.	NodeStack:
	0.	FunctionDefinitionStart -> function2
	1.	ReturnStatementStart -> no value
	2.	IntLiteral -> inst+26
inst_block_stack_:
	0.	block<invalid>	{inst+0, inst+1, inst+2, inst+23}
	1.	block9	{inst+26}
param_and_arg_refs_stack:
args_type_info_stack_:
```

And after:

```
2.	Check::Context
          NodeStack:
            0. FunctionDefinitionStart: function2
            1. ReturnStatementStart: no value
            2. IntLiteral:
              unexpected.inst+26.loc12_10: i32 = int_literal 0 [template = constants.%.2]
          inst_block_stack_:
            0. block<invalid> {
                package: <namespace> = namespace [template] {
                  .Core = unexpected.inst+2
                  .F = unexpected.inst+23.loc11_22
                }
                unexpected.inst+1 = import Core
                unexpected.inst+2: <namespace> = namespace unexpected.inst+1, [template] {}
                unexpected.inst+23.loc11_22: %F.type = fn_decl @F [template = constants.%F] {
                  unexpected.inst+9.loc11_9: init type = call constants.%Bool() [template = bool]
                  unexpected.inst+10.loc11_9: type = value_of_initializer unexpected.inst+9.loc11_9 [template = bool]
                  unexpected.inst+11.loc11_9: type = converted unexpected.inst+9.loc11_9, unexpected.inst+10.loc11_9 [template = bool]
                  unexpected.inst+12.loc11_6: bool = param b
                  @F.%b: bool = bind_name b, unexpected.inst+12.loc11_6
                  unexpected.inst+19.loc11_18: init type = call constants.%Int32() [template = i32]
                  unexpected.inst+20.loc11_18: type = value_of_initializer unexpected.inst+19.loc11_18 [template = i32]
                  unexpected.inst+21.loc11_18: type = converted unexpected.inst+19.loc11_18, unexpected.inst+20.loc11_18 [template = i32]
                  @F.%return: ref i32 = var <return slot>
                }
              }
            1. block9 {
                unexpected.inst+26.loc12_10: i32 = int_literal 0 [template = constants.%.2]
              }
          param_and_arg_refs_stack:
          args_type_info_stack_:
```
2024-07-17 22:05:19 +00:00

91 lines
3.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
#ifndef CARBON_TOOLCHAIN_CHECK_PARAM_AND_ARG_REFS_STACK_H_
#define CARBON_TOOLCHAIN_CHECK_PARAM_AND_ARG_REFS_STACK_H_
#include "common/check.h"
#include "toolchain/check/inst_block_stack.h"
#include "toolchain/check/node_stack.h"
namespace Carbon::Check {
// The stack of instruction blocks being used for per-element tracking of
// instructions in parameter and argument instruction blocks. Versus
// InstBlockStack, an element will have 1 or more instructions in blocks in
// InstBlockStack, but only ever 1 instruction in blocks here. The result is
// typically referred to as "param_refs" or "arg_refs".
class ParamAndArgRefsStack {
public:
explicit ParamAndArgRefsStack(SemIR::File& sem_ir,
llvm::raw_ostream* vlog_stream,
NodeStack& node_stack)
: node_stack_(&node_stack),
stack_("param_and_arg_refs_stack", sem_ir, vlog_stream) {}
// Starts handling parameters or arguments.
auto Push() -> void { stack_.Push(); }
// On a comma, pushes the most recent instruction, becoming param or arg ref.
// This also pops the NodeStack, meaning its top will remain start_kind.
auto ApplyComma() -> void {
// Support expressions, parameters, and other nodes like `StructField`
// that produce InstIds.
stack_.AddInstId(node_stack_->Pop<SemIR::InstId>());
}
// Detects whether there's an entry to push from the end of a parameter or
// argument list, and if so, moves it to the current parameter or argument
// list. Does not pop the list. `start_kind` is the node kind at the start
// of the parameter or argument list, and will be at the top of the parse node
// stack when this function returns.
auto EndNoPop(Parse::NodeKind start_kind) -> void {
if (!node_stack_->PeekIs(start_kind)) {
// Support expressions, parameters, and other nodes like
// `StructField` that produce InstIds.
stack_.AddInstId(node_stack_->Pop<SemIR::InstId>());
}
}
// Pops the current parameter or argument list. Should only be called after
// `EndNoPop`.
auto Pop() -> SemIR::InstBlockId { return stack_.Pop(); }
// Detects whether there's an entry to push. Pops and returns the argument
// list. This is the same as `EndNoPop` followed by `Pop`.
auto EndAndPop(Parse::NodeKind start_kind) -> SemIR::InstBlockId {
EndNoPop(start_kind);
return Pop();
}
// Pops the top instruction block, and discards it if it hasn't had an ID
// allocated.
auto PopAndDiscard() -> void { stack_.PopAndDiscard(); }
// Returns a view of the contents of the top instruction block on the stack.
auto PeekCurrentBlockContents() -> llvm::ArrayRef<SemIR::InstId> {
return stack_.PeekCurrentBlockContents();
}
// Runs verification that the processing cleanly finished.
auto VerifyOnFinish() -> void { stack_.VerifyOnFinish(); }
// Prints the stack for a stack dump.
auto PrintForStackDump(SemIR::Formatter& formatter, int indent,
llvm::raw_ostream& output) const -> void {
return stack_.PrintForStackDump(formatter, indent, output);
}
private:
// The node stack is manipulated when adding refs.
NodeStack* node_stack_;
// The refs stack.
InstBlockStack stack_;
};
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_PARAM_AND_ARG_REFS_STACK_H_