-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for importing a trivial global C++ function #5033
Changes from 1 commit
9358e9d
afd4441
a1cf815
ddb345b
2ffec0e
b6b93aa
a216d6c
b12945e
b369be6
63701ab
3ec0ec8
29e1548
30881c1
b7e5bc4
0384049
2c59d1d
4cf320d
16867c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
#include <string> | ||
|
||
#include "clang/Frontend/TextDiagnosticPrinter.h" | ||
#include "clang/Sema/Lookup.h" | ||
#include "clang/Tooling/Tooling.h" | ||
#include "common/raw_string_ostream.h" | ||
#include "llvm/ADT/IntrusiveRefCntPtr.h" | ||
|
@@ -61,7 +62,9 @@ static auto GenerateAst(Context& context, llvm::StringRef importing_file_path, | |
diagnostic_options.get()); | ||
// TODO: Share compilation flags with ClangRunner. | ||
auto ast = clang::tooling::buildASTFromCodeWithArgs( | ||
GenerateCppIncludesHeaderCode(context, imports), {}, | ||
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>(), | ||
clang::tooling::getClangStripDependencyFileAdjuster(), | ||
|
@@ -113,14 +116,19 @@ static auto AddNamespace(Context& context, PackageNameId cpp_package_id, | |
} | ||
|
||
auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, | ||
std::unique_ptr<clang::ASTUnit>* ast, | ||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
llvm::ArrayRef<Parse::Tree::PackagingNames> imports, | ||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs) | ||
-> void { | ||
if (imports.empty()) { | ||
return; | ||
} | ||
|
||
auto [ast, ast_has_error] = | ||
CARBON_CHECK(ast); | ||
CARBON_CHECK(!ast->get()); | ||
CARBON_CHECK(!context.sem_ir().cpp_ast()); | ||
|
||
auto [generated_ast, ast_has_error] = | ||
GenerateAst(context, importing_file_path, imports, fs); | ||
|
||
PackageNameId package_id = imports.front().package_id; | ||
|
@@ -131,10 +139,146 @@ auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, | |
auto name_scope_id = AddNamespace(context, package_id, imports); | ||
SemIR::NameScope& name_scope = context.name_scopes().Get(name_scope_id); | ||
name_scope.set_is_closed_import(true); | ||
name_scope.set_is_cpp_scope(true); | ||
|
||
*ast = std::move(generated_ast); | ||
context.sem_ir().set_cpp_ast(ast->get()); | ||
|
||
if (ast_has_error) { | ||
name_scope.set_has_error(); | ||
} | ||
} | ||
|
||
static auto ClangLookup(Context& context, SemIR::NameId name_id) | ||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
-> std::optional<clang::LookupResult> { | ||
clang::ASTUnit* ast = context.sem_ir().cpp_ast(); | ||
CARBON_CHECK(ast); | ||
CARBON_CHECK(ast->hasSema()); | ||
clang::Sema& sema = ast->getSema(); | ||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
auto name = context.names().GetAsStringIfIdentifier(name_id); | ||
CARBON_CHECK(name); | ||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if we try to look up a non-identifier Carbon name, such as via There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a test and now using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My general understanding is we want to require raw keyword syntax in this sort of situation: i.e., There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
|
||
clang::LookupResult lookup( | ||
sema, | ||
clang::DeclarationNameInfo( | ||
clang::DeclarationName( | ||
sema.getPreprocessor().getIdentifierInfo(*name)), | ||
clang::SourceLocation()), | ||
clang::Sema::LookupNameKind::LookupOrdinaryName); | ||
|
||
if (!sema.LookupQualifiedName( | ||
lookup, ast->getASTContext().getTranslationUnitDecl())) { | ||
return std::nullopt; | ||
} | ||
|
||
return lookup; | ||
} | ||
|
||
static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, | ||
SemIR::NameScopeId scope_id, | ||
SemIR::NameId name_id, | ||
const clang::FunctionDecl* clang_decl) | ||
-> SemIR::InstId { | ||
if (clang_decl->isVariadic()) { | ||
context.TODO(loc_id, "Unsupported: Variadic function"); | ||
return SemIR::InstId::None; | ||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
if (!clang_decl->isGlobal()) { | ||
context.TODO(loc_id, "Unsupported: Non-global function"); | ||
return SemIR::InstId::None; | ||
} | ||
if (clang_decl->getTemplatedKind() != clang::FunctionDecl::TK_NonTemplate) { | ||
context.TODO(loc_id, "Unsupported: Template function"); | ||
return SemIR::InstId::None; | ||
} | ||
if (!clang_decl->param_empty()) { | ||
context.TODO(loc_id, "Unsupported: Function with parameters"); | ||
return SemIR::InstId::None; | ||
} | ||
if (!clang_decl->getReturnType()->isVoidType()) { | ||
context.TODO(loc_id, "Unsupported: Function with non-void return type"); | ||
return SemIR::InstId::None; | ||
} | ||
|
||
auto function_decl = SemIR::FunctionDecl{ | ||
SemIR::TypeId::None, SemIR::FunctionId::None, SemIR::InstBlockId::Empty}; | ||
auto decl_id = AddPlaceholderInst( | ||
context, SemIR::LocIdAndInst(Parse::NodeId::None, function_decl)); | ||
|
||
auto function_info = SemIR::Function{ | ||
SemIR::EntityWithParamsBase{ | ||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.name_id = name_id, | ||
.parent_scope_id = scope_id, | ||
.generic_id = SemIR::GenericId::None, | ||
.first_param_node_id = Parse::NodeId::None, | ||
.last_param_node_id = Parse::NodeId::None, | ||
.pattern_block_id = SemIR::InstBlockId::Empty, | ||
.implicit_param_patterns_id = SemIR::InstBlockId::Empty, | ||
.param_patterns_id = SemIR::InstBlockId::Empty, | ||
.call_params_id = SemIR::InstBlockId::Empty, | ||
.is_extern = false, | ||
.extern_library_id = SemIR::LibraryNameId ::None, | ||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.non_owning_decl_id = SemIR::InstId::None, | ||
.first_owning_decl_id = decl_id, | ||
.definition_id = SemIR::InstId::None}, | ||
SemIR::FunctionFields{ | ||
.return_slot_pattern_id = SemIR::InstId::None, | ||
.virtual_modifier = SemIR::FunctionFields::VirtualModifier::None, | ||
.self_param_id = SemIR::InstId::None}}; | ||
|
||
function_decl.function_id = context.functions().Add(function_info); | ||
|
||
function_decl.type_id = GetFunctionType(context, function_decl.function_id, | ||
SemIR::SpecificId::None); | ||
|
||
ReplaceInstBeforeConstantUse(context, decl_id, function_decl); | ||
|
||
return decl_id; | ||
} | ||
|
||
static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, | ||
SemIR::NameScopeId scope_id, SemIR::NameId name_id, | ||
const clang::NamedDecl* clang_decl) | ||
-> SemIR::InstId { | ||
if (const auto* clang_function_decl = | ||
clang::dyn_cast<clang::FunctionDecl>(clang_decl)) { | ||
return ImportFunctionDecl(context, loc_id, scope_id, name_id, | ||
clang_function_decl); | ||
} | ||
|
||
context.TODO(loc_id, llvm::formatv("Unsupported: Declaration type {0}", | ||
clang_decl->getDeclKindName()) | ||
.str()); | ||
return SemIR::InstId::None; | ||
} | ||
|
||
auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, | ||
SemIR::NameScopeId scope_id, SemIR::NameId name_id) | ||
-> SemIR::InstId { | ||
auto lookup = ClangLookup(context, name_id); | ||
if (!lookup) { | ||
return SemIR::InstId::None; | ||
} | ||
|
||
DiagnosticAnnotationScope annotate_diagnostics( | ||
&context.emitter(), [&](auto& builder) { | ||
CARBON_DIAGNOSTIC(InCppNameLookup, Note, | ||
"in `Cpp` name lookup for `{0}`", SemIR::NameId); | ||
builder.Note(loc_id, InCppNameLookup, name_id); | ||
}); | ||
|
||
if (!lookup->isSingleResult()) { | ||
context.TODO(loc_id, | ||
llvm::formatv("Unsupported: Lookup succeeded but couldn't " | ||
"find a single result; LookupResultKind: {0}", | ||
lookup->getResultKind()) | ||
.str()); | ||
return SemIR::InstId::None; | ||
} | ||
|
||
return ImportNameDecl(context, loc_id, scope_id, name_id, | ||
lookup->getFoundDecl()); | ||
} | ||
|
||
} // namespace Carbon::Check |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per style: "Only use line comments (with //, not /* ... */), on a line by themselves"
https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/cpp_style_guide.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.