Files
carbon-lang/toolchain/check/cpp/export.h
T
Nicholas Bishop f2c94517cc Reland "Fix crash from accessing a Check::Context during lowering (#7335)" (#7359)
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.

Originally landed in #7335, reverted in #7353 due to ASAN errors.
Changes since original:
* Use LLVM RTTI to make `Lower::Context::Finalize` less brittle.
Add LLVM RTTI to `ReadOnlyASTSource` (and `CarbonExternalASTSource`).
Change Finalize so that instead of just deleting the last multiplex
child source, it erases any multiplex child sources that match
`ReadOnlyASTSource`; this includes `CarbonExternalASTSource` since it's
a subclass.
* Fix ASAN error by updating the `MultiplexExternalSemaSource` earlier
in lowering. It is sometimes accessed during PrepareToLower, so update
it in `Context::GetFileContext` rather than `Context::Finalize`.

Fixes https://github.com/carbon-language/carbon-lang/issues/7142
2026-06-15 20:30:07 +00:00

75 lines
2.9 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_CPP_EXPORT_H_
#define CARBON_TOOLCHAIN_CHECK_CPP_EXPORT_H_
#include "clang/AST/Decl.h"
#include "toolchain/check/context.h"
#include "toolchain/sem_ir/ids.h"
namespace clang {
class CXXDestructorDecl;
class CXXRecordDecl;
} // namespace clang
namespace Carbon::Check {
// Exports a Carbon name scope into C++ as a namespace or class, or returns the
// C++ namespace or class declaration that it was imported from.
//
// If the name scope has already been exported, returns the existing context.
// Otherwise, creates a new C++ declaration context and returns it. Returns
// nullptr if the name scope could not be exported and an error was diagnosed.
auto ExportNameScopeToCpp(Context& context, SemIR::LocId loc_id,
SemIR::NameScopeId name_scope_id)
-> clang::DeclContext*;
// Exports a Carbon class into C++ as a class, or returns the C++ tag type that
// the class was imported from.
//
// If the class has already been exported, returns the existing C++ class.
// Otherwise, creates a new C++ class and returns it. Returns nullptr if the
// class could not be exported and an error was diagnosed.
auto ExportClassToCpp(Context& context, SemIR::LocId loc_id,
SemIR::ClassType class_type) -> clang::TagDecl*;
// Export all `SemIR::FieldDecl`s in the class body as `clang::FieldDecl`s.
auto ExportAllFieldsToCpp(Context& context, SemIR::Class& class_info) -> void;
// Exports a Carbon class field into C++.
//
// If the field has already been exported, returns the existing C++
// field.
//
// If the field has not already been exported, *all* fields of the class
// are exported, and then the requested C++ field is returned.
//
// Returns nullptr if the class could not be exported and an error was
// diagnosed.
auto ExportFieldToCpp(Context& context, SemIR::InstId field_inst_id,
SemIR::FieldDecl field_decl) -> clang::FieldDecl*;
// Get a `clang::FunctionDecl` that can be used to call a Carbon function.
auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id,
SemIR::FunctionId function_id) -> clang::FunctionDecl*;
// Export a Carbon destructor into C++.
//
// The destructor calls the `Destroy` operator.
auto ExportDestructorToCpp(Context& context, const SemIR::Class& class_info,
clang::CXXRecordDecl* record_decl)
-> clang::CXXDestructorDecl*;
// Export a Carbon variable into C++.
//
// Returns nullptr if the variable could not be exported an an error was
// diagnosed.
auto ExportVarToCpp(Context& context, SemIR::InstId inst_id,
SemIR::VarStorage var_storage) -> clang::VarDecl*;
} // namespace Carbon::Check
#endif // CARBON_TOOLCHAIN_CHECK_CPP_EXPORT_H_