mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Encapsulate clang::ASTUnit in SemIR::CppFile. (#6459)
This intends to avoid proliferation of dependencies on the exact API of `clang::ASTUnit`, and would enable us to more easily switch to a different approach that gives us more control over the construction of the Clang AST. Also remove some unnecessary tracking of the `CppFile` and instead always retrieve it from the `SemIR::File`. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
parent
78025fed70
commit
d208e950c7
@@ -16,7 +16,6 @@
|
||||
#include "clang/AST/UnresolvedSet.h"
|
||||
#include "clang/AST/VTableBuilder.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/TextDiagnostic.h"
|
||||
@@ -62,6 +61,7 @@
|
||||
#include "toolchain/parse/node_ids.h"
|
||||
#include "toolchain/sem_ir/clang_decl.h"
|
||||
#include "toolchain/sem_ir/class.h"
|
||||
#include "toolchain/sem_ir/cpp_file.h"
|
||||
#include "toolchain/sem_ir/cpp_overload_set.h"
|
||||
#include "toolchain/sem_ir/function.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
@@ -278,8 +278,9 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
|
||||
// Outputs Carbon diagnostics based on the collected Clang diagnostics. Must
|
||||
// be called after the AST is set in the context.
|
||||
auto EmitDiagnostics() -> void {
|
||||
CARBON_CHECK(sem_ir_->clang_ast_unit(),
|
||||
"Attempted to emit diagnostics before the AST Unit is loaded");
|
||||
CARBON_CHECK(
|
||||
sem_ir_->cpp_file(),
|
||||
"Attempted to emit C++ diagnostics before the C++ file is set");
|
||||
|
||||
for (size_t i = 0; i != diagnostic_infos_.size(); ++i) {
|
||||
const ClangDiagnosticInfo& info = diagnostic_infos_[i];
|
||||
@@ -388,15 +389,14 @@ class ShallowCopyCompilerInvocation : public clang::CompilerInvocation {
|
||||
|
||||
} // namespace
|
||||
|
||||
// Returns an AST for the C++ imports and a bool that represents whether
|
||||
// compilation errors where encountered or the generated AST is null due to an
|
||||
// error. Sets the AST in the context's `sem_ir`.
|
||||
// TODO: Consider to always have a (non-null) AST.
|
||||
// Generates a Clang AST for the C++ imports and sets it in the context's
|
||||
// `sem_ir`. Returns a bool that represents whether compilation was successful.
|
||||
// TODO: Consider to always have a (non-null) AST even if there are no Cpp
|
||||
// imports.
|
||||
static auto GenerateAst(
|
||||
Context& context, llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
std::shared_ptr<clang::CompilerInvocation> base_invocation)
|
||||
-> std::pair<std::unique_ptr<clang::ASTUnit>, bool> {
|
||||
std::shared_ptr<clang::CompilerInvocation> base_invocation) -> bool {
|
||||
auto invocation =
|
||||
std::make_shared<ShallowCopyCompilerInvocation>(*base_invocation);
|
||||
|
||||
@@ -434,12 +434,13 @@ static auto GenerateAst(
|
||||
// Attach the AST to SemIR. This needs to be done before we can emit any
|
||||
// diagnostics, so their locations can be properly interpreted by our
|
||||
// diagnostics machinery.
|
||||
context.sem_ir().set_clang_ast_unit(ast.get());
|
||||
context.sem_ir().set_cpp_file(
|
||||
std::make_unique<SemIR::CppFile>(std::move(ast)));
|
||||
|
||||
// Emit any diagnostics we queued up while building the AST.
|
||||
context.emitter().Flush();
|
||||
|
||||
return {std::move(ast), !ast || trap.hasErrorOccurred()};
|
||||
return !trap.hasErrorOccurred();
|
||||
}
|
||||
|
||||
// Adds a namespace for the `Cpp` import and returns its `NameScopeId`.
|
||||
@@ -462,16 +463,15 @@ static auto AddNamespace(Context& context, PackageNameId cpp_package_id,
|
||||
.add_result.name_scope_id;
|
||||
}
|
||||
|
||||
auto ImportCppFiles(Context& context,
|
||||
llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
std::shared_ptr<clang::CompilerInvocation> invocation)
|
||||
-> std::unique_ptr<clang::ASTUnit> {
|
||||
auto ImportCpp(Context& context,
|
||||
llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
|
||||
std::shared_ptr<clang::CompilerInvocation> invocation) -> void {
|
||||
if (imports.empty()) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
CARBON_CHECK(!context.sem_ir().clang_ast_unit());
|
||||
CARBON_CHECK(!context.sem_ir().cpp_file());
|
||||
|
||||
PackageNameId package_id = imports.front().package_id;
|
||||
CARBON_CHECK(
|
||||
@@ -480,21 +480,19 @@ auto ImportCppFiles(Context& context,
|
||||
}));
|
||||
auto name_scope_id = AddNamespace(context, package_id, imports);
|
||||
|
||||
auto [generated_ast, ast_has_error] =
|
||||
GenerateAst(context, imports, fs, std::move(invocation));
|
||||
bool ast_has_error =
|
||||
!GenerateAst(context, imports, fs, std::move(invocation));
|
||||
|
||||
SemIR::NameScope& name_scope = context.name_scopes().Get(name_scope_id);
|
||||
name_scope.set_is_closed_import(true);
|
||||
name_scope.set_clang_decl_context_id(context.clang_decls().Add(
|
||||
{.key = SemIR::ClangDeclKey(
|
||||
generated_ast->getASTContext().getTranslationUnitDecl()),
|
||||
{.key =
|
||||
SemIR::ClangDeclKey(context.ast_context().getTranslationUnitDecl()),
|
||||
.inst_id = name_scope.inst_id()}));
|
||||
|
||||
if (ast_has_error) {
|
||||
name_scope.set_has_error();
|
||||
}
|
||||
|
||||
return std::move(generated_ast);
|
||||
}
|
||||
|
||||
// Returns the Clang `DeclContext` for the given name scope. Return the
|
||||
@@ -2472,8 +2470,8 @@ auto ImportClassDefinitionForClangDecl(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::ClassId class_id,
|
||||
SemIR::ClangDeclId clang_decl_id)
|
||||
-> bool {
|
||||
clang::ASTUnit* ast = context.sem_ir().clang_ast_unit();
|
||||
CARBON_CHECK(ast);
|
||||
SemIR::CppFile* cpp_file = context.sem_ir().cpp_file();
|
||||
CARBON_CHECK(cpp_file);
|
||||
|
||||
auto* clang_decl =
|
||||
cast<clang::TagDecl>(context.clang_decls().Get(clang_decl_id).key.decl);
|
||||
@@ -2494,8 +2492,8 @@ auto ImportClassDefinitionForClangDecl(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
// Ask Clang whether the type is complete. This triggers template
|
||||
// instantiation if necessary.
|
||||
clang::DiagnosticErrorTrap trap(ast->getDiagnostics());
|
||||
if (!ast->getSema().isCompleteType(
|
||||
clang::DiagnosticErrorTrap trap(cpp_file->diagnostics());
|
||||
if (!cpp_file->sema().isCompleteType(
|
||||
loc, context.ast_context().getCanonicalTagType(clang_decl))) {
|
||||
// Type is incomplete. Nothing more to do, but tell the caller if we
|
||||
// produced an error.
|
||||
|
||||
Reference in New Issue
Block a user