mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Change how CheckParseTrees receives NodeLocConverters (#4563)
This is really a set of closely related changes: 1) We really shouldn't be creating a Check::Unit for _Lower_. This fixes that by storing the diagnostic converter for reuse. 2) Rather than passing in node converters to Check as their own array, pass diagnostic converters as part of Check::Unit. 3) To support creating the converters early, pass SemIR::File pre-constructed. 4) Since SemIR::File construction was used to track "checked", add `is_checked` for that. 5) Clarifies a subtle edge case around `input_filename_` use with `-`. Note the key consequence of this change, where I actually started, is that `Check` only has one array of `Check::Unit` instead of receiving `NodeLocConverter` as a separate array.
This commit is contained in:
@@ -395,7 +395,7 @@ class CompilationUnit {
|
||||
|
||||
// Parses tokens. Returns true on success.
|
||||
auto RunParse() -> void {
|
||||
CARBON_CHECK(tokens_);
|
||||
CARBON_CHECK(tokens_, "Must call RunLex first");
|
||||
|
||||
LogCall("Parse::Parse", "parse", [&] {
|
||||
parse_tree_ = Parse::Parse(*tokens_, *consumer_, vlog_stream_);
|
||||
@@ -418,34 +418,49 @@ class CompilationUnit {
|
||||
}
|
||||
}
|
||||
|
||||
auto PreCheck() -> Parse::NodeLocConverter& {
|
||||
CARBON_CHECK(parse_tree_, "Must call RunParse first");
|
||||
get_parse_tree_and_subtrees_ = [this]() -> const Parse::TreeAndSubtrees& {
|
||||
return this->GetParseTreeAndSubtrees();
|
||||
};
|
||||
node_converter_.emplace(&*tokens_, source_->filename(),
|
||||
*get_parse_tree_and_subtrees_);
|
||||
return *node_converter_;
|
||||
}
|
||||
|
||||
// Returns information needed to check this unit.
|
||||
auto GetCheckUnit() -> Check::Unit {
|
||||
CARBON_CHECK(parse_tree_);
|
||||
return {
|
||||
.value_stores = &value_stores_,
|
||||
.timings = &timings_,
|
||||
.tokens = &*tokens_,
|
||||
.parse_tree = &*parse_tree_,
|
||||
.consumer = consumer_,
|
||||
.get_parse_tree_and_subtrees = [&]() -> const Parse::TreeAndSubtrees& {
|
||||
return GetParseTreeAndSubtrees();
|
||||
},
|
||||
.sem_ir = &sem_ir_};
|
||||
auto GetCheckUnit(SemIR::CheckIRId check_ir_id,
|
||||
llvm::ArrayRef<Parse::NodeLocConverter*> node_converters)
|
||||
-> Check::Unit {
|
||||
CARBON_CHECK(node_converter_, "Must call PreCheck first");
|
||||
|
||||
sem_ir_.emplace(check_ir_id, parse_tree_->packaging_decl(), value_stores_,
|
||||
input_filename_);
|
||||
if (mem_usage_) {
|
||||
mem_usage_->Collect("sem_ir_", *sem_ir_);
|
||||
}
|
||||
|
||||
sem_ir_converter_.emplace(node_converters, &*sem_ir_);
|
||||
return {.consumer = consumer_,
|
||||
.value_stores = &value_stores_,
|
||||
.timings = &timings_,
|
||||
.tokens = &*tokens_,
|
||||
.parse_tree = &*parse_tree_,
|
||||
.get_parse_tree_and_subtrees = *get_parse_tree_and_subtrees_,
|
||||
.sem_ir = &*sem_ir_,
|
||||
.node_converter = &*node_converter_,
|
||||
.sem_ir_converter = &*sem_ir_converter_};
|
||||
}
|
||||
|
||||
// Runs post-check logic. Returns true if checking succeeded for the IR.
|
||||
auto PostCheck() -> void {
|
||||
CARBON_CHECK(sem_ir_);
|
||||
CARBON_CHECK(sem_ir_converter_, "Must call GetCheckUnit first");
|
||||
|
||||
// We've finished all steps that can produce diagnostics. Emit the
|
||||
// diagnostics now, so that the developer sees them sooner and doesn't need
|
||||
// to wait for code generation.
|
||||
consumer_->Flush();
|
||||
|
||||
if (mem_usage_) {
|
||||
mem_usage_->Collect("sem_ir_", *sem_ir_);
|
||||
}
|
||||
|
||||
if (options_.dump_raw_sem_ir && IncludeInDumps()) {
|
||||
CARBON_VLOG("*** Raw SemIR::File ***\n{0}\n", *sem_ir_);
|
||||
sem_ir_->Print(driver_env_->output_stream, options_.builtin_sem_ir);
|
||||
@@ -486,8 +501,8 @@ class CompilationUnit {
|
||||
}
|
||||
|
||||
// Lower SemIR to LLVM IR.
|
||||
auto RunLower(const Check::SemIRDiagnosticConverter& converter) -> void {
|
||||
CARBON_CHECK(sem_ir_);
|
||||
auto RunLower() -> void {
|
||||
CARBON_CHECK(sem_ir_converter_, "Must call PostCheck first");
|
||||
|
||||
LogCall("Lower::LowerToLLVM", "lower", [&] {
|
||||
llvm_context_ = std::make_unique<llvm::LLVMContext>();
|
||||
@@ -495,8 +510,8 @@ class CompilationUnit {
|
||||
// producing textual LLVM IR.
|
||||
SemIR::InstNamer inst_namer(*tokens_, *parse_tree_, *sem_ir_);
|
||||
module_ = Lower::LowerToLLVM(*llvm_context_, options_.include_debug_info,
|
||||
converter, input_filename_, *sem_ir_,
|
||||
&inst_namer, vlog_stream_);
|
||||
*sem_ir_converter_, input_filename_,
|
||||
*sem_ir_, &inst_namer, vlog_stream_);
|
||||
});
|
||||
if (vlog_stream_) {
|
||||
CARBON_VLOG("*** llvm::Module ***\n");
|
||||
@@ -511,7 +526,7 @@ class CompilationUnit {
|
||||
}
|
||||
|
||||
auto RunCodeGen() -> void {
|
||||
CARBON_CHECK(module_);
|
||||
CARBON_CHECK(module_, "Must call RunLower first");
|
||||
LogCall("CodeGen", "codegen", [&] { success_ = RunCodeGenHelper(); });
|
||||
}
|
||||
|
||||
@@ -577,8 +592,8 @@ class CompilationUnit {
|
||||
if (!source_->is_regular_file()) {
|
||||
// Don't invent file names like `-.o` or `/dev/stdin.o`.
|
||||
driver_env_->error_stream
|
||||
<< "error: output file name must be specified for input '"
|
||||
<< input_filename_ << "' that is not a regular file\n";
|
||||
<< "error: output file name must be specified for input `"
|
||||
<< input_filename_ << "` that is not a regular file\n";
|
||||
return false;
|
||||
}
|
||||
output_filename = input_filename_;
|
||||
@@ -654,6 +669,10 @@ class CompilationUnit {
|
||||
DriverEnv* driver_env_;
|
||||
SharedValueStores value_stores_;
|
||||
const CompileOptions& options_;
|
||||
// The input filename from the command line. For most diagnostics, we
|
||||
// typically use `source_->filename()`, which includes a `-` -> `<stdin>`
|
||||
// translation. However, logging and some diagnostics use the command line
|
||||
// argument.
|
||||
std::string input_filename_;
|
||||
|
||||
// Copied from driver_ for CARBON_VLOG.
|
||||
@@ -675,6 +694,10 @@ class CompilationUnit {
|
||||
std::optional<Lex::TokenizedBuffer> tokens_;
|
||||
std::optional<Parse::Tree> parse_tree_;
|
||||
std::optional<Parse::TreeAndSubtrees> parse_tree_and_subtrees_;
|
||||
std::optional<std::function<const Parse::TreeAndSubtrees&()>>
|
||||
get_parse_tree_and_subtrees_;
|
||||
std::optional<Parse::NodeLocConverter> node_converter_;
|
||||
std::optional<Check::SemIRDiagnosticConverter> sem_ir_converter_;
|
||||
std::optional<SemIR::File> sem_ir_;
|
||||
std::unique_ptr<llvm::LLVMContext> llvm_context_;
|
||||
std::unique_ptr<llvm::Module> module_;
|
||||
@@ -779,22 +802,30 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
|
||||
return make_result();
|
||||
}
|
||||
|
||||
// Check.
|
||||
SharedValueStores builtin_value_stores;
|
||||
llvm::SmallVector<Check::Unit> check_units;
|
||||
// Pre-check assigns IR IDs and constructs node converters.
|
||||
llvm::SmallVector<Parse::NodeLocConverter*> node_converters;
|
||||
// This size may not match due to units that are missing source, but that's an
|
||||
// error case and not worth extra work.
|
||||
node_converters.reserve(units.size());
|
||||
for (auto& unit : units) {
|
||||
if (unit->has_source()) {
|
||||
check_units.push_back(unit->GetCheckUnit());
|
||||
node_converters.push_back(&unit->PreCheck());
|
||||
}
|
||||
}
|
||||
llvm::SmallVector<Parse::NodeLocConverter> node_converters;
|
||||
node_converters.reserve(check_units.size());
|
||||
for (auto& unit : check_units) {
|
||||
node_converters.emplace_back(unit.tokens, unit.tokens->source().filename(),
|
||||
unit.get_parse_tree_and_subtrees);
|
||||
|
||||
// Gather Check::Units.
|
||||
llvm::SmallVector<Check::Unit> check_units;
|
||||
check_units.reserve(node_converters.size());
|
||||
for (auto& unit : units) {
|
||||
if (unit->has_source()) {
|
||||
SemIR::CheckIRId check_ir_id(check_units.size());
|
||||
check_units.push_back(unit->GetCheckUnit(check_ir_id, node_converters));
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the actual checking.
|
||||
CARBON_VLOG_TO(driver_env.vlog_stream, "*** Check::CheckParseTrees ***\n");
|
||||
Check::CheckParseTrees(check_units, node_converters, options_.prelude_import,
|
||||
Check::CheckParseTrees(check_units, options_.prelude_import,
|
||||
driver_env.vlog_stream);
|
||||
CARBON_VLOG_TO(driver_env.vlog_stream,
|
||||
"*** Check::CheckParseTrees done ***\n");
|
||||
@@ -816,9 +847,7 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
|
||||
|
||||
// Lower.
|
||||
for (const auto& unit : units) {
|
||||
Check::SemIRDiagnosticConverter converter(node_converters,
|
||||
&**unit->GetCheckUnit().sem_ir);
|
||||
unit->RunLower(converter);
|
||||
unit->RunLower();
|
||||
}
|
||||
if (options_.phase == CompileOptions::Phase::Lower) {
|
||||
return make_result();
|
||||
|
||||
Reference in New Issue
Block a user