mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
When using a C++ struct as a parameter, map its type to a Carbon class type (#5538)
This doesn't support actually passing the value of the struct, which is planned to be implemented using thunks. `ClangDeclId` value is now `ClangDecl` which includes the mapped Carbon instruction in addition to the Clang declaration. This allows finding the Carbon instruction for a given Clang declaration, which is necessary for mapping a Clang struct parameter type to the Carbon class without doing name lookup. We don't take the instruction as part of the hash key, as discussed in [Discord](https://discord.com/channels/655572317891461132/768530752592805919/1380575881050718469). To map the type, we also need to map namespaces. To avoid recursion for inner namespaces, we use a vector. Note that the first commit just changes the order of functions in the file to make review easier. C++ Interop Demo (that shows missing behavior): ```c++ // hello_world.h struct S { S(const S&) { x = 1; } int x; }; void hello_world(S s); ``` ```c++ // hello_world.cpp #include "hello_world.h" #include <cstdio> void hello_world2(S s) { printf("hello_world2: %d\n", s.x); } void hello_world(S s) { printf("hello_world: %d\n", s.x); hello_world2(s); } ``` ```carbon // main.carbon library "Main"; import Cpp library "hello_world.h"; fn Run() -> i32 { var s : Cpp.S; Cpp.hello_world(s); return 0; } ``` ```shell $ clang -c hello_world.cpp $ bazel-bin/toolchain/carbon compile main.carbon $ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo $ ./demo hello_world: -1108224096 hello_world2: 1 ``` Part of #5533.
This commit is contained in:
+273
-143
@@ -52,7 +52,21 @@ static auto GenerateCppIncludesHeaderCode(
|
||||
return code;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Adds the name to the scope with the given `inst_id`, if the `inst_id` is not
|
||||
// `None`.
|
||||
static auto AddNameToScope(Context& context, SemIR::NameScopeId scope_id,
|
||||
SemIR::NameId name_id, SemIR::InstId inst_id)
|
||||
-> void {
|
||||
if (inst_id.has_value()) {
|
||||
context.name_scopes().AddRequiredName(scope_id, name_id, inst_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Maps a Clang name to a Carbon `NameId`.
|
||||
static auto AddIdentifierName(Context& context, llvm::StringRef name)
|
||||
-> SemIR::NameId {
|
||||
return SemIR::NameId::ForIdentifier(context.identifiers().Add(name));
|
||||
}
|
||||
|
||||
// Adds the given source location and an `ImportIRInst` referring to it in
|
||||
// `ImportIRId::Cpp`.
|
||||
@@ -65,6 +79,8 @@ static auto AddImportIRInst(Context& context,
|
||||
SemIR::ImportIRInst(clang_source_loc_id));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Used to convert Clang diagnostics to Carbon diagnostics.
|
||||
class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
|
||||
public:
|
||||
@@ -255,7 +271,8 @@ auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path,
|
||||
SemIR::NameScope& name_scope = context.name_scopes().Get(name_scope_id);
|
||||
name_scope.set_is_closed_import(true);
|
||||
name_scope.set_clang_decl_context_id(context.sem_ir().clang_decls().Add(
|
||||
generated_ast->getASTContext().getTranslationUnitDecl()));
|
||||
{.decl = generated_ast->getASTContext().getTranslationUnitDecl(),
|
||||
.inst_id = name_scope.inst_id()}));
|
||||
|
||||
if (ast_has_error) {
|
||||
name_scope.set_has_error();
|
||||
@@ -292,10 +309,14 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id,
|
||||
// `TextDiagnosticPrinter` assumes we're processing a C++ source file.
|
||||
lookup.suppressDiagnostics();
|
||||
|
||||
auto scope_clang_decl_context_id =
|
||||
context.name_scopes().Get(scope_id).clang_decl_context_id();
|
||||
bool found = sema.LookupQualifiedName(
|
||||
lookup,
|
||||
clang::dyn_cast<clang::DeclContext>(context.sem_ir().clang_decls().Get(
|
||||
context.name_scopes().Get(scope_id).clang_decl_context_id())));
|
||||
clang::dyn_cast<clang::DeclContext>(context.sem_ir()
|
||||
.clang_decls()
|
||||
.Get(scope_clang_decl_context_id)
|
||||
.decl));
|
||||
|
||||
if (!found) {
|
||||
return std::nullopt;
|
||||
@@ -304,6 +325,174 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id,
|
||||
return lookup;
|
||||
}
|
||||
|
||||
// Imports a namespace declaration from Clang to Carbon. If successful, returns
|
||||
// the new Carbon namespace declaration `InstId`.
|
||||
static auto ImportNamespaceDecl(Context& context,
|
||||
SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::NamespaceDecl* clang_decl)
|
||||
-> SemIR::InstId {
|
||||
auto result = AddImportNamespace(
|
||||
context, GetSingletonType(context, SemIR::NamespaceType::TypeInstId),
|
||||
name_id, parent_scope_id, /*import_id=*/SemIR::InstId::None);
|
||||
context.name_scopes()
|
||||
.Get(result.name_scope_id)
|
||||
.set_clang_decl_context_id(context.sem_ir().clang_decls().Add(
|
||||
{.decl = clang_decl, .inst_id = result.inst_id}));
|
||||
return result.inst_id;
|
||||
}
|
||||
|
||||
// Maps a C++ declaration context to a Carbon namespace.
|
||||
static auto AsCarbonNamespace(Context& context,
|
||||
clang::DeclContext* decl_context)
|
||||
-> SemIR::InstId {
|
||||
CARBON_CHECK(decl_context);
|
||||
auto& clang_decls = context.sem_ir().clang_decls();
|
||||
|
||||
// Check if the decl context is already mapped to a Carbon namespace.
|
||||
if (auto context_clang_decl_id = clang_decls.Lookup(
|
||||
{.decl = clang::dyn_cast<clang::Decl>(decl_context),
|
||||
.inst_id = SemIR::InstId::None});
|
||||
context_clang_decl_id.has_value()) {
|
||||
return clang_decls.Get(context_clang_decl_id).inst_id;
|
||||
}
|
||||
|
||||
// We know we have at least one context to map, add all decl contexts we need
|
||||
// to map.
|
||||
llvm::SmallVector<clang::DeclContext*> decl_contexts;
|
||||
auto parent_decl_id = SemIR::ClangDeclId::None;
|
||||
do {
|
||||
decl_contexts.push_back(decl_context);
|
||||
decl_context = decl_context->getParent();
|
||||
parent_decl_id =
|
||||
clang_decls.Lookup({.decl = clang::dyn_cast<clang::Decl>(decl_context),
|
||||
.inst_id = SemIR::InstId::None});
|
||||
} while (!parent_decl_id.has_value());
|
||||
|
||||
// We know the parent of the last decl context is mapped, map the rest.
|
||||
auto namespace_inst_id = SemIR::InstId::None;
|
||||
do {
|
||||
decl_context = decl_contexts.pop_back_val();
|
||||
auto parent_inst_id = clang_decls.Get(parent_decl_id).inst_id;
|
||||
auto parent_namespace =
|
||||
context.insts().GetAs<SemIR::Namespace>(parent_inst_id);
|
||||
namespace_inst_id = ImportNamespaceDecl(
|
||||
context, parent_namespace.name_scope_id,
|
||||
AddIdentifierName(
|
||||
context, llvm::dyn_cast<clang::NamedDecl>(decl_context)->getName()),
|
||||
clang::dyn_cast<clang::NamespaceDecl>(decl_context));
|
||||
parent_decl_id = clang_decls.Add({
|
||||
.decl = clang::dyn_cast<clang::Decl>(decl_context),
|
||||
.inst_id = namespace_inst_id,
|
||||
});
|
||||
} while (!decl_contexts.empty());
|
||||
|
||||
return namespace_inst_id;
|
||||
}
|
||||
|
||||
// Creates a class declaration for the given class name in the given scope.
|
||||
// Returns the `InstId` for the declaration.
|
||||
static auto BuildClassDecl(Context& context, SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id)
|
||||
-> std::tuple<SemIR::ClassId, SemIR::InstId> {
|
||||
// Add the class declaration.
|
||||
auto class_decl = SemIR::ClassDecl{.type_id = SemIR::TypeType::TypeId,
|
||||
.class_id = SemIR::ClassId::None,
|
||||
.decl_block_id = SemIR::InstBlockId::None};
|
||||
// TODO: Consider setting a proper location.
|
||||
auto class_decl_id = AddPlaceholderInstInNoBlock(
|
||||
context, SemIR::LocIdAndInst::NoLoc(class_decl));
|
||||
context.imports().push_back(class_decl_id);
|
||||
|
||||
SemIR::Class class_info = {
|
||||
{.name_id = name_id,
|
||||
.parent_scope_id = parent_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::None,
|
||||
.implicit_param_patterns_id = SemIR::InstBlockId::None,
|
||||
.param_patterns_id = SemIR::InstBlockId::None,
|
||||
.is_extern = false,
|
||||
.extern_library_id = SemIR::LibraryNameId::None,
|
||||
.non_owning_decl_id = SemIR::InstId::None,
|
||||
.first_owning_decl_id = class_decl_id},
|
||||
{// `.self_type_id` depends on the ClassType, so is set below.
|
||||
.self_type_id = SemIR::TypeId::None,
|
||||
// TODO: Support Dynamic classes.
|
||||
// TODO: Support Final classes.
|
||||
.inheritance_kind = SemIR::Class::Base}};
|
||||
|
||||
class_decl.class_id = context.classes().Add(class_info);
|
||||
|
||||
// Write the class ID into the ClassDecl.
|
||||
ReplaceInstBeforeConstantUse(context, class_decl_id, class_decl);
|
||||
|
||||
SetClassSelfType(context, class_decl.class_id);
|
||||
|
||||
return {class_decl.class_id, class_decl_id};
|
||||
}
|
||||
|
||||
// Creates a class definition for the given class name in the given scope based
|
||||
// on the information in the given Clang declaration. Returns the `InstId` for
|
||||
// the declaration, which is assumed to be for a class definition. Returns the
|
||||
// new class id and instruction id.
|
||||
static auto BuildClassDefinition(Context& context,
|
||||
SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* clang_decl)
|
||||
-> std::tuple<SemIR::ClassId, SemIR::InstId> {
|
||||
auto [class_id, class_inst_id] =
|
||||
BuildClassDecl(context, parent_scope_id, name_id);
|
||||
auto& class_info = context.classes().Get(class_id);
|
||||
StartClassDefinition(context, class_info, class_inst_id);
|
||||
|
||||
context.name_scopes()
|
||||
.Get(class_info.scope_id)
|
||||
.set_clang_decl_context_id(context.sem_ir().clang_decls().Add(
|
||||
{.decl = clang_decl, .inst_id = class_inst_id}));
|
||||
|
||||
return {class_id, class_inst_id};
|
||||
}
|
||||
|
||||
// Imports a record declaration from Clang to Carbon. If successful, returns
|
||||
// the new Carbon class declaration `InstId`.
|
||||
// TODO: Change `clang_decl` to `const &` when lookup is using `clang::DeclID`
|
||||
// and we don't need to store the decl for lookup context.
|
||||
static auto ImportCXXRecordDecl(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* clang_decl)
|
||||
-> SemIR::InstId {
|
||||
clang::CXXRecordDecl* clang_def = clang_decl->getDefinition();
|
||||
if (!clang_def) {
|
||||
context.TODO(loc_id,
|
||||
"Unsupported: Record declarations without a definition");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
if (clang_def->isDynamicClass()) {
|
||||
context.TODO(loc_id, "Unsupported: Dynamic Class");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
auto [class_id, class_def_id] =
|
||||
BuildClassDefinition(context, parent_scope_id, name_id, clang_def);
|
||||
|
||||
// The class type is now fully defined. Compute its object representation.
|
||||
ComputeClassObjectRepr(context,
|
||||
// TODO: Consider having a proper location here.
|
||||
Parse::ClassDefinitionId::None, class_id,
|
||||
// TODO: Set fields.
|
||||
/*field_decls=*/{},
|
||||
// TODO: Set vtable.
|
||||
/*vtable_contents=*/{},
|
||||
// TODO: Set block.
|
||||
/*body=*/{});
|
||||
|
||||
return class_def_id;
|
||||
}
|
||||
|
||||
// Creates an integer type of the given size.
|
||||
static auto MakeIntType(Context& context, IntId size_id) -> TypeExpr {
|
||||
// TODO: Fill in a location for the type once available.
|
||||
@@ -312,23 +501,19 @@ static auto MakeIntType(Context& context, IntId size_id) -> TypeExpr {
|
||||
return ExprAsType(context, Parse::NodeId::None, type_inst_id);
|
||||
}
|
||||
|
||||
// Maps a C++ type to a Carbon type.
|
||||
// TODO: Support more types.
|
||||
static auto MapType(Context& context, clang::QualType type) -> TypeExpr {
|
||||
const auto* builtin_type = dyn_cast<clang::BuiltinType>(type);
|
||||
if (!builtin_type) {
|
||||
return {.inst_id = SemIR::ErrorInst::TypeInstId,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
// Maps a C++ builtin type to a Carbon type.
|
||||
// TODO: Support more builtin types.
|
||||
static auto MapBuiltinType(Context& context, const clang::BuiltinType& type)
|
||||
-> TypeExpr {
|
||||
// TODO: Refactor to avoid duplication.
|
||||
switch (builtin_type->getKind()) {
|
||||
switch (type.getKind()) {
|
||||
case clang::BuiltinType::Short:
|
||||
if (context.ast_context().getTypeSize(type) == 16) {
|
||||
if (context.ast_context().getTypeSize(&type) == 16) {
|
||||
return MakeIntType(context, context.ints().Add(16));
|
||||
}
|
||||
break;
|
||||
case clang::BuiltinType::Int:
|
||||
if (context.ast_context().getTypeSize(type) == 32) {
|
||||
if (context.ast_context().getTypeSize(&type) == 32) {
|
||||
return MakeIntType(context, context.ints().Add(32));
|
||||
}
|
||||
break;
|
||||
@@ -339,6 +524,57 @@ static auto MapType(Context& context, clang::QualType type) -> TypeExpr {
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
// Maps a C++ record type to a Carbon type.
|
||||
// TODO: Support more record types.
|
||||
static auto MapRecordType(Context& context, SemIR::LocId loc_id,
|
||||
const clang::RecordType& type) -> TypeExpr {
|
||||
auto* record_decl = clang::dyn_cast<clang::CXXRecordDecl>(type.getDecl());
|
||||
if (record_decl && record_decl->isStruct()) {
|
||||
auto& clang_decls = context.sem_ir().clang_decls();
|
||||
SemIR::InstId struct_inst_id = SemIR::InstId::None;
|
||||
if (auto struct_clang_decl_id = clang_decls.Lookup(
|
||||
{.decl = record_decl, .inst_id = SemIR::InstId::None});
|
||||
struct_clang_decl_id.has_value()) {
|
||||
struct_inst_id = clang_decls.Get(struct_clang_decl_id).inst_id;
|
||||
} else {
|
||||
auto parent_inst_id =
|
||||
AsCarbonNamespace(context, record_decl->getDeclContext());
|
||||
auto parent_name_scope_id =
|
||||
context.insts().GetAs<SemIR::Namespace>(parent_inst_id).name_scope_id;
|
||||
SemIR::NameId struct_name_id =
|
||||
AddIdentifierName(context, record_decl->getName());
|
||||
struct_inst_id = ImportCXXRecordDecl(
|
||||
context, loc_id, parent_name_scope_id, struct_name_id, record_decl);
|
||||
AddNameToScope(context, parent_name_scope_id, struct_name_id,
|
||||
struct_inst_id);
|
||||
}
|
||||
SemIR::TypeInstId struct_type_inst_id =
|
||||
context.types().GetAsTypeInstId(struct_inst_id);
|
||||
return {
|
||||
.inst_id = struct_type_inst_id,
|
||||
.type_id = context.types().GetTypeIdForTypeInstId(struct_type_inst_id)};
|
||||
}
|
||||
|
||||
return {.inst_id = SemIR::ErrorInst::TypeInstId,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
// Maps a C++ type to a Carbon type.
|
||||
// TODO: Support more types.
|
||||
static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
-> TypeExpr {
|
||||
if (const auto* builtin_type = dyn_cast<clang::BuiltinType>(type)) {
|
||||
return MapBuiltinType(context, *builtin_type);
|
||||
}
|
||||
|
||||
if (const auto* record_type = clang::dyn_cast<clang::RecordType>(type)) {
|
||||
return MapRecordType(context, loc_id, *record_type);
|
||||
}
|
||||
|
||||
return {.inst_id = SemIR::ErrorInst::TypeInstId,
|
||||
.type_id = SemIR::ErrorInst::TypeId};
|
||||
}
|
||||
|
||||
// Returns a block id for the explicit parameters of the given function
|
||||
// declaration. If the function declaration has no parameters, it returns
|
||||
// `SemIR::InstBlockId::Empty`. In the case of an unsupported parameter type, it
|
||||
@@ -359,7 +595,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
|
||||
// Mark the start of a region of insts, needed for the type expression
|
||||
// created later with the call of `EndSubpatternAsExpr()`.
|
||||
BeginSubpattern(context);
|
||||
auto [type_inst_id, type_id] = MapType(context, param_type);
|
||||
auto [type_inst_id, type_id] = MapType(context, loc_id, param_type);
|
||||
// Type expression of the binding pattern - a single-entry/single-exit
|
||||
// region that allows control flow in the type expression e.g. fn F(x: if C
|
||||
// then i32 else i64).
|
||||
@@ -378,8 +614,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
|
||||
// Translate an unnamed parameter to an underscore to
|
||||
// match Carbon's naming of unnamed/unused function params.
|
||||
? SemIR::NameId::Underscore
|
||||
: SemIR::NameId::ForIdentifier(
|
||||
context.sem_ir().identifiers().Add(param_name));
|
||||
: AddIdentifierName(context, param_name);
|
||||
|
||||
// TODO: Fix this once templates are supported.
|
||||
bool is_template = false;
|
||||
@@ -413,7 +648,7 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id,
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
|
||||
auto [type_inst_id, type_id] = MapType(context, ret_type);
|
||||
auto [type_inst_id, type_id] = MapType(context, loc_id, ret_type);
|
||||
if (type_id == SemIR::ErrorInst::TypeId) {
|
||||
context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
|
||||
ret_type.getAsString()));
|
||||
@@ -531,7 +766,8 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
.return_slot_pattern_id = function_params_insts->return_slot_pattern_id,
|
||||
.virtual_modifier = SemIR::FunctionFields::VirtualModifier::None,
|
||||
.self_param_id = SemIR::InstId::None,
|
||||
.clang_decl_id = context.sem_ir().clang_decls().Add(clang_decl)}};
|
||||
.clang_decl_id = context.sem_ir().clang_decls().Add(
|
||||
{.decl = clang_decl, .inst_id = decl_id})}};
|
||||
|
||||
function_decl.function_id = context.functions().Add(function_info);
|
||||
|
||||
@@ -542,127 +778,6 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
return decl_id;
|
||||
}
|
||||
|
||||
// Imports a namespace declaration from Clang to Carbon. If successful, returns
|
||||
// the new Carbon namespace declaration `InstId`.
|
||||
static auto ImportNamespaceDecl(Context& context,
|
||||
SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::NamespaceDecl* clang_decl)
|
||||
-> SemIR::InstId {
|
||||
auto result = AddImportNamespace(
|
||||
context, GetSingletonType(context, SemIR::NamespaceType::TypeInstId),
|
||||
name_id, parent_scope_id, /*import_id=*/SemIR::InstId::None);
|
||||
context.name_scopes()
|
||||
.Get(result.name_scope_id)
|
||||
.set_clang_decl_context_id(
|
||||
context.sem_ir().clang_decls().Add(clang_decl));
|
||||
return result.inst_id;
|
||||
}
|
||||
|
||||
// Creates a class declaration for the given class name in the given scope.
|
||||
// Returns the `InstId` for the declaration.
|
||||
static auto BuildClassDecl(Context& context, SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id)
|
||||
-> std::tuple<SemIR::ClassId, SemIR::InstId> {
|
||||
// Add the class declaration.
|
||||
auto class_decl = SemIR::ClassDecl{.type_id = SemIR::TypeType::TypeId,
|
||||
.class_id = SemIR::ClassId::None,
|
||||
.decl_block_id = SemIR::InstBlockId::None};
|
||||
// TODO: Consider setting a proper location.
|
||||
auto class_decl_id = AddPlaceholderInstInNoBlock(
|
||||
context, SemIR::LocIdAndInst::NoLoc(class_decl));
|
||||
context.imports().push_back(class_decl_id);
|
||||
|
||||
SemIR::Class class_info = {
|
||||
{.name_id = name_id,
|
||||
.parent_scope_id = parent_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::None,
|
||||
.implicit_param_patterns_id = SemIR::InstBlockId::None,
|
||||
.param_patterns_id = SemIR::InstBlockId::None,
|
||||
.is_extern = false,
|
||||
.extern_library_id = SemIR::LibraryNameId::None,
|
||||
.non_owning_decl_id = SemIR::InstId::None,
|
||||
.first_owning_decl_id = class_decl_id},
|
||||
{// `.self_type_id` depends on the ClassType, so is set below.
|
||||
.self_type_id = SemIR::TypeId::None,
|
||||
// TODO: Support Dynamic classes.
|
||||
// TODO: Support Final classes.
|
||||
.inheritance_kind = SemIR::Class::Base}};
|
||||
|
||||
class_decl.class_id = context.classes().Add(class_info);
|
||||
|
||||
// Write the class ID into the ClassDecl.
|
||||
ReplaceInstBeforeConstantUse(context, class_decl_id, class_decl);
|
||||
|
||||
SetClassSelfType(context, class_decl.class_id);
|
||||
|
||||
return {class_decl.class_id, class_decl_id};
|
||||
}
|
||||
|
||||
// Creates a class definition for the given class name in the given scope based
|
||||
// on the information in the given Clang declaration. Returns the `InstId` for
|
||||
// the declaration, which is assumed to be for a class definition. Returns the
|
||||
// new class id and instruction id.
|
||||
static auto BuildClassDefinition(Context& context,
|
||||
SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* clang_decl)
|
||||
-> std::tuple<SemIR::ClassId, SemIR::InstId> {
|
||||
auto [class_id, class_decl_id] =
|
||||
BuildClassDecl(context, parent_scope_id, name_id);
|
||||
auto& class_info = context.classes().Get(class_id);
|
||||
StartClassDefinition(context, class_info, class_decl_id);
|
||||
|
||||
context.name_scopes()
|
||||
.Get(class_info.scope_id)
|
||||
.set_clang_decl_context_id(
|
||||
context.sem_ir().clang_decls().Add(clang_decl));
|
||||
|
||||
return {class_id, class_decl_id};
|
||||
}
|
||||
|
||||
// Imports a record declaration from Clang to Carbon. If successful, returns
|
||||
// the new Carbon class declaration `InstId`.
|
||||
// TODO: Change `clang_decl` to `const &` when lookup is using `clang::DeclID`
|
||||
// and we don't need to store the decl for lookup context.
|
||||
static auto ImportCXXRecordDecl(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::NameScopeId parent_scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::CXXRecordDecl* clang_decl)
|
||||
-> SemIR::InstId {
|
||||
clang::CXXRecordDecl* clang_def = clang_decl->getDefinition();
|
||||
if (!clang_def) {
|
||||
context.TODO(loc_id,
|
||||
"Unsupported: Record declarations without a definition");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
if (clang_def->isDynamicClass()) {
|
||||
context.TODO(loc_id, "Unsupported: Dynamic Class");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
auto [class_id, class_def_id] =
|
||||
BuildClassDefinition(context, parent_scope_id, name_id, clang_def);
|
||||
|
||||
// The class type is now fully defined. Compute its object representation.
|
||||
ComputeClassObjectRepr(context,
|
||||
// TODO: Consider having a proper location here.
|
||||
Parse::ClassDefinitionId::None, class_id,
|
||||
// TODO: Set fields.
|
||||
/*field_decls=*/{},
|
||||
// TODO: Set vtable.
|
||||
/*vtable_contents=*/{},
|
||||
// TODO: Set block.
|
||||
/*body=*/{});
|
||||
|
||||
return class_def_id;
|
||||
}
|
||||
|
||||
// Imports a declaration from Clang to Carbon. If successful, returns the
|
||||
// instruction for the new Carbon declaration.
|
||||
static auto ImportNameDecl(Context& context, SemIR::LocId loc_id,
|
||||
@@ -690,6 +805,19 @@ static auto ImportNameDecl(Context& context, SemIR::LocId loc_id,
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
|
||||
// Imports a `clang::NamedDecl` into Carbon and adds that name into the
|
||||
// `NameScope`.
|
||||
static auto ImportNameDeclIntoScope(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::NameScopeId scope_id,
|
||||
SemIR::NameId name_id,
|
||||
clang::NamedDecl* clang_decl)
|
||||
-> SemIR::InstId {
|
||||
SemIR::InstId inst_id =
|
||||
ImportNameDecl(context, loc_id, scope_id, name_id, clang_decl);
|
||||
AddNameToScope(context, scope_id, name_id, inst_id);
|
||||
return inst_id;
|
||||
}
|
||||
|
||||
auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::NameScopeId scope_id, SemIR::NameId name_id)
|
||||
-> SemIR::InstId {
|
||||
@@ -711,11 +839,13 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id,
|
||||
"find a single result; LookupResultKind: {0}",
|
||||
static_cast<int>(lookup->getResultKind()))
|
||||
.str());
|
||||
context.name_scopes().AddRequiredName(scope_id, name_id,
|
||||
SemIR::ErrorInst::InstId);
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
return ImportNameDecl(context, loc_id, scope_id, name_id,
|
||||
lookup->getFoundDecl());
|
||||
return ImportNameDeclIntoScope(context, loc_id, scope_id, name_id,
|
||||
lookup->getFoundDecl());
|
||||
}
|
||||
|
||||
} // namespace Carbon::Check
|
||||
|
||||
@@ -190,10 +190,8 @@ auto LookupNameInExactScope(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::InstId imported_inst_id =
|
||||
ImportNameFromCpp(context, loc_id, scope_id, name_id);
|
||||
if (imported_inst_id.has_value()) {
|
||||
SemIR::ScopeLookupResult result = SemIR::ScopeLookupResult::MakeFound(
|
||||
imported_inst_id, SemIR::AccessKind::Public);
|
||||
scope.AddRequired({.name_id = name_id, .result = result});
|
||||
return result;
|
||||
return SemIR::ScopeLookupResult::MakeFound(imported_inst_id,
|
||||
SemIR::AccessKind::Public);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,729 @@
|
||||
// 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
|
||||
//
|
||||
// EXTRA-ARGS: --no-prelude-import
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/function/class.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/class.carbon
|
||||
|
||||
// ============================================================================
|
||||
// Forward-declared class as parameter type
|
||||
// ============================================================================
|
||||
|
||||
// --- decl_value_param_type.h
|
||||
|
||||
class C;
|
||||
|
||||
auto foo(C) -> void;
|
||||
|
||||
// --- fail_todo_import_decl_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "decl_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// TODO: This should fail on the fact `C` is declared and not defined.
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined class without data members as parameter type
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_no_data_members_value_param_type.h
|
||||
|
||||
class C {};
|
||||
|
||||
auto foo(C) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_no_data_members_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_no_data_members_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined class with a single data member as parameter type
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_single_data_member_value_param_type.h
|
||||
|
||||
class D {};
|
||||
|
||||
class C {
|
||||
D d;
|
||||
};
|
||||
|
||||
auto foo(C) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_single_data_member_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_single_data_member_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined class with multiple data members as parameter type
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_multiple_data_members_value_param_type.h
|
||||
|
||||
class D {};
|
||||
|
||||
class C {
|
||||
D d1;
|
||||
D d2;
|
||||
D d3;
|
||||
};
|
||||
|
||||
auto foo(C) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_multiple_data_members_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined class in namespace
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_in_namespace_value_param_type.h
|
||||
|
||||
namespace N { class C {}; }
|
||||
|
||||
auto foo(N::C) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_in_namespace_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_in_namespace_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_in_namespace_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class N::C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_in_namespace_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined class in relative namespace
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_in_relative_namespace_value_param_type.h
|
||||
|
||||
namespace N1 {
|
||||
namespace N2 { class C {}; }
|
||||
auto foo(N2::C) -> void;
|
||||
}
|
||||
|
||||
// --- fail_todo_import_definition_in_relative_namespace_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_in_relative_namespace_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_in_relative_namespace_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class N1::N2::C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.N1.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_in_relative_namespace_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.N1.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.N1.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined class and explicitly used
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_with_static_method.h
|
||||
|
||||
class C {
|
||||
static void bar();
|
||||
};
|
||||
|
||||
auto foo(C) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_and_static_method_call_before.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_with_static_method.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
Cpp.C.bar();
|
||||
// CHECK:STDERR: fail_todo_import_definition_and_static_method_call_before.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_and_static_method_call_before.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- fail_todo_import_definition_and_static_method_call_after.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_with_static_method.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_and_static_method_call_after.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_and_static_method_call_after.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
Cpp.C.bar();
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pointer to forward-declared class as parameter type
|
||||
// ============================================================================
|
||||
|
||||
// --- decl_pointer_param_type.h
|
||||
|
||||
class C;
|
||||
|
||||
auto foo(C*) -> void;
|
||||
|
||||
// --- fail_todo_import_decl_pointer_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "decl_pointer_param_type.h";
|
||||
|
||||
// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+7]]:9: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo]
|
||||
// CHECK:STDERR: fn F(s: Cpp.C*) {
|
||||
// CHECK:STDERR: ^~~~~
|
||||
// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+4]]:9: note: in `Cpp` name lookup for `C` [InCppNameLookup]
|
||||
// CHECK:STDERR: fn F(s: Cpp.C*) {
|
||||
// CHECK:STDERR: ^~~~~
|
||||
// CHECK:STDERR:
|
||||
fn F(s: Cpp.C*) {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C *` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo(s);
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo(s);
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo(s);
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pointer to defined class as parameter type
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_pointer_param_type.h
|
||||
|
||||
class C {};
|
||||
|
||||
auto foo(C*) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_pointer_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_pointer_param_type.h";
|
||||
|
||||
fn F(s: Cpp.C*) {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_pointer_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C *` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo(s);
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_pointer_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo(s);
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo(s);
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Forward-declared class as return type
|
||||
// ============================================================================
|
||||
|
||||
// --- decl_value_return_type.h
|
||||
|
||||
class C;
|
||||
|
||||
auto foo() -> C;
|
||||
|
||||
// --- fail_todo_import_decl_value_return_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "decl_value_return_type.h";
|
||||
|
||||
fn F() {
|
||||
// TODO: This should fail on the fact `C` is declared and not defined.
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined class as return type
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_value_return_type.h
|
||||
|
||||
class C {};
|
||||
|
||||
auto foo() -> C;
|
||||
|
||||
// --- fail_todo_import_definition_value_return_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_value_return_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo();
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pointer to forward-declared class as return type
|
||||
// ============================================================================
|
||||
|
||||
// --- decl_pointer_return_type.h
|
||||
|
||||
class C;
|
||||
|
||||
auto foo() -> C*;
|
||||
|
||||
// --- fail_todo_import_decl_pointer_return_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "decl_pointer_return_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C *` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo();
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pointer to defined class as return type
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_pointer_return_type.h
|
||||
|
||||
class C {};
|
||||
|
||||
auto foo() -> C*;
|
||||
|
||||
// --- fail_todo_import_definition_pointer_return_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_pointer_return_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_pointer_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C *` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_pointer_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo();
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: --- fail_todo_import_decl_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc16: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_no_data_members_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_single_data_member_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_in_namespace_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_in_relative_namespace_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .N1 = %N1
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %N1: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %N1.ref: <namespace> = name_ref N1, imports.%N1 [concrete = imports.%N1]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_and_static_method_call_before.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete]
|
||||
// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref.loc8: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C]
|
||||
// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar]
|
||||
// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref()
|
||||
// CHECK:STDOUT: %Cpp.ref.loc16: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc16: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_and_static_method_call_after.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
||||
// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete]
|
||||
// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref.loc15: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %Cpp.ref.loc16: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C]
|
||||
// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar]
|
||||
// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_decl_pointer_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .C = <error>
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F(%s.param: <error>) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref.loc22: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %s.ref: <error> = name_ref s, %s [concrete = <error>]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_pointer_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %C: type = class_type @C [concrete]
|
||||
// CHECK:STDOUT: %ptr: type = ptr_type %C [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .C = %C.decl
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F(%s.param: %ptr) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref.loc15: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %s.ref: %ptr = name_ref s, %s
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_value_return_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_decl_pointer_return_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_pointer_return_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
+358
-48
@@ -29,6 +29,13 @@ import Cpp library "decl_value_param_type.h";
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// TODO: This should fail on the fact `S` is declared and not defined.
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+14]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+11]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
@@ -50,7 +57,7 @@ struct S {};
|
||||
|
||||
auto foo(S) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_no_data_members_value_param_type.carbon
|
||||
// --- import_definition_no_data_members_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
@@ -58,13 +65,6 @@ import Cpp library "definition_no_data_members_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
@@ -83,7 +83,7 @@ struct S {
|
||||
|
||||
auto foo(S) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_single_data_member_value_param_type.carbon
|
||||
// --- import_definition_single_data_member_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
@@ -91,13 +91,6 @@ import Cpp library "definition_single_data_member_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
@@ -118,7 +111,7 @@ struct S {
|
||||
|
||||
auto foo(S) -> void;
|
||||
|
||||
// --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon
|
||||
// --- import_definition_multiple_data_members_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
@@ -126,17 +119,93 @@ import Cpp library "definition_multiple_data_members_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo({});
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined struct in namespace
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_in_namespace_value_param_type.h
|
||||
|
||||
namespace N { struct S {}; }
|
||||
|
||||
auto foo(N::S) -> void;
|
||||
|
||||
// --- import_definition_in_namespace_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_in_namespace_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined struct in relative namespace
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_in_relative_namespace_value_param_type.h
|
||||
|
||||
namespace N1 {
|
||||
namespace N2 { struct S {}; }
|
||||
auto foo(N2::S) -> void;
|
||||
}
|
||||
|
||||
// --- import_definition_in_relative_namespace_value_param_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_in_relative_namespace_value_param_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
Cpp.N1.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Defined struct and explicitly used
|
||||
// ============================================================================
|
||||
|
||||
// --- definition_with_static_method.h
|
||||
|
||||
struct S {
|
||||
static void bar();
|
||||
};
|
||||
|
||||
auto foo(S) -> void;
|
||||
|
||||
// --- import_definition_and_static_method_call_before.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_with_static_method.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
Cpp.S.bar();
|
||||
Cpp.foo({});
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// --- import_definition_and_static_method_call_after.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
import Cpp library "definition_with_static_method.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
Cpp.foo({});
|
||||
Cpp.S.bar();
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pointer to forward-declared struct as parameter type
|
||||
// ============================================================================
|
||||
@@ -221,6 +290,13 @@ import Cpp library "decl_value_return_type.h";
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// TODO: This should fail on the fact `S` is declared and not defined.
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+14]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+11]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: struct S` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
@@ -242,7 +318,7 @@ struct S {};
|
||||
|
||||
auto foo() -> S;
|
||||
|
||||
// --- fail_todo_import_definition_value_return_type.carbon
|
||||
// --- import_definition_value_return_type.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
@@ -250,13 +326,6 @@ import Cpp library "definition_value_return_type.h";
|
||||
|
||||
fn F() {
|
||||
//@dump-sem-ir-begin
|
||||
// CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: struct S` [SemanticsTodo]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup]
|
||||
// CHECK:STDERR: Cpp.foo();
|
||||
// CHECK:STDERR: ^~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Cpp.foo();
|
||||
//@dump-sem-ir-end
|
||||
}
|
||||
@@ -328,6 +397,7 @@ fn F() {
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: .S = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
@@ -336,70 +406,296 @@ fn F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc16: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc23: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_no_data_members_value_param_type.carbon
|
||||
// CHECK:STDOUT: --- import_definition_no_data_members_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: .S = %S.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val]
|
||||
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
|
||||
// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4
|
||||
// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_single_data_member_value_param_type.carbon
|
||||
// CHECK:STDOUT: --- import_definition_single_data_member_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: .S = %S.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val]
|
||||
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
|
||||
// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4
|
||||
// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon
|
||||
// CHECK:STDOUT: --- import_definition_multiple_data_members_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: .S = %S.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val]
|
||||
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
|
||||
// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4
|
||||
// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- import_definition_in_namespace_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val]
|
||||
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
|
||||
// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4
|
||||
// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- import_definition_in_relative_namespace_value_param_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .N1 = %N1
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %N1: <namespace> = namespace [concrete] {
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %N1.ref: <namespace> = name_ref N1, imports.%N1 [concrete = imports.%N1]
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc8_15.1: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc8_15.2: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %.loc8_15.3: init %S = class_init (), %.loc8_15.2 [concrete = constants.%S.val]
|
||||
// CHECK:STDOUT: %.loc8_15.4: ref %S = temporary %.loc8_15.2, %.loc8_15.3
|
||||
// CHECK:STDOUT: %.loc8_15.5: ref %S = converted %.loc8_15.1, %.loc8_15.4
|
||||
// CHECK:STDOUT: %.loc8_15.6: %S = bind_value %.loc8_15.5
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_15.6)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- import_definition_and_static_method_call_before.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete]
|
||||
// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .S = %S.decl
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
|
||||
// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {}
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref.loc8: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S]
|
||||
// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar]
|
||||
// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref()
|
||||
// CHECK:STDOUT: %Cpp.ref.loc9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc9_12.1: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc9_12.2: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %.loc9_12.3: init %S = class_init (), %.loc9_12.2 [concrete = constants.%S.val]
|
||||
// CHECK:STDOUT: %.loc9_12.4: ref %S = temporary %.loc9_12.2, %.loc9_12.3
|
||||
// CHECK:STDOUT: %.loc9_12.5: ref %S = converted %.loc9_12.1, %.loc9_12.4
|
||||
// CHECK:STDOUT: %.loc9_12.6: %S = bind_value %.loc9_12.5
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc9_12.6)
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- import_definition_and_static_method_call_after.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %S.val: %S = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete]
|
||||
// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: .S = %S.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {}
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref.loc8: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal ()
|
||||
// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val]
|
||||
// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3
|
||||
// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4
|
||||
// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5
|
||||
// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6)
|
||||
// CHECK:STDOUT: %Cpp.ref.loc9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S]
|
||||
// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar]
|
||||
// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref()
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -456,6 +752,7 @@ fn F() {
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: .S = <error>
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
@@ -467,22 +764,35 @@ fn F() {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: --- fail_todo_import_definition_value_return_type.carbon
|
||||
// CHECK:STDOUT: --- import_definition_value_return_type.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %S: type = class_type @S [concrete]
|
||||
// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete]
|
||||
// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: .foo = <error>
|
||||
// CHECK:STDOUT: .foo = %foo.decl
|
||||
// CHECK:STDOUT: .S = %S.decl
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {}
|
||||
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F() {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
|
||||
// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo]
|
||||
// CHECK:STDOUT: %.loc8_11.1: ref %S = temporary_storage
|
||||
// CHECK:STDOUT: %foo.call: init %S = call %foo.ref() to %.loc8_11.1
|
||||
// CHECK:STDOUT: %.loc8_11.2: ref %S = temporary %.loc8_11.1, %foo.call
|
||||
// CHECK:STDOUT: <elided>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
@@ -675,7 +675,7 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
||||
CARBON_CHECK(!specific_id.has_value(),
|
||||
"Specific functions cannot have C++ definitions");
|
||||
HandleReferencedCppFunction(clang::dyn_cast<clang::FunctionDecl>(
|
||||
sem_ir().clang_decls().Get(clang_decl_id)));
|
||||
sem_ir().clang_decls().Get(clang_decl_id).decl));
|
||||
// TODO: Check that the signature and mangling generated by Clang and the
|
||||
// one we generated are the same.
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ auto Mangler::Mangle(SemIR::FunctionId function_id,
|
||||
}
|
||||
if (function.clang_decl_id.has_value()) {
|
||||
return MangleCppClang(llvm::dyn_cast<clang::NamedDecl>(
|
||||
sem_ir().clang_decls().Get(function.clang_decl_id)));
|
||||
sem_ir().clang_decls().Get(function.clang_decl_id).decl));
|
||||
}
|
||||
RawStringOstream os;
|
||||
os << "_C";
|
||||
|
||||
@@ -57,6 +57,18 @@ cc_test(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "clang_decl",
|
||||
srcs = ["clang_decl.cpp"],
|
||||
hdrs = ["clang_decl.h"],
|
||||
deps = [
|
||||
":typed_insts",
|
||||
"//common:hashtable_key_context",
|
||||
"//common:ostream",
|
||||
"@llvm-project//clang:ast",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "file",
|
||||
srcs = [
|
||||
@@ -107,6 +119,7 @@ cc_library(
|
||||
],
|
||||
deps = [
|
||||
":block_value_store",
|
||||
":clang_decl",
|
||||
":typed_insts",
|
||||
"//common:check",
|
||||
"//common:enum_base",
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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
|
||||
|
||||
#include "toolchain/sem_ir/clang_decl.h"
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
auto ClangDecl::Print(llvm::raw_ostream& out) const -> void {
|
||||
out << "{decl: ";
|
||||
decl->print(out);
|
||||
out << ", inst_id: " << inst_id << "}";
|
||||
}
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
@@ -0,0 +1,62 @@
|
||||
// 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_CLANG_DECL_H_
|
||||
#define CARBON_TOOLCHAIN_SEM_IR_CLANG_DECL_H_
|
||||
|
||||
#include "common/hashtable_key_context.h"
|
||||
#include "common/ostream.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
namespace clang {
|
||||
|
||||
// Forward declare indexed types, for integration with ValueStore.
|
||||
class Decl;
|
||||
|
||||
} // namespace clang
|
||||
|
||||
namespace Carbon::SemIR {
|
||||
|
||||
// A Clang declaration mapped to a Carbon instruction.
|
||||
// Using custom hashing since the declaration is keyed by the `decl` member for
|
||||
// lookup.
|
||||
// TODO: Avoid custom hashing by either having the data structure support keying
|
||||
// or create a dedicated mapping. See
|
||||
// https://discord.com/channels/655572317891461132/768530752592805919/1384999468293947537
|
||||
struct ClangDecl : public Printable<ClangDecl> {
|
||||
auto Print(llvm::raw_ostream& out) const -> void;
|
||||
|
||||
friend auto CarbonHashtableEq(const ClangDecl& lhs, const ClangDecl& rhs)
|
||||
-> bool {
|
||||
return HashtableEq(lhs.decl, rhs.decl);
|
||||
}
|
||||
|
||||
// Hashing for ClangDecl. See common/hashing.h.
|
||||
friend auto CarbonHashValue(const ClangDecl& value, uint64_t seed)
|
||||
-> HashCode {
|
||||
return HashValue(value.decl, seed);
|
||||
}
|
||||
|
||||
// The Clang declaration pointing to the Clang AST.
|
||||
// TODO: Ensure we can easily serialize/deserialize this. Consider
|
||||
// `clang::LazyDeclPtr`.
|
||||
clang::Decl* decl = nullptr;
|
||||
|
||||
// The instruction the Clang declaration is mapped to.
|
||||
InstId inst_id;
|
||||
};
|
||||
|
||||
// The ID of a `ClangDecl`.
|
||||
struct ClangDeclId : public IdBase<ClangDeclId> {
|
||||
static constexpr llvm::StringLiteral Label = "clang_decl_id";
|
||||
|
||||
using ValueType = ClangDecl;
|
||||
|
||||
using IdBase::IdBase;
|
||||
};
|
||||
|
||||
} // namespace Carbon::SemIR
|
||||
|
||||
#endif // CARBON_TOOLCHAIN_SEM_IR_CLANG_DECL_H_
|
||||
@@ -335,7 +335,9 @@ class File : public Printable<File> {
|
||||
// `Cpp` imports.
|
||||
clang::ASTUnit* cpp_ast_ = nullptr;
|
||||
|
||||
// Clang AST declarations pointing to the AST.
|
||||
// Clang AST declarations pointing to the AST and their mapped Carbon
|
||||
// instructions. When calling `Lookup()`, `inst_id` is ignored. `Add()` will
|
||||
// not add multiple entries with the same `decl` and different `inst_id`.
|
||||
CanonicalValueStore<ClangDeclId> clang_decls_;
|
||||
|
||||
// All instructions. The first entries will always be the singleton
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "toolchain/sem_ir/builtin_function_kind.h"
|
||||
#include "toolchain/sem_ir/clang_decl.h"
|
||||
#include "toolchain/sem_ir/entity_with_params_base.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst_categories.h"
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
namespace clang {
|
||||
|
||||
// Forward declare indexed types, for integration with ValueStore.
|
||||
class Decl;
|
||||
class SourceLocation;
|
||||
|
||||
} // namespace clang
|
||||
@@ -788,17 +787,6 @@ struct TypeId : public IdBase<TypeId> {
|
||||
auto Print(llvm::raw_ostream& out) const -> void;
|
||||
};
|
||||
|
||||
// The ID of a Clang `Decl` pointer, pointing to the Clang AST.
|
||||
struct ClangDeclId : public IdBase<ClangDeclId> {
|
||||
static constexpr llvm::StringLiteral Label = "clang_decl_id";
|
||||
|
||||
// TODO: Ensure we can easily serialize/deserialize this. Consider
|
||||
// `clang::LazyDeclPtr`.
|
||||
using ValueType = clang::Decl*;
|
||||
|
||||
using IdBase::IdBase;
|
||||
};
|
||||
|
||||
// The ID of a Clang Source Location.
|
||||
struct ClangSourceLocId : public IdBase<ClangSourceLocId> {
|
||||
static constexpr llvm::StringLiteral Label = "clang_source_loc";
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "common/map.h"
|
||||
#include "toolchain/sem_ir/clang_decl.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/inst.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user