Skip to content

Commit 844ad0f

Browse files
committed
Generate AST when importing cpp files
Ignore the AST, for now. Report cpp compilation errors and warnings. Part of #4666
1 parent d42128e commit 844ad0f

File tree

13 files changed

+372
-16
lines changed

13 files changed

+372
-16
lines changed

toolchain/check/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ cc_library(
2626
"global_init.cpp",
2727
"impl_lookup.cpp",
2828
"import.cpp",
29+
"import_cpp.cpp",
2930
"import_ref.cpp",
3031
"inst_block_stack.cpp",
3132
"literal.cpp",
@@ -52,6 +53,7 @@ cc_library(
5253
"global_init.h",
5354
"impl_lookup.h",
5455
"import.h",
56+
"import_cpp.h",
5557
"import_ref.h",
5658
"inst_block_stack.h",
5759
"keyword_modifier_set.h",
@@ -88,6 +90,8 @@ cc_library(
8890
"//toolchain/sem_ir:formatter",
8991
"//toolchain/sem_ir:inst",
9092
"//toolchain/sem_ir:typed_insts",
93+
"@llvm-project//clang:frontend",
94+
"@llvm-project//clang:tooling",
9195
"@llvm-project//llvm:Support",
9296
],
9397
)

toolchain/check/check.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,20 @@ static auto TrackImport(Map<ImportKey, UnitAndImports*>& api_map,
6666

6767
IdentifierId file_package_id =
6868
packaging ? packaging->names.package_id : IdentifierId::Invalid;
69-
auto import_key = GetImportKey(unit_info, file_package_id, import);
69+
const auto import_key = GetImportKey(unit_info, file_package_id, import);
70+
const auto& [import_package_name, import_library_name] = import_key;
7071

7172
// True if the import has `Main` as the package name, even if it comes from
7273
// the file's packaging (diagnostics may differentiate).
73-
bool is_explicit_main = import_key.first == MainPackageName;
74+
bool is_explicit_main = import_package_name == MainPackageName;
75+
76+
bool is_cpp =
77+
import_package_name == CppPackageName && !import_library_name.empty();
78+
79+
if (is_cpp) {
80+
unit_info.cpp_imports.push_back(import);
81+
return;
82+
}
7483

7584
// Explicit imports need more validation than implicit ones. We try to do
7685
// these in an order of imports that should be removed, followed by imports
@@ -185,7 +194,7 @@ static auto TrackImport(Map<ImportKey, UnitAndImports*>& api_map,
185194
} else {
186195
// The imported api is missing.
187196
package_imports.has_load_error = true;
188-
if (!explicit_import_map && import_key.first == CppPackageName) {
197+
if (!explicit_import_map && import_package_name == CppPackageName) {
189198
// Don't diagnose the implicit import in `impl package Cpp`, because we'll
190199
// have diagnosed the use of `Cpp` in the declaration.
191200
return;
@@ -295,6 +304,7 @@ static auto BuildApiMapAndDiagnosePackaging(
295304
}
296305

297306
auto CheckParseTrees(llvm::MutableArrayRef<Unit> units, bool prelude_import,
307+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
298308
llvm::raw_ostream* vlog_stream) -> void {
299309
// UnitAndImports is big due to its SmallVectors, so we default to 0 on the
300310
// stack.
@@ -350,7 +360,7 @@ auto CheckParseTrees(llvm::MutableArrayRef<Unit> units, bool prelude_import,
350360
for (int check_index = 0;
351361
check_index < static_cast<int>(ready_to_check.size()); ++check_index) {
352362
auto* unit_info = ready_to_check[check_index];
353-
CheckUnit(unit_info, units.size(), vlog_stream).Run();
363+
CheckUnit(unit_info, units.size(), fs, vlog_stream).Run();
354364
for (auto* incoming_import : unit_info->incoming_imports) {
355365
--incoming_import->imports_remaining;
356366
if (incoming_import->imports_remaining == 0) {
@@ -397,7 +407,7 @@ auto CheckParseTrees(llvm::MutableArrayRef<Unit> units, bool prelude_import,
397407
// incomplete imports.
398408
for (auto& unit_info : unit_infos) {
399409
if (unit_info.imports_remaining > 0) {
400-
CheckUnit(&unit_info, units.size(), vlog_stream).Run();
410+
CheckUnit(&unit_info, units.size(), fs, vlog_stream).Run();
401411
}
402412
}
403413
}

toolchain/check/check.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct Unit {
3737
// Checks a group of parse trees. This will use imports to decide the order of
3838
// checking.
3939
auto CheckParseTrees(llvm::MutableArrayRef<Unit> units, bool prelude_import,
40+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
4041
llvm::raw_ostream* vlog_stream) -> void;
4142

4243
} // namespace Carbon::Check

toolchain/check/check_unit.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@
44

55
#include "toolchain/check/check_unit.h"
66

7+
#include <string>
8+
9+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
10+
#include "llvm/ADT/StringRef.h"
11+
#include "llvm/Support/VirtualFileSystem.h"
712
#include "toolchain/base/kind_switch.h"
813
#include "toolchain/base/pretty_stack_trace_function.h"
914
#include "toolchain/check/generic.h"
1015
#include "toolchain/check/handle.h"
1116
#include "toolchain/check/impl.h"
1217
#include "toolchain/check/import.h"
18+
#include "toolchain/check/import_cpp.h"
1319
#include "toolchain/check/import_ref.h"
1420
#include "toolchain/check/node_id_traversal.h"
1521

@@ -29,9 +35,11 @@ static auto GetImportedIRCount(UnitAndImports* unit_and_imports) -> int {
2935
}
3036

3137
CheckUnit::CheckUnit(UnitAndImports* unit_and_imports, int total_ir_count,
38+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
3239
llvm::raw_ostream* vlog_stream)
3340
: unit_and_imports_(unit_and_imports),
3441
total_ir_count_(total_ir_count),
42+
fs_(std::move(fs)),
3543
vlog_stream_(vlog_stream),
3644
emitter_(*unit_and_imports_->unit->sem_ir_converter,
3745
unit_and_imports_->err_tracker),
@@ -130,6 +138,7 @@ auto CheckUnit::InitPackageScopeAndImports() -> void {
130138
ImportCurrentPackage(package_inst_id, namespace_type_id);
131139
CARBON_CHECK(context_.scope_stack().PeekIndex() == ScopeIndex::Package);
132140
ImportOtherPackages(namespace_type_id);
141+
ImportCppPackages();
133142
}
134143

135144
auto CheckUnit::CollectDirectImports(
@@ -325,6 +334,37 @@ auto CheckUnit::ImportOtherPackages(SemIR::TypeId namespace_type_id) -> void {
325334
}
326335
}
327336

337+
auto CheckUnit::ImportCppPackages() -> void {
338+
for (const auto& import : unit_and_imports_->cpp_imports) {
339+
llvm::StringRef cpp_file_path =
340+
unit_and_imports_->unit->value_stores->string_literal_values().Get(
341+
import.library_id);
342+
343+
auto file = fs_->openFileForRead(cpp_file_path);
344+
if (!file) {
345+
CARBON_DIAGNOSTIC(CppInteropFileNotFound, Error,
346+
"file '{0}' couldn't be opened for reading: {1}",
347+
std::string, std::string);
348+
emitter_.Emit(import.node_id, CppInteropFileNotFound, cpp_file_path.str(),
349+
file.getError().message());
350+
continue;
351+
}
352+
353+
llvm::vfs::File& file_ref = *file.get();
354+
auto buffer = file_ref.getBuffer(cpp_file_path);
355+
if (!buffer) {
356+
CARBON_DIAGNOSTIC(CppInteropFailedAccessingFileBuffer, Error,
357+
"failed accessing buffer of file '{0}': {1}",
358+
std::string, std::string);
359+
emitter_.Emit(import.node_id, CppInteropFailedAccessingFileBuffer,
360+
cpp_file_path.str(), buffer.getError().message());
361+
continue;
362+
}
363+
ImportCppFile(context_, import.node_id, cpp_file_path,
364+
buffer.get()->getBuffer());
365+
}
366+
}
367+
328368
// Loops over all nodes in the tree. On some errors, this may return early,
329369
// for example if an unrecoverable state is encountered.
330370
// NOLINTNEXTLINE(readability-function-size)

toolchain/check/check_unit.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ struct UnitAndImports {
7474
// A map of the package names to the outgoing imports above.
7575
Map<IdentifierId, int32_t> package_imports_map;
7676

77+
// List of the `import Cpp` imports.
78+
llvm::SmallVector<Parse::Tree::PackagingNames> cpp_imports;
79+
7780
// The remaining number of imports which must be checked before this unit can
7881
// be processed.
7982
int32_t imports_remaining = 0;
@@ -98,6 +101,7 @@ struct UnitAndImports {
98101
class CheckUnit {
99102
public:
100103
explicit CheckUnit(UnitAndImports* unit_and_imports, int total_ir_count,
104+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
101105
llvm::raw_ostream* vlog_stream);
102106

103107
// Produces and checks the IR for the provided unit.
@@ -125,9 +129,12 @@ class CheckUnit {
125129
auto ImportCurrentPackage(SemIR::InstId package_inst_id,
126130
SemIR::TypeId namespace_type_id) -> void;
127131

128-
// Imports all other packages (excluding the current package).
132+
// Imports all other Carbon packages (excluding the current package).
129133
auto ImportOtherPackages(SemIR::TypeId namespace_type_id) -> void;
130134

135+
// Imports all C++ packages.
136+
auto ImportCppPackages() -> void;
137+
131138
// Checks that each required definition is available. If the definition can be
132139
// generated by resolving a specific, does so, otherwise emits a diagnostic
133140
// for each declaration in context.definitions_required() that doesn't have a
@@ -142,6 +149,7 @@ class CheckUnit {
142149
UnitAndImports* unit_and_imports_;
143150
// The number of IRs being checked in total.
144151
int total_ir_count_;
152+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs_;
145153
llvm::raw_ostream* vlog_stream_;
146154

147155
Context::DiagnosticEmitter emitter_;

toolchain/check/import_cpp.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2+
// Exceptions. See /LICENSE for license information.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#include "toolchain/check/import_cpp.h"
6+
7+
#include <memory>
8+
#include <string>
9+
10+
#include "clang/Frontend/TextDiagnosticPrinter.h"
11+
#include "clang/Tooling/Tooling.h"
12+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
13+
#include "llvm/ADT/StringRef.h"
14+
#include "llvm/Support/raw_ostream.h"
15+
#include "toolchain/check/context.h"
16+
#include "toolchain/check/diagnostic_helpers.h"
17+
#include "toolchain/diagnostics/diagnostic.h"
18+
#include "toolchain/diagnostics/format_providers.h"
19+
20+
namespace Carbon::Check {
21+
22+
auto ImportCppFile(Context& context, SemIRLoc loc, llvm::StringRef file_path,
23+
llvm::StringRef code) -> void {
24+
std::string diagnostics_str;
25+
llvm::raw_string_ostream diagnostics_stream(diagnostics_str);
26+
27+
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnostic_options(
28+
new clang::DiagnosticOptions());
29+
clang::TextDiagnosticPrinter diagnostics_consumer(diagnostics_stream,
30+
diagnostic_options.get());
31+
// TODO: Share compilation flags with ClangRunner.
32+
auto ast = clang::tooling::buildASTFromCodeWithArgs(
33+
code, {}, file_path, "clang-tool",
34+
std::make_shared<clang::PCHContainerOperations>(),
35+
clang::tooling::getClangStripDependencyFileAdjuster(),
36+
clang::tooling::FileContentMappings(), &diagnostics_consumer);
37+
// TODO: Implement and use a DynamicRecursiveASTVisitor to traverse the AST.
38+
int num_errors = diagnostics_consumer.getNumErrors();
39+
int num_warnings = diagnostics_consumer.getNumWarnings();
40+
if (num_errors > 0) {
41+
// TODO: Remove the warnings part when there are no warnings.
42+
CARBON_DIAGNOSTIC(
43+
CppInteropCodeErrors, Error,
44+
"{0} error{0:s} and {1} warning{1:s} in C++ file '{2}':\n{3}",
45+
IntAsSelect, IntAsSelect, std::string, std::string);
46+
context.emitter().Emit(loc, CppInteropCodeErrors, num_errors, num_warnings,
47+
file_path.str(), diagnostics_str);
48+
} else if (num_warnings > 0) {
49+
CARBON_DIAGNOSTIC(CppInteropCodeWarnings, Warning,
50+
"{0} warning{0:s} in C++ file '{1}':\n{2}", IntAsSelect,
51+
std::string, std::string);
52+
context.emitter().Emit(loc, CppInteropCodeWarnings, num_warnings,
53+
file_path.str(), diagnostics_str);
54+
}
55+
}
56+
57+
} // namespace Carbon::Check

toolchain/check/import_cpp.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
2+
// Exceptions. See /LICENSE for license information.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#ifndef CARBON_TOOLCHAIN_CHECK_IMPORT_CPP_H_
6+
#define CARBON_TOOLCHAIN_CHECK_IMPORT_CPP_H_
7+
8+
#include "llvm/ADT/StringRef.h"
9+
#include "toolchain/check/context.h"
10+
#include "toolchain/check/diagnostic_helpers.h"
11+
12+
namespace Carbon::Check {
13+
14+
// Parses the C++ code and report errors and warnings.
15+
auto ImportCppFile(Context& context, SemIRLoc loc, llvm::StringRef file_path,
16+
llvm::StringRef code) -> void;
17+
18+
} // namespace Carbon::Check
19+
20+
#endif // CARBON_TOOLCHAIN_CHECK_IMPORT_CPP_H_

0 commit comments

Comments
 (0)