Fix crash from accessing a Check::Context during lowering (#7335)

In generate_ast.cpp, an `CarbonExternalASTSource` is installed that has
a `Check::Context` pointer. During lowering, this `ExternalASTSource` is
still installed, and using it can cause a crash if the now-invalid
pointer is dereferenced.

Fix by adding a new `ReadOnlyASTSource` in sem_ir, and using that during
lowering.

`CarbonExternalASTSource` now inherits from `ReadOnlyASTSource` to avoid
some code duplication.

In generate_ast.cpp, we now always install a multiplex source, even if
there's only one child source. Clang internally keeps pointers to the
top-level `ExternalASTSource` installed via `setExternalSource`, and
those pointers aren't updated if `setExternalSource` is called again. By
using `MultiplexExternalSemaSource`, we can keep the top-level
`ExternalASTSource` pointer the same, and only update its children.

Using `MultiplexExternalSemaSource` this way requires a new constructor
and a method to modify its child sources; added a new LLVM patch adding
those.

https://github.com/carbon-language/carbon-lang/issues/7142
This commit is contained in:
Nicholas Bishop
2026-06-12 18:05:19 +00:00
committed by GitHub
parent f3b8e231ca
commit afd679129d
14 changed files with 495 additions and 169 deletions
+19
View File
@@ -5,6 +5,7 @@
#include "toolchain/lower/context.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Sema/MultiplexExternalSemaSource.h"
#include "common/check.h"
#include "common/growing_range.h"
#include "common/raw_string_ostream.h"
@@ -12,6 +13,7 @@
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "toolchain/lower/file_context.h"
#include "toolchain/sem_ir/inst_namer.h"
#include "toolchain/sem_ir/read_only_ast_source.h"
namespace Carbon::Lower {
@@ -70,6 +72,23 @@ auto Context::Finalize() && -> std::unique_ptr<llvm::Module> {
for (auto& file_context : file_contexts_.values()) {
if (file_context) {
if (file_context->cpp_file()) {
// Remove the `CarbonExternalASTSource` installed during check
// (always the last child of the multiplex source) and replace
// it with a `ReadOnlyASTSource`. This is necessary because the
// original source has a now-invalid pointer to a
// `Check::Context`.
auto& ast = const_cast<clang::ASTContext&>(
file_context->cpp_file()->ast_context());
auto* multiplex_source =
cast<clang::MultiplexExternalSemaSource>(ast.getExternalSource());
auto& child_sources = multiplex_source->GetSources();
child_sources.pop_back();
multiplex_source->AddSource(
llvm::makeIntrusiveRefCnt<SemIR::ReadOnlyASTSource>(
file_context->sem_ir()));
}
file_context->Finalize();
}
}