Add support for importing C++ inline functions (#5427)

This requires:
* Making `FunctionDecl` mutable since generating code
(`HandleTopLevelDecl()`) requires a mutable declaration and since we
manually add `used` attribute to force code generation.
* Passing the file system to `Lower` since it's needed by Clang code
generation.
* Creating an internal Clang LLVM module and link it against the Carbon
LLVM module.

Demo:

```c++
// hello_world.h

extern int puts;
inline void hello_world() {
  ((int (*)(const char*))&puts)("hello world");
}
```

```carbon
// main.carbon

library "Main";

import Cpp library "hello_world.h";

fn Run() -> i32 {
  Cpp.hello_world();
  return 0;
}
```

```shell
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link main.o --output=demo
$ ./demo
hello world
```

Based on https://github.com/carbon-language/carbon-lang/pull/5406.

Part of #5405.
This commit is contained in:
Boaz Brickner
2025-05-21 07:02:05 +00:00
committed by GitHub
parent 5b884ae14d
commit 852d0191a9
16 changed files with 385 additions and 57 deletions
+13 -9
View File
@@ -179,7 +179,8 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
// TODO: Consider to always have a (non-null) AST.
static auto GenerateAst(Context& context, llvm::StringRef importing_file_path,
llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs)
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
llvm::StringRef target)
-> std::pair<std::unique_ptr<clang::ASTUnit>, bool> {
// TODO: Use all import locations by referring each Clang diagnostic to the
// relevant import.
@@ -190,9 +191,12 @@ static auto GenerateAst(Context& context, llvm::StringRef importing_file_path,
// TODO: Share compilation flags with ClangRunner.
auto ast = clang::tooling::buildASTFromCodeWithArgs(
GenerateCppIncludesHeaderCode(context, imports),
// Parse C++ (and not C)
{"-x", "c++"}, (importing_file_path + ".generated.cpp_imports.h").str(),
"clang-tool", std::make_shared<clang::PCHContainerOperations>(),
// Parse C++ (and not C).
{"-x", "c++",
// Propagate the target to Clang.
"-target", target.str()},
(importing_file_path + ".generated.cpp_imports.h").str(), "clang-tool",
std::make_shared<clang::PCHContainerOperations>(),
clang::tooling::getClangStripDependencyFileAdjuster(),
clang::tooling::FileContentMappings(), &diagnostics_consumer, fs);
// Remove link to the diagnostics consumer before its deletion.
@@ -235,8 +239,8 @@ static auto AddNamespace(Context& context, PackageNameId cpp_package_id,
auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path,
llvm::ArrayRef<Parse::Tree::PackagingNames> imports,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs)
-> std::unique_ptr<clang::ASTUnit> {
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
llvm::StringRef target) -> std::unique_ptr<clang::ASTUnit> {
if (imports.empty()) {
return nullptr;
}
@@ -244,7 +248,7 @@ auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path,
CARBON_CHECK(!context.sem_ir().cpp_ast());
auto [generated_ast, ast_has_error] =
GenerateAst(context, importing_file_path, imports, fs);
GenerateAst(context, importing_file_path, imports, fs, target);
PackageNameId package_id = imports.front().package_id;
CARBON_CHECK(
@@ -422,7 +426,7 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id,
static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
SemIR::NameScopeId scope_id,
SemIR::NameId name_id,
const clang::FunctionDecl* clang_decl)
clang::FunctionDecl* clang_decl)
-> SemIR::InstId {
if (clang_decl->isVariadic()) {
context.TODO(loc_id, "Unsupported: Variadic function");
@@ -603,7 +607,7 @@ static auto ImportCXXRecordDecl(Context& context, SemIR::LocId loc_id,
static auto ImportNameDecl(Context& context, SemIR::LocId loc_id,
SemIR::NameScopeId scope_id, SemIR::NameId name_id,
clang::NamedDecl* clang_decl) -> SemIR::InstId {
if (const auto* clang_function_decl =
if (auto* clang_function_decl =
clang::dyn_cast<clang::FunctionDecl>(clang_decl)) {
return ImportFunctionDecl(context, loc_id, scope_id, name_id,
clang_function_decl);