Files
carbon-lang/toolchain/sem_ir/cpp_file.h
T
Chandler CarruthandChristopher Di Bella 8a59f2a76b Fix mangling collision for C++ class template specializations (#7269)
Carbon-side thunks (for example the `Copy`/`Destroy` witness thunks
generated for imported C++ types) are mangled by Carbon, and their names
incorporate a fingerprint of the involved types. The instruction
fingerprinter identifies a class only by its name and parent scope,
which is sufficient for Carbon classes but not for imported C++ classes:
different specializations of one class template (and other cases such as
types in anonymous namespaces) share a Carbon name and parent scope. As
a result, the thunks for two distinct specializations could mangle to
the same name, producing a single LLVM function with two definitions and
failing `verifyModule` during lowering.

When fingerprinting a class imported from C++, also include the Clang
mangled name of its type.

Test: toolchain/lower/testdata/interop/cpp/thunks.carbon gains a split
with two specializations of one class template, each requiring a thunk;
their thunks now get distinct mangled names instead of colliding.

Assisted-by: Claude Code

---------

Co-authored-by: Christopher Di Bella <cjdb.ns@gmail.com>
2026-05-30 08:13:00 +00:00

90 lines
3.1 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_SEM_IR_CPP_FILE_H_
#define CARBON_TOOLCHAIN_SEM_IR_CPP_FILE_H_
#include <memory>
#include "clang/AST/Mangle.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "common/check.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
namespace Carbon::SemIR {
// The result of compiling the C++ portion of a `File`, including both any
// imported C++ headers and any inline C++ fragments.
class CppFile {
public:
explicit CppFile(std::unique_ptr<clang::CompilerInstance> clang,
llvm::LLVMContext* llvm_context)
: clang_(std::move(clang)), llvm_context_(llvm_context) {}
// Access to compilation options.
auto diagnostic_options() const -> const clang::DiagnosticOptions& {
return clang_->getDiagnostics().getDiagnosticOptions();
}
auto lang_options() const -> const clang::LangOptions& {
return clang_->getLangOpts();
}
// Access to Clang's compilation environment.
auto source_manager() -> clang::SourceManager& {
return clang_->getSourceManager();
}
auto source_manager() const -> const clang::SourceManager& {
return clang_->getSourceManager();
}
// TODO: This doesn't really belong here, but is currently used by lowering
// because Clang's code generation may produce diagnostics.
auto diagnostics() const -> clang::DiagnosticsEngine& {
return clang_->getDiagnostics();
}
// Access to layers of Clang's C++ representation.
auto ast_context() -> clang::ASTContext& { return clang_->getASTContext(); }
auto ast_context() const -> const clang::ASTContext& {
return clang_->getASTContext();
}
// Creates the mangle context for this file's C++ AST. Must be called once the
// AST context is available (after the frontend begins the source file) and
// before `mangle_context()` is used.
auto CreateMangleContext() -> void {
CARBON_CHECK(!mangle_context_);
mangle_context_.reset(ast_context().createMangleContext());
}
auto mangle_context() const -> clang::MangleContext& {
return *mangle_context_;
}
auto llvm_context() const -> llvm::LLVMContext* { return llvm_context_; }
auto SetCodeGenerator(clang::CodeGenerator* code_generator) -> void {
code_generator_ = code_generator;
}
auto GetCodeGenerator() const -> clang::CodeGenerator* {
// Clang code generation should not actually modify the AST, but isn't
// const-correct.
return code_generator_;
}
private:
std::unique_ptr<clang::CompilerInstance> clang_;
llvm::LLVMContext* llvm_context_;
clang::CodeGenerator* code_generator_ = nullptr;
// Created by `CreateMangleContext()` once the AST context is available.
std::unique_ptr<clang::MangleContext> mangle_context_;
};
} // namespace Carbon::SemIR
#endif // CARBON_TOOLCHAIN_SEM_IR_CPP_FILE_H_