mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-02 22:02:51 +01:00
SemIR::Namespace->clang::NamespaceDecl interop (#6935)
Rough-in with TODO for caching and scoping/nesting, this only handles top level namespaces and doesn't nest them appropriately.
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "toolchain/check/context.h"
|
||||
#include "toolchain/check/cpp/import.h"
|
||||
#include "toolchain/check/name_lookup.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
#include "toolchain/diagnostics/emitter.h"
|
||||
#include "toolchain/diagnostics/format_providers.h"
|
||||
@@ -334,8 +336,9 @@ class ShallowCopyCompilerInvocation : public clang::CompilerInvocation {
|
||||
|
||||
class CarbonExternalASTSource : public clang::ExternalASTSource {
|
||||
public:
|
||||
explicit CarbonExternalASTSource(clang::ASTContext* ast_context)
|
||||
: ast_context_(*ast_context) {}
|
||||
explicit CarbonExternalASTSource(Context* context,
|
||||
clang::ASTContext* ast_context)
|
||||
: context_(context), ast_context_(ast_context) {}
|
||||
|
||||
auto FindExternalVisibleDeclsByName(
|
||||
const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
|
||||
@@ -344,41 +347,107 @@ class CarbonExternalASTSource : public clang::ExternalASTSource {
|
||||
auto StartTranslationUnit(clang::ASTConsumer* consumer) -> void override;
|
||||
|
||||
private:
|
||||
clang::ASTContext& ast_context_;
|
||||
Check::Context* context_;
|
||||
clang::ASTContext* ast_context_;
|
||||
clang::NamespaceDecl* carbon_cpp_namespace_ = nullptr;
|
||||
};
|
||||
|
||||
void CarbonExternalASTSource::StartTranslationUnit(
|
||||
clang::ASTConsumer* /*Consumer*/) {
|
||||
auto& translation_unit = *ast_context_.getTranslationUnitDecl();
|
||||
auto& translation_unit = *ast_context_->getTranslationUnitDecl();
|
||||
// Mark the translation unit as having external storage so we get a query for
|
||||
// the `Carbon` namespace in the top level/translation unit scope.
|
||||
translation_unit.setHasExternalVisibleStorage();
|
||||
}
|
||||
|
||||
// Map a Carbon entity to a Clang NamedDecl.
|
||||
static auto MapInstIdToClangDecl(Context& context,
|
||||
clang::ASTContext& ast_context,
|
||||
clang::DeclContext& decl_context,
|
||||
LookupResult lookup) -> clang::NamedDecl* {
|
||||
auto target_inst_id = lookup.scope_result.target_inst_id();
|
||||
if (auto target_inst =
|
||||
context.insts().TryGetAs<SemIR::Namespace>(target_inst_id)) {
|
||||
auto& name_scope = context.name_scopes().Get(target_inst->name_scope_id);
|
||||
auto* identifier_info =
|
||||
GetClangIdentifierInfo(context, name_scope.name_id());
|
||||
// TODO: Don't immediately use the decl_context - build any intermediate
|
||||
// namespaces iteratively.
|
||||
// Eventually add a mapping and use that/populate it/keep it up to date.
|
||||
// decl_context could be prepopulated in that mapping and not passed
|
||||
// explicitly to MapInstIdToClangDecl.
|
||||
return clang::NamespaceDecl::Create(
|
||||
ast_context, &decl_context, false, clang::SourceLocation(),
|
||||
clang::SourceLocation(), identifier_info, nullptr, false);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
|
||||
const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
|
||||
const clang::DeclContext* /*OriginalDC*/) -> bool {
|
||||
if (decl_context->getDeclKind() != clang::Decl::Kind::TranslationUnit) {
|
||||
if (decl_context != carbon_cpp_namespace_) {
|
||||
if (decl_context->getDeclKind() != clang::Decl::Kind::TranslationUnit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const llvm::StringLiteral carbon_namespace_name = "Carbon";
|
||||
if (auto* identifier = decl_name.getAsIdentifierInfo();
|
||||
!identifier || !identifier->isStr(carbon_namespace_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the top level 'Carbon' namespace
|
||||
auto& ast_context = decl_context->getParentASTContext();
|
||||
auto& mutable_tu_decl_context = *ast_context.getTranslationUnitDecl();
|
||||
carbon_cpp_namespace_ = clang::NamespaceDecl::Create(
|
||||
ast_context, &mutable_tu_decl_context, false, clang::SourceLocation(),
|
||||
clang::SourceLocation(), &ast_context.Idents.get(carbon_namespace_name),
|
||||
nullptr, false);
|
||||
carbon_cpp_namespace_->setHasExternalVisibleStorage();
|
||||
SetExternalVisibleDeclsForName(decl_context, decl_name,
|
||||
{carbon_cpp_namespace_});
|
||||
return true;
|
||||
}
|
||||
|
||||
// Lookup the name in Carbon package scope
|
||||
|
||||
llvm::SmallVector<Check::LookupScope> lookup_scopes;
|
||||
|
||||
// LocId::None seems fine here because we shouldn't produce any diagnostics
|
||||
// here - completeness should've been checked by clang before this point.
|
||||
if (!AppendLookupScopesForConstant(
|
||||
*context_, SemIR::LocId::None,
|
||||
context_->constant_values().Get(SemIR::Namespace::PackageInstId),
|
||||
SemIR::ConstantId::None, &lookup_scopes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const llvm::StringLiteral carbon_namespace_name = "Carbon";
|
||||
if (auto* identifier = decl_name.getAsIdentifierInfo();
|
||||
!identifier || !identifier->isStr(carbon_namespace_name)) {
|
||||
auto* identifier = decl_name.getAsIdentifierInfo();
|
||||
if (!identifier) {
|
||||
// Only supporting identifiers for now.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& ast_context = decl_context->getParentASTContext();
|
||||
auto& mutable_tu_decl_context = *ast_context.getTranslationUnitDecl();
|
||||
SetExternalVisibleDeclsForName(
|
||||
decl_context, decl_name,
|
||||
{
|
||||
clang::NamespaceDecl::Create(
|
||||
ast_context, &mutable_tu_decl_context, false,
|
||||
clang::SourceLocation(), clang::SourceLocation(),
|
||||
&ast_context.Idents.get(carbon_namespace_name), nullptr, false),
|
||||
});
|
||||
auto name_id = AddIdentifierName(*context_, identifier->getName());
|
||||
|
||||
// `required=false` so Carbon doesn't diagnose a failure, let Clang diagnose
|
||||
// it or even SFINAE.
|
||||
LookupResult result =
|
||||
LookupQualifiedName(*context_, SemIR::LocId::None, name_id, lookup_scopes,
|
||||
/*required=*/false);
|
||||
if (!result.scope_result.is_found()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the found Carbon entity to a Clang NamedDecl.
|
||||
auto* clang_decl = MapInstIdToClangDecl(*context_, *ast_context_,
|
||||
*carbon_cpp_namespace_, result);
|
||||
if (!clang_decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetExternalVisibleDeclsForName(decl_context, decl_name, {clang_decl});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -526,7 +595,7 @@ auto GenerateAst(Context& context,
|
||||
// support. Implement multiplexing support (possibly in Clang) to restore
|
||||
// modules functionality.
|
||||
ast.setExternalSource(
|
||||
llvm::makeIntrusiveRefCnt<CarbonExternalASTSource>(&ast));
|
||||
llvm::makeIntrusiveRefCnt<CarbonExternalASTSource>(&context, &ast));
|
||||
|
||||
if (llvm::Error error = action.Execute()) {
|
||||
// `Execute` currently never fails, but its contract allows it to.
|
||||
|
||||
Reference in New Issue
Block a user