mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 08:31:04 +01:00
Add initial support for exporting generic Carbon functions to C++ (#7462)
This allows C++ to call Carbon functions with generic type parameters,
with some conditions. Example:
```carbon
interface I {
fn Doit(self);
}
class A {
impl as I { fn Doit(unused self) {} }
}
class B {
impl as I { fn Doit(unused self) {} }
}
fn F[T:! I](t: T) {
t.Doit();
}
inline Cpp '''
void G() {
Carbon::A a;
Carbon::B b;
Carbon::F(a);
Carbon::F(b);
}
''';
```
The initial support is limited; only explicit parameters are handled
currently.
`CarbonExternalASTSource::GetOrExportFunctionToCpp` now generates a
`clang::FunctionTemplateDecl` for generic Carbon functions. If C++ code
attempts to call that templated function,
`CarbonExternalASTSource::LoadExternalSpecializations` will be called
with the template argument types of that call site. Then we can generate
a specialized thunk for those argument types for C++ to call.
This commit is contained in:
+215
-25
@@ -5,8 +5,10 @@
|
||||
#include "toolchain/check/cpp/export.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Sema/EnterExpressionEvaluationContext.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "toolchain/check/cpp/access.h"
|
||||
@@ -421,18 +423,22 @@ static auto BuildCppFunctionDeclForCarbonFn(Context& context,
|
||||
CARBON_CHECK(identifier_info, "function with non-identifier name {0}",
|
||||
function.name_id);
|
||||
|
||||
auto* tinfo = context.ast_context().getTrivialTypeSourceInfo(
|
||||
cpp_function_type, clang_loc);
|
||||
clang::FunctionDecl* function_decl = clang::FunctionDecl::Create(
|
||||
context.ast_context(), context.ast_context().getTranslationUnitDecl(),
|
||||
/*StartLoc=*/clang_loc, /*NLoc=*/clang_loc, identifier_info,
|
||||
cpp_function_type, /*TInfo=*/nullptr, clang::SC_Extern);
|
||||
cpp_function_type, tinfo, clang::SC_Extern);
|
||||
|
||||
// Build parameter decls.
|
||||
llvm::SmallVector<clang::ParmVarDecl*> param_var_decls;
|
||||
for (auto [i, type] : llvm::enumerate(cpp_param_types)) {
|
||||
auto* param_tinfo =
|
||||
context.ast_context().getTrivialTypeSourceInfo(type, clang_loc);
|
||||
clang::ParmVarDecl* param = clang::ParmVarDecl::Create(
|
||||
context.ast_context(), function_decl, /*StartLoc=*/clang_loc,
|
||||
/*IdLoc=*/clang_loc, /*Id=*/nullptr, type, /*TInfo=*/nullptr,
|
||||
clang::SC_None, /*DefArg=*/nullptr);
|
||||
/*IdLoc=*/clang_loc, /*Id=*/nullptr, type, param_tinfo, clang::SC_None,
|
||||
/*DefArg=*/nullptr);
|
||||
param_var_decls.push_back(param);
|
||||
}
|
||||
function_decl->setParams(param_var_decls);
|
||||
@@ -683,6 +689,10 @@ static auto BuildCppToCarbonThunk(Context& context, SemIR::LocId loc_id,
|
||||
// Build the thunk function body.
|
||||
clang::Sema& sema = context.clang_sema();
|
||||
clang::Sema::ContextRAII context_raii(sema, thunk_function_decl);
|
||||
// Ensure that the evaluation context is not `Unevaluated`, as that
|
||||
// would cause code generation to fail.
|
||||
clang::EnterExpressionEvaluationContext evaluated(
|
||||
sema, clang::Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
|
||||
sema.ActOnStartOfFunctionDef(nullptr, thunk_function_decl);
|
||||
clang::StmtResult body = BuildCppToCarbonThunkBody(
|
||||
sema, target, thunk_function_decl, carbon_function_decl);
|
||||
@@ -696,13 +706,18 @@ static auto BuildCppToCarbonThunk(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
// Create a Carbon thunk that calls `callee`. The thunk's parameters are
|
||||
// all references to the callee parameter type.
|
||||
//
|
||||
// `extra_name` will be appended to the thunk name. This is used to
|
||||
// disambiguate the names of specialized function thunks.
|
||||
static auto BuildCarbonToCarbonThunk(Context& context, SemIR::LocId loc_id,
|
||||
const FunctionInfo& target)
|
||||
const FunctionInfo& target,
|
||||
std::string_view extra_name = "")
|
||||
-> SemIR::FunctionId {
|
||||
// Create the thunk's name.
|
||||
llvm::SmallString<64> thunk_name =
|
||||
context.names().GetFormatted(target.function.name_id);
|
||||
thunk_name += "__carbon_thunk";
|
||||
thunk_name += extra_name;
|
||||
auto& ident = context.ast_context().Idents.get(thunk_name);
|
||||
auto thunk_name_id =
|
||||
SemIR::NameId::ForIdentifier(context.identifiers().Add(ident.getName()));
|
||||
@@ -738,18 +753,204 @@ static auto BuildCarbonToCarbonThunk(Context& context, SemIR::LocId loc_id,
|
||||
return carbon_thunk_function_id;
|
||||
}
|
||||
|
||||
auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::FunctionId callee_function_id)
|
||||
// Creates a `clang::FunctionDecl` that calls the Carbon function in
|
||||
// `target`. The `extra_name` string is appended to the Carbon thunk's
|
||||
// name.
|
||||
//
|
||||
// Returns nullptr if an error occurs.
|
||||
auto ExportNonGenericFunctionToCpp(Context& context, SemIR::LocId loc_id,
|
||||
const FunctionInfo& target,
|
||||
std::string_view extra_name = "")
|
||||
-> clang::FunctionDecl* {
|
||||
const SemIR::Function& callee = context.functions().Get(callee_function_id);
|
||||
// Create a Carbon thunk that calls the callee. The thunk's parameters
|
||||
// are all references so that the ABI is compatible with C++ callers.
|
||||
auto carbon_thunk_function_id =
|
||||
BuildCarbonToCarbonThunk(context, loc_id, target, extra_name);
|
||||
|
||||
if (callee.generic_id.has_value()) {
|
||||
context.TODO(loc_id,
|
||||
"unsupported: C++ calling a Carbon function with "
|
||||
"generic parameters");
|
||||
// Create a `clang::FunctionDecl` that can be used to call the Carbon thunk.
|
||||
auto* carbon_function_decl = BuildCppFunctionDeclForCarbonFn(
|
||||
context, loc_id, carbon_thunk_function_id);
|
||||
if (!carbon_function_decl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a C++ thunk that calls the Carbon thunk.
|
||||
return BuildCppToCarbonThunk(
|
||||
context, loc_id, target,
|
||||
context.names().GetFormatted(target.function.name_id),
|
||||
carbon_function_decl);
|
||||
}
|
||||
|
||||
auto ExportFunctionSpecializationToCpp(
|
||||
Context& context, clang::FunctionTemplateDecl* function_template_decl,
|
||||
llvm::ArrayRef<clang::TemplateArgument> template_args) -> bool {
|
||||
// Map from the `clang::FunctionTemplateDecl` to the Carbon `FunctionDecl`.
|
||||
auto clang_decl_id = context.clang_decls().LookupId(
|
||||
SemIR::ClangDeclKey(function_template_decl));
|
||||
if (clang_decl_id == SemIR::ClangDeclId::None) {
|
||||
return false;
|
||||
}
|
||||
SemIR::InstId inst_id = context.clang_decls().Get(clang_decl_id).inst_id;
|
||||
CARBON_CHECK(inst_id.has_value());
|
||||
auto target_function_decl =
|
||||
context.insts().GetAs<SemIR::FunctionDecl>(inst_id);
|
||||
auto target_function =
|
||||
context.functions().Get(target_function_decl.function_id);
|
||||
|
||||
auto* decl_context = function_template_decl->getDeclContext();
|
||||
FunctionInfo target(context, target_function_decl.function_id,
|
||||
target_function, decl_context);
|
||||
SemIR::LocId loc_id(target.function.first_decl_id());
|
||||
|
||||
const auto& generic = context.generics().Get(target.function.generic_id);
|
||||
auto bindings = context.inst_blocks().Get(generic.bindings_id);
|
||||
CARBON_CHECK(bindings.size() == template_args.size());
|
||||
|
||||
// This name will be appended to the thunk name to disambiguate
|
||||
// between specializations.
|
||||
std::string extra_name;
|
||||
|
||||
// Create a mapping from Carbon generic parameters to the
|
||||
// corresponding C++ type in `template_args`.
|
||||
Map<SemIR::InstId, SemIR::TypeId> symbolic_to_actual;
|
||||
for (auto [binding_inst_id, clang_template_arg] :
|
||||
llvm::zip(bindings, template_args)) {
|
||||
auto type_expr =
|
||||
ImportCppType(context, loc_id, clang_template_arg.getAsType());
|
||||
if (type_expr.type_id == SemIR::ErrorInst::TypeId) {
|
||||
return false;
|
||||
}
|
||||
if (!type_expr.type_id.has_value()) {
|
||||
context.TODO(loc_id, "failed to import C++ type");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto binding_const_inst_id =
|
||||
context.constant_values().GetConstantInstId(binding_inst_id);
|
||||
symbolic_to_actual.Insert(binding_const_inst_id, type_expr.type_id);
|
||||
|
||||
// TODO: this generates a pretty ugly name.
|
||||
extra_name += std::string(llvm::formatv("{}", type_expr.inst_id));
|
||||
}
|
||||
|
||||
// Replace symbolic explicit parameters with a concrete Carbon type.
|
||||
//
|
||||
// This will only handle simple cases like `x: T`, and not things like
|
||||
// `x: T*`. Ultimately what we should be doing here is producing a Specific
|
||||
// for the generic function. See `fail_todo_generic_pointer.carbon`.
|
||||
for (auto& param : target.explicit_params) {
|
||||
auto param_type_inst_id = context.types().GetTypeInstId(param.type_id);
|
||||
SemIR::InstId symbolic_inst_id = SemIR::InstId::None;
|
||||
if (auto symbolic_binding =
|
||||
context.insts().TryGetAs<SemIR::SymbolicBinding>(
|
||||
param_type_inst_id)) {
|
||||
symbolic_inst_id = param_type_inst_id;
|
||||
} else if (auto facet_access_type =
|
||||
context.insts().TryGetAs<SemIR::FacetAccessType>(
|
||||
param_type_inst_id)) {
|
||||
symbolic_inst_id = facet_access_type->facet_value_inst_id;
|
||||
}
|
||||
|
||||
if (symbolic_inst_id.has_value()) {
|
||||
if (auto lookup = symbolic_to_actual.Lookup(symbolic_inst_id)) {
|
||||
param.type_id = lookup.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle generic return type.
|
||||
|
||||
// Build the thunks. Mark the C++ thunk as a template specialization.
|
||||
auto* function_decl =
|
||||
ExportNonGenericFunctionToCpp(context, loc_id, target, extra_name);
|
||||
if (!function_decl) {
|
||||
return false;
|
||||
}
|
||||
auto* template_arg_list = clang::TemplateArgumentList::CreateCopy(
|
||||
context.ast_context(), template_args);
|
||||
function_decl->setFunctionTemplateSpecialization(
|
||||
function_template_decl, template_arg_list,
|
||||
/*InsertPos=*/nullptr, clang::TSK_ExplicitSpecialization);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates a `clang::FunctionTemplateDecl` for a generic Carbon function.
|
||||
//
|
||||
// Returns nullptr if an error occurs.
|
||||
static auto ExportGenericFunctionToCpp(Context& context, SemIR::LocId loc_id,
|
||||
const FunctionInfo& callee)
|
||||
-> clang::FunctionTemplateDecl* {
|
||||
auto clang_loc = GetCppLocation(context, loc_id);
|
||||
|
||||
const auto& generic = context.generics().Get(callee.function.generic_id);
|
||||
auto bindings = context.inst_blocks().Get(generic.bindings_id);
|
||||
llvm::SmallVector<clang::NamedDecl*> template_param_decls;
|
||||
|
||||
// Create `clang::TemplateTypeParmDecl`s for each of the function's
|
||||
// symbolic parameters.
|
||||
//
|
||||
// TODO: handle the case where the function is within an enclosing generic,
|
||||
// and only include the bindings introduced in the inner function here. See
|
||||
// `fail_todo_enclosing_generic.carbon`.
|
||||
for (auto binding_inst_id : bindings) {
|
||||
binding_inst_id =
|
||||
context.constant_values().GetConstantInstId(binding_inst_id);
|
||||
auto symbolic_binding =
|
||||
context.insts().GetAs<SemIR::SymbolicBinding>(binding_inst_id);
|
||||
|
||||
const auto& entity_name =
|
||||
context.entity_names().Get(symbolic_binding.entity_name_id);
|
||||
|
||||
auto* param_ident = GetClangIdentifierInfo(context, entity_name.name_id);
|
||||
CARBON_CHECK(param_ident, "non-identifier param name {0}",
|
||||
entity_name.name_id);
|
||||
|
||||
if (symbolic_binding.type_id != SemIR::TypeType::TypeId &&
|
||||
!context.types().Is<SemIR::FacetType>(symbolic_binding.type_id)) {
|
||||
context.TODO(loc_id, "binding maps to a non-type template parameter");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* param_decl = clang::TemplateTypeParmDecl::Create(
|
||||
context.ast_context(), callee.decl_context, /*KeyLoc=*/clang_loc,
|
||||
/*NameLoc=*/clang_loc,
|
||||
/*D=*/0, /*P=*/0, param_ident, /*Typename=*/true,
|
||||
/*ParameterPack=*/false);
|
||||
template_param_decls.push_back(param_decl);
|
||||
|
||||
// Store a mapping between the generic parameter's `TypeInstId` and
|
||||
// the `clang::TemplateTypeParmDecl`.
|
||||
auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(param_decl);
|
||||
context.clang_decls().Add({.key = key, .inst_id = binding_inst_id});
|
||||
}
|
||||
|
||||
auto* template_param_list = clang::TemplateParameterList::Create(
|
||||
context.ast_context(),
|
||||
/*TemplateLoc=*/clang_loc,
|
||||
/*LAngleLoc=*/clang_loc, template_param_decls,
|
||||
/*RAngleLoc=*/clang_loc,
|
||||
/*RequiresClause=*/nullptr);
|
||||
|
||||
auto* function_decl =
|
||||
BuildCppFunctionDeclForCarbonFn(context, loc_id, callee.function_id);
|
||||
if (!function_decl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* template_decl = clang::FunctionTemplateDecl::Create(
|
||||
context.ast_context(), callee.decl_context, clang_loc,
|
||||
function_decl->getDeclName(), template_param_list, function_decl);
|
||||
function_decl->setDescribedFunctionTemplate(template_decl);
|
||||
|
||||
return template_decl;
|
||||
}
|
||||
|
||||
auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::FunctionId callee_function_id)
|
||||
-> clang::NamedDecl* {
|
||||
const SemIR::Function& callee = context.functions().Get(callee_function_id);
|
||||
|
||||
// Map the parent scope into the C++ AST.
|
||||
auto* decl_context =
|
||||
ExportNameScopeToCpp(context, loc_id, callee.parent_scope_id);
|
||||
@@ -760,22 +961,11 @@ auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id,
|
||||
FunctionInfo target_function_info(context, callee_function_id, callee,
|
||||
decl_context);
|
||||
|
||||
// Create a Carbon thunk that calls the callee. The thunk's parameters
|
||||
// are all references so that the ABI is compatible with C++ callers.
|
||||
auto carbon_thunk_function_id =
|
||||
BuildCarbonToCarbonThunk(context, loc_id, target_function_info);
|
||||
|
||||
// Create a `clang::FunctionDecl` that can be used to call the Carbon thunk.
|
||||
auto* carbon_function_decl = BuildCppFunctionDeclForCarbonFn(
|
||||
context, loc_id, carbon_thunk_function_id);
|
||||
if (!carbon_function_decl) {
|
||||
return nullptr;
|
||||
if (callee.generic_id.has_value()) {
|
||||
return ExportGenericFunctionToCpp(context, loc_id, target_function_info);
|
||||
}
|
||||
|
||||
// Create a C++ thunk that calls the Carbon thunk.
|
||||
return BuildCppToCarbonThunk(context, loc_id, target_function_info,
|
||||
context.names().GetFormatted(callee.name_id),
|
||||
carbon_function_decl);
|
||||
return ExportNonGenericFunctionToCpp(context, loc_id, target_function_info);
|
||||
}
|
||||
|
||||
// Returns whether the given class has any abstract methods.
|
||||
|
||||
@@ -52,8 +52,18 @@ auto ExportFieldToCpp(Context& context, SemIR::InstId field_inst_id,
|
||||
SemIR::FieldDecl field_decl) -> clang::FieldDecl*;
|
||||
|
||||
// Get a `clang::FunctionDecl` that can be used to call a Carbon function.
|
||||
// If the function is generic, a `clang::FunctionTemplateDecl` will be
|
||||
// created instead.
|
||||
auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::FunctionId function_id) -> clang::FunctionDecl*;
|
||||
SemIR::FunctionId function_id) -> clang::NamedDecl*;
|
||||
|
||||
// Creates a C++ function template specialization for a generic Carbon
|
||||
// function.
|
||||
//
|
||||
// Returns true if a specialization was added, false otherwise.
|
||||
auto ExportFunctionSpecializationToCpp(
|
||||
Context& context, clang::FunctionTemplateDecl* function_template_decl,
|
||||
llvm::ArrayRef<clang::TemplateArgument> template_args) -> bool;
|
||||
|
||||
// Export a Carbon destructor into C++.
|
||||
//
|
||||
|
||||
@@ -338,6 +338,21 @@ class CarbonExternalASTSource : public SemIR::ReadOnlyASTSource {
|
||||
const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
|
||||
const clang::DeclContext* original_decl_context) -> bool override;
|
||||
|
||||
auto LoadExternalSpecializations(
|
||||
const clang::Decl* decl,
|
||||
llvm::ArrayRef<clang::TemplateArgument> template_args) -> bool override {
|
||||
const auto* function_template_decl =
|
||||
llvm::dyn_cast<clang::FunctionTemplateDecl>(decl);
|
||||
if (!function_template_decl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ExportFunctionSpecializationToCpp(
|
||||
*context_,
|
||||
const_cast<clang::FunctionTemplateDecl*>(function_template_decl),
|
||||
template_args);
|
||||
}
|
||||
|
||||
auto CompleteType(clang::TagDecl* tag_decl) -> void override;
|
||||
|
||||
auto layoutRecordType(
|
||||
@@ -367,7 +382,7 @@ class CarbonExternalASTSource : public SemIR::ReadOnlyASTSource {
|
||||
|
||||
auto GetOrExportFunctionToCpp(SemIR::InstId target_inst_id,
|
||||
SemIR::FunctionId function_id)
|
||||
-> clang::FunctionDecl*;
|
||||
-> clang::NamedDecl*;
|
||||
// Get a current best-effort location for the current position within C++
|
||||
// processing.
|
||||
auto GetCurrentCppLocId() -> SemIR::LocId {
|
||||
@@ -460,20 +475,29 @@ auto CarbonExternalASTSource::MapInstIdToClangDeclOrType(LookupResult lookup)
|
||||
|
||||
auto CarbonExternalASTSource::GetOrExportFunctionToCpp(
|
||||
SemIR::InstId target_inst_id, SemIR::FunctionId function_id)
|
||||
-> clang::FunctionDecl* {
|
||||
-> clang::NamedDecl* {
|
||||
SemIR::Function& function = context_->functions().Get(function_id);
|
||||
if (const auto* clang_decl =
|
||||
context_->clang_decls().Lookup(function.first_decl_id())) {
|
||||
return cast<clang::FunctionDecl>(clang_decl->decl());
|
||||
return cast<clang::NamedDecl>(clang_decl->decl());
|
||||
}
|
||||
|
||||
auto* clang_function_decl =
|
||||
auto* named_decl =
|
||||
ExportFunctionToCpp(*context_, SemIR::LocId(target_inst_id), function_id);
|
||||
|
||||
if (!clang_function_decl) {
|
||||
if (!named_decl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto* function_template_decl =
|
||||
llvm::dyn_cast<clang::FunctionTemplateDecl>(named_decl)) {
|
||||
context_->clang_decls().Add(
|
||||
{.key = SemIR::ClangDeclKey::ForNonFunctionDecl(function_template_decl),
|
||||
.inst_id = function.first_decl_id()});
|
||||
return function_template_decl;
|
||||
}
|
||||
|
||||
auto* clang_function_decl = llvm::cast<clang::FunctionDecl>(named_decl);
|
||||
|
||||
SemIR::ClangDeclSignature thunk_signature;
|
||||
thunk_signature.kind = SemIR::ClangDeclSignature::Normal;
|
||||
thunk_signature.num_params =
|
||||
|
||||
@@ -236,6 +236,18 @@ static auto TryMapClassType(Context& context, SemIR::TypeInstId class_inst_id,
|
||||
return ast_context.getCanonicalTagType(tag_decl);
|
||||
}
|
||||
|
||||
// Maps a symbolic Carbon type to a C++ template parameter type.
|
||||
static auto TryMapSymbolicType(Context& context,
|
||||
SemIR::InstId symbolic_inst_id) {
|
||||
const auto* clang_decl = context.clang_decls().Lookup(symbolic_inst_id);
|
||||
if (!clang_decl) {
|
||||
return clang::QualType();
|
||||
}
|
||||
return context.ast_context().getTemplateTypeParmType(
|
||||
/*Depth=*/0, /*Index=*/0, /*ParameterPack=*/false,
|
||||
llvm::cast<clang::TemplateTypeParmDecl>(clang_decl->decl()));
|
||||
}
|
||||
|
||||
// Maps a Carbon type to a C++ type. Either returns the mapped type, a null type
|
||||
// as a placeholder indicating the type can't be mapped, or a `WrappedType`
|
||||
// representing a type that needs more work before it can be mapped.
|
||||
@@ -299,6 +311,13 @@ static auto TryMapType(Context& context, SemIR::TypeId type_id)
|
||||
clang::ArraySizeModifier::Normal, /*IndexTypeQuals=*/0);
|
||||
}};
|
||||
}
|
||||
case SemIR::SymbolicBinding::Kind: {
|
||||
auto type_inst_id = context.types().GetTypeInstId(type_id);
|
||||
return TryMapSymbolicType(context, type_inst_id);
|
||||
}
|
||||
case CARBON_KIND(SemIR::FacetAccessType facet_access_type): {
|
||||
return TryMapSymbolicType(context, facet_access_type.facet_value_inst_id);
|
||||
}
|
||||
|
||||
default: {
|
||||
return clang::QualType();
|
||||
|
||||
@@ -85,42 +85,29 @@ void G() { F(); }
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+9]]:1: in import [InImport]
|
||||
// CHECK:STDERR: other.carbon:7:1: error: 1 argument passed to function expecting 2 arguments [CallArgCountMismatch]
|
||||
// CHECK:STDERR: fn HasGenericArg(T:! type, a: T) { a; }
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+5]]:1: in import [InImport]
|
||||
// CHECK:STDERR: other.carbon:7:1: error: semantics TODO: `unsupported: C++ calling a Carbon function with generic parameters` [SemanticsTodo]
|
||||
// CHECK:STDERR: other.carbon:7:1: note: calling function declared here [InCallToEntity]
|
||||
// CHECK:STDERR: fn HasGenericArg(T:! type, a: T) { a; }
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
import Other;
|
||||
import Cpp inline '''
|
||||
void G() {
|
||||
// CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+8]]:18: error: no member named 'HasGenericArg' in namespace 'Carbon::Other' [CppInteropParseError]
|
||||
// CHECK:STDERR: 20 | Carbon::Other::HasGenericArg<int>(123);
|
||||
// CHECK:STDERR: | ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+4]]:35: error: expected '(' for function-style cast or type construction [CppInteropParseError]
|
||||
// CHECK:STDERR: 20 | Carbon::Other::HasGenericArg<int>(123);
|
||||
// CHECK:STDERR: | ~~~^
|
||||
// CHECK:STDERR:
|
||||
Carbon::Other::HasGenericArg<int>(123);
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_todo_deduced.carbon
|
||||
// --- deduced.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// CHECK:STDERR: fail_todo_deduced.carbon:[[@LINE+5]]:1: in import [InImport]
|
||||
// CHECK:STDERR: other.carbon:8:1: error: semantics TODO: `unsupported: C++ calling a Carbon function with generic parameters` [SemanticsTodo]
|
||||
// CHECK:STDERR: fn HasDeducedArg[T:! type](a: T) { a; }
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
import Other;
|
||||
import Cpp inline '''
|
||||
void G() {
|
||||
// CHECK:STDERR: fail_todo_deduced.carbon:[[@LINE+4]]:18: error: no member named 'HasDeducedArg' in namespace 'Carbon::Other' [CppInteropParseError]
|
||||
// CHECK:STDERR: 16 | Carbon::Other::HasDeducedArg(123);
|
||||
// CHECK:STDERR: | ^~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
Carbon::Other::HasDeducedArg(123);
|
||||
}
|
||||
''';
|
||||
|
||||
@@ -0,0 +1,550 @@
|
||||
// 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-FILE: toolchain/testing/testdata/min_prelude/int.carbon
|
||||
//
|
||||
// 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/export/generic.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/export/generic.carbon
|
||||
|
||||
// --- generic_type_impls_interface.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
//@dump-sem-ir-begin
|
||||
interface I {
|
||||
fn Doit(self);
|
||||
}
|
||||
|
||||
class A {
|
||||
impl as I {
|
||||
fn Doit(unused self) {}
|
||||
}
|
||||
}
|
||||
class B {
|
||||
impl as I {
|
||||
fn Doit(unused self) {}
|
||||
}
|
||||
}
|
||||
|
||||
fn F[T:! I](t: T) {
|
||||
t.Doit();
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
void G() {
|
||||
Carbon::A a;
|
||||
Carbon::B b;
|
||||
Carbon::F(a);
|
||||
Carbon::F(b);
|
||||
}
|
||||
''';
|
||||
//@dump-sem-ir-end
|
||||
|
||||
// --- fail_todo_non_type_generic.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
// CHECK:STDERR: fail_todo_non_type_generic.carbon:[[@LINE+4]]:1: error: semantics TODO: `binding maps to a non-type template parameter` [SemanticsTodo]
|
||||
// CHECK:STDERR: fn F[unused N:! i32]() {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn F[unused N:! i32]() {}
|
||||
|
||||
inline Cpp '''
|
||||
void G() {
|
||||
// CHECK:STDERR: fail_todo_non_type_generic.carbon:[[@LINE+8]]:11: error: no member named 'F' in namespace 'Carbon' [CppInteropParseError]
|
||||
// CHECK:STDERR: 20 | Carbon::F<3>();
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_non_type_generic.carbon:[[@LINE+4]]:16: error: expected expression [CppInteropParseError]
|
||||
// CHECK:STDERR: 20 | Carbon::F<3>();
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
Carbon::F<3>();
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_todo_generic_pointer.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
fn F[T:! type](unused t: T*) {}
|
||||
|
||||
inline Cpp '''
|
||||
void G() {
|
||||
int x = 0;
|
||||
int* _Nonnull p = &x;
|
||||
// CHECK:STDERR: fail_todo_generic_pointer.carbon:[[@LINE+7]]:3: error: no matching function for call to 'F' [CppInteropParseError]
|
||||
// CHECK:STDERR: 17 | Carbon::F(p);
|
||||
// CHECK:STDERR: | ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_todo_generic_pointer.carbon:[[@LINE-9]]:30: note: candidate template ignored: deduced type 'T * _Nonnull' of 1st parameter does not match adjusted type 'int * _Nonnull' of argument [with T = int] [CppInteropParseNote]
|
||||
// CHECK:STDERR: 4 | fn F[T:! type](unused t: T*) {}
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
Carbon::F(p);
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_todo_enclosing_generic.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
class A(T:! type) {
|
||||
fn F[U:! type](x: T, y: U);
|
||||
}
|
||||
alias B = A(i32);
|
||||
|
||||
inline Cpp '''
|
||||
void f() {
|
||||
// TODO: this currently fails because `B` can't be imported, but the intent
|
||||
// is to test a generic function within an enclosing generic scope.
|
||||
//
|
||||
// CHECK:STDERR: fail_todo_enclosing_generic.carbon:[[@LINE+8]]:11: error: semantics TODO: `interop with unsupported type` [SemanticsTodo]
|
||||
// CHECK:STDERR: Carbon::B b;
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_todo_enclosing_generic.carbon:[[@LINE+4]]:11: error: no type named 'B' in namespace 'Carbon' [CppInteropParseError]
|
||||
// CHECK:STDERR: 22 | Carbon::B b;
|
||||
// CHECK:STDERR: | ~~~~~~~~^
|
||||
// CHECK:STDERR:
|
||||
Carbon::B b;
|
||||
b.F(1, 2);
|
||||
}
|
||||
''';
|
||||
|
||||
// --- fail_generic_unsupported_type.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
// CHECK:STDERR: fail_generic_unsupported_type.carbon:[[@LINE+4]]:1: error: semantics TODO: `failed to import C++ type` [SemanticsTodo]
|
||||
// CHECK:STDERR: fn F[T:! type](unused t: T) {}
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
fn F[T:! type](unused t: T) {}
|
||||
|
||||
inline Cpp '''
|
||||
void G() {
|
||||
volatile int x;
|
||||
// CHECK:STDERR: fail_generic_unsupported_type.carbon:[[@LINE+7]]:3: error: no matching function for call to 'F' [CppInteropParseError]
|
||||
// CHECK:STDERR: 20 | Carbon::F(x);
|
||||
// CHECK:STDERR: | ^~~~~~~~~
|
||||
// CHECK:STDERR: fail_generic_unsupported_type.carbon:[[@LINE-8]]:29: note: candidate template ignored: substitution failure [with T = volatile int] [CppInteropParseNote]
|
||||
// CHECK:STDERR: 8 | fn F[T:! type](unused t: T) {}
|
||||
// CHECK:STDERR: | ^
|
||||
// CHECK:STDERR:
|
||||
Carbon::F(x);
|
||||
}
|
||||
''';
|
||||
|
||||
// CHECK:STDOUT: --- generic_type_impls_interface.carbon
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: constants {
|
||||
// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete]
|
||||
// CHECK:STDOUT: %Self.37e: %I.type = symbolic_binding Self, 0 [symbolic]
|
||||
// CHECK:STDOUT: %Self.as_type.c84: type = facet_access_type %Self.37e [symbolic]
|
||||
// CHECK:STDOUT: %pattern_type.c60: type = pattern_type %Self.as_type.c84 [symbolic]
|
||||
// CHECK:STDOUT: %self.param_patt.a33: %pattern_type.c60 = value_param_pattern [symbolic]
|
||||
// CHECK:STDOUT: %self.patt.696: %pattern_type.c60 = at_binding_pattern self, %self.param_patt.a33 [symbolic]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type.26f: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%Self.37e) [symbolic]
|
||||
// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.11f: %I.WithSelf.Doit.type.26f = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @I [concrete]
|
||||
// CHECK:STDOUT: %assoc0.628: %I.assoc_type = assoc_entity element0, @I.WithSelf.%I.WithSelf.Doit.decl [concrete]
|
||||
// CHECK:STDOUT: %A: type = class_type @A [concrete]
|
||||
// CHECK:STDOUT: %I.impl_witness.6ad: <witness> = impl_witness @A.as.I.impl.%I.impl_witness_table [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.9ef: type = pattern_type %A [concrete]
|
||||
// CHECK:STDOUT: %self.param_patt.04e: %pattern_type.9ef = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt.312: %pattern_type.9ef = at_binding_pattern self, %self.param_patt.04e [concrete]
|
||||
// CHECK:STDOUT: %A.as.I.impl.Doit.type: type = fn_type @A.as.I.impl.Doit [concrete]
|
||||
// CHECK:STDOUT: %A.as.I.impl.Doit: %A.as.I.impl.Doit.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %I.facet.64b: %I.type = facet_value %A, (%I.impl_witness.6ad) [concrete]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type.5b3: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%I.facet.64b) [concrete]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.dab: %I.WithSelf.Doit.type.5b3 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete]
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness %empty_struct_type [concrete]
|
||||
// CHECK:STDOUT: %B: type = class_type @B [concrete]
|
||||
// CHECK:STDOUT: %I.impl_witness.5b8: <witness> = impl_witness @B.as.I.impl.%I.impl_witness_table [concrete]
|
||||
// CHECK:STDOUT: %pattern_type.e39: type = pattern_type %B [concrete]
|
||||
// CHECK:STDOUT: %self.param_patt.f1f: %pattern_type.e39 = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %self.patt.4eb: %pattern_type.e39 = at_binding_pattern self, %self.param_patt.f1f [concrete]
|
||||
// CHECK:STDOUT: %B.as.I.impl.Doit.type: type = fn_type @B.as.I.impl.Doit [concrete]
|
||||
// CHECK:STDOUT: %B.as.I.impl.Doit: %B.as.I.impl.Doit.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %I.facet.9f8: %I.type = facet_value %B, (%I.impl_witness.5b8) [concrete]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type.2ce: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%I.facet.9f8) [concrete]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.450: %I.WithSelf.Doit.type.2ce = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %type: type = facet_type <type> [concrete]
|
||||
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self]
|
||||
// CHECK:STDOUT: %pattern_type.6cb: type = pattern_type %I.type [concrete]
|
||||
// CHECK:STDOUT: %T.patt: %pattern_type.6cb = symbolic_binding_pattern T, 0 [symbolic]
|
||||
// CHECK:STDOUT: %T: %I.type = symbolic_binding T, 0 [symbolic]
|
||||
// CHECK:STDOUT: %T.as_type: type = facet_access_type %T [symbolic]
|
||||
// CHECK:STDOUT: %pattern_type.b3a: type = pattern_type %T.as_type [symbolic]
|
||||
// CHECK:STDOUT: %t.param_patt.5db: %pattern_type.b3a = value_param_pattern [symbolic]
|
||||
// CHECK:STDOUT: %t.patt.030: %pattern_type.b3a = at_binding_pattern t, %t.param_patt.5db [symbolic]
|
||||
// CHECK:STDOUT: %F.type: type = fn_type @F [concrete]
|
||||
// CHECK:STDOUT: %F: %F.type = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type %T.as_type [symbolic]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type.860: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%T) [symbolic]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.45d: %I.WithSelf.Doit.type.860 = struct_value () [symbolic]
|
||||
// CHECK:STDOUT: %I.lookup_impl_witness: <witness> = lookup_impl_witness %T, @I [symbolic]
|
||||
// CHECK:STDOUT: %.8a9: type = fn_type_with_self_type %I.WithSelf.Doit.type.860, %T [symbolic]
|
||||
// CHECK:STDOUT: %impl.elem0: %.8a9 = impl_witness_access %I.lookup_impl_witness, element0 [symbolic]
|
||||
// CHECK:STDOUT: %self.param_patt.58e: %pattern_type.b3a = value_param_pattern [symbolic]
|
||||
// CHECK:STDOUT: %self.patt.300: %pattern_type.b3a = at_binding_pattern self, %self.param_patt.58e [symbolic]
|
||||
// CHECK:STDOUT: %specific_impl_fn: <specific function> = specific_impl_function %impl.elem0, @I.WithSelf.Doit(%T) [symbolic]
|
||||
// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete]
|
||||
// CHECK:STDOUT: %Destroy.Op.type.1d8f74.2: type = fn_type @Destroy.Op.loc9_9.2 [concrete]
|
||||
// CHECK:STDOUT: %Destroy.Op.1a2547.2: %Destroy.Op.type.1d8f74.2 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %custom_witness.df9cc1.2: <witness> = custom_witness (%Destroy.Op.1a2547.2), @Destroy [concrete]
|
||||
// CHECK:STDOUT: %Destroy.facet.6e5: %Destroy.type = facet_value %A, (%custom_witness.df9cc1.2) [concrete]
|
||||
// CHECK:STDOUT: %Destroy.WithSelf.Op.type.09e: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Destroy.facet.6e5) [concrete]
|
||||
// CHECK:STDOUT: %.dca: type = fn_type_with_self_type %Destroy.WithSelf.Op.type.09e, %Destroy.facet.6e5 [concrete]
|
||||
// CHECK:STDOUT: %Destroy.Op.type.1d8f74.3: type = fn_type @Destroy.Op.loc14 [concrete]
|
||||
// CHECK:STDOUT: %Destroy.Op.1a2547.3: %Destroy.Op.type.1d8f74.3 = struct_value () [concrete]
|
||||
// CHECK:STDOUT: %custom_witness.df9cc1.3: <witness> = custom_witness (%Destroy.Op.1a2547.3), @Destroy [concrete]
|
||||
// CHECK:STDOUT: %Destroy.facet.f70: %Destroy.type = facet_value %B, (%custom_witness.df9cc1.3) [concrete]
|
||||
// CHECK:STDOUT: %Destroy.WithSelf.Op.type.cda: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Destroy.facet.f70) [concrete]
|
||||
// CHECK:STDOUT: %.3d9: type = fn_type_with_self_type %Destroy.WithSelf.Op.type.cda, %Destroy.facet.f70 [concrete]
|
||||
// CHECK:STDOUT: %t.param_patt.169: %pattern_type.9ef = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %t.patt.ee8: %pattern_type.9ef = at_binding_pattern t, %t.param_patt.169 [concrete]
|
||||
// CHECK:STDOUT: %F.specific_fn.f33: <specific function> = specific_function %F, @F(%I.facet.64b) [concrete]
|
||||
// CHECK:STDOUT: %t.param_patt.267: %pattern_type.e39 = value_param_pattern [concrete]
|
||||
// CHECK:STDOUT: %t.patt.062: %pattern_type.e39 = at_binding_pattern t, %t.param_patt.267 [concrete]
|
||||
// CHECK:STDOUT: %F.specific_fn.db2: <specific function> = specific_function %F, @F(%I.facet.9f8) [concrete]
|
||||
// CHECK:STDOUT: %.660: type = fn_type_with_self_type %I.WithSelf.Doit.type.5b3, %I.facet.64b [concrete]
|
||||
// CHECK:STDOUT: %.545: type = fn_type_with_self_type %I.WithSelf.Doit.type.2ce, %I.facet.9f8 [concrete]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: imports {
|
||||
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
|
||||
// CHECK:STDOUT: import Cpp//...
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: file {
|
||||
// CHECK:STDOUT: %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {}
|
||||
// CHECK:STDOUT: %A.decl: type = class_decl @A [concrete = constants.%A] {} {}
|
||||
// CHECK:STDOUT: %B.decl: type = class_decl @B [concrete = constants.%B] {} {}
|
||||
// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] {
|
||||
// CHECK:STDOUT: %T.patt.loc20_7.1: %pattern_type.6cb = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc20_7.2 (constants.%T.patt)]
|
||||
// CHECK:STDOUT: %t.param_patt.loc20_14.1: @F.%pattern_type (%pattern_type.b3a) = value_param_pattern [symbolic = %t.param_patt.loc20_14.2 (constants.%t.param_patt.5db)]
|
||||
// CHECK:STDOUT: %t.patt.loc20_14.1: @F.%pattern_type (%pattern_type.b3a) = at_binding_pattern t, %t.param_patt.loc20_14.1 [symbolic = %t.patt.loc20_14.2 (constants.%t.patt.030)]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %.loc20_10: type = splice_block %I.ref [concrete = constants.%I.type] {
|
||||
// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self]
|
||||
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %T.loc20_7.2: %I.type = symbolic_binding T, 0 [symbolic = %T.loc20_7.1 (constants.%T)]
|
||||
// CHECK:STDOUT: %t.param: @F.%T.as_type.loc20_16.1 (%T.as_type) = value_param call_param0
|
||||
// CHECK:STDOUT: %.loc20_16.1: type = splice_block %.loc20_16.2 [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)] {
|
||||
// CHECK:STDOUT: %T.ref: %I.type = name_ref T, %T.loc20_7.2 [symbolic = %T.loc20_7.1 (constants.%T)]
|
||||
// CHECK:STDOUT: %T.as_type.loc20_16.2: type = facet_access_type %T.ref [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)]
|
||||
// CHECK:STDOUT: %.loc20_16.2: type = converted %T.ref, %T.as_type.loc20_16.2 [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %t: @F.%T.as_type.loc20_16.1 (%T.as_type) = wrapper_binding t, %t.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
|
||||
// CHECK:STDOUT: inline_cpp "void G() {\n Carbon::A a;\n Carbon::B b;\n Carbon::F(a);\n Carbon::F(b);\n}\n"
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: interface @I {
|
||||
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = constants.%Self.37e]
|
||||
// CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I [concrete]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !with Self:
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.decl: @I.WithSelf.%I.WithSelf.Doit.type (%I.WithSelf.Doit.type.26f) = fn_decl @I.WithSelf.Doit [symbolic = @I.WithSelf.%I.WithSelf.Doit (constants.%I.WithSelf.Doit.11f)] {
|
||||
// CHECK:STDOUT: %self.param_patt.loc6_11.1: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = value_param_pattern [symbolic = %self.param_patt.loc6_11.2 (constants.%self.param_patt.a33)]
|
||||
// CHECK:STDOUT: %self.patt.loc6_11.1: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = at_binding_pattern self, %self.param_patt.loc6_11.1 [symbolic = %self.patt.loc6_11.2 (constants.%self.patt.696)]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %self.param: @I.WithSelf.Doit.%Self.as_type.loc6_11.1 (%Self.as_type.c84) = value_param call_param0
|
||||
// CHECK:STDOUT: %.loc6_11.1: type = splice_block %.loc6_11.2 [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)] {
|
||||
// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self.37e)]
|
||||
// CHECK:STDOUT: %Self.as_type.loc6_11.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)]
|
||||
// CHECK:STDOUT: %.loc6_11.2: type = converted %Self.ref, %Self.as_type.loc6_11.2 [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %self: @I.WithSelf.Doit.%Self.as_type.loc6_11.1 (%Self.as_type.c84) = wrapper_binding self, %self.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %I.WithSelf.Doit.decl [concrete = constants.%assoc0.628]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = %Self
|
||||
// CHECK:STDOUT: .Doit = @I.WithSelf.%assoc0
|
||||
// CHECK:STDOUT: witness = (@I.WithSelf.%I.WithSelf.Doit.decl)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !requires:
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @A.as.I.impl: %Self.ref as %I.ref {
|
||||
// CHECK:STDOUT: %A.as.I.impl.Doit.decl: %A.as.I.impl.Doit.type = fn_decl @A.as.I.impl.Doit [concrete = constants.%A.as.I.impl.Doit] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.9ef = value_param_pattern [concrete = constants.%self.param_patt.04e]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.9ef = at_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.312]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %self.param: %A = value_param call_param0
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%A [concrete = constants.%A]
|
||||
// CHECK:STDOUT: %self: %A = wrapper_binding self, %self.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (%A.as.I.impl.Doit.decl), @A.as.I.impl [concrete]
|
||||
// CHECK:STDOUT: %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness.6ad]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Doit = %A.as.I.impl.Doit.decl
|
||||
// CHECK:STDOUT: extend %I.ref
|
||||
// CHECK:STDOUT: witness = %I.impl_witness
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: impl @B.as.I.impl: %Self.ref as %I.ref {
|
||||
// CHECK:STDOUT: %B.as.I.impl.Doit.decl: %B.as.I.impl.Doit.type = fn_decl @B.as.I.impl.Doit [concrete = constants.%B.as.I.impl.Doit] {
|
||||
// CHECK:STDOUT: %self.param_patt: %pattern_type.e39 = value_param_pattern [concrete = constants.%self.param_patt.f1f]
|
||||
// CHECK:STDOUT: %self.patt: %pattern_type.e39 = at_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.4eb]
|
||||
// CHECK:STDOUT: } {
|
||||
// CHECK:STDOUT: %self.param: %B = value_param call_param0
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B [concrete = constants.%B]
|
||||
// CHECK:STDOUT: %self: %B = wrapper_binding self, %self.param
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (%B.as.I.impl.Doit.decl), @B.as.I.impl [concrete]
|
||||
// CHECK:STDOUT: %I.impl_witness: <witness> = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness.5b8]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Doit = %B.as.I.impl.Doit.decl
|
||||
// CHECK:STDOUT: extend %I.ref
|
||||
// CHECK:STDOUT: witness = %I.impl_witness
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @A {
|
||||
// CHECK:STDOUT: impl_decl @A.as.I.impl [concrete] {} {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%A [concrete = constants.%A]
|
||||
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%A
|
||||
// CHECK:STDOUT: .I = <poisoned>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @B {
|
||||
// CHECK:STDOUT: impl_decl @B.as.I.impl [concrete] {} {
|
||||
// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B [concrete = constants.%B]
|
||||
// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type]
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: %complete_type: <witness> = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type]
|
||||
// CHECK:STDOUT: complete_type_witness = %complete_type
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .Self = constants.%B
|
||||
// CHECK:STDOUT: .I = <poisoned>
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic fn @I.WithSelf.Doit(@I.%Self: %I.type) {
|
||||
// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.37e)]
|
||||
// CHECK:STDOUT: %Self.as_type.loc6_11.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)]
|
||||
// CHECK:STDOUT: %pattern_type: type = pattern_type %Self.as_type.loc6_11.1 [symbolic = %pattern_type (constants.%pattern_type.c60)]
|
||||
// CHECK:STDOUT: %self.param_patt.loc6_11.2: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = value_param_pattern [symbolic = %self.param_patt.loc6_11.2 (constants.%self.param_patt.a33)]
|
||||
// CHECK:STDOUT: %self.patt.loc6_11.2: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = at_binding_pattern self, %self.param_patt.loc6_11.2 [symbolic = %self.patt.loc6_11.2 (constants.%self.patt.696)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn(%self.param: @I.WithSelf.Doit.%Self.as_type.loc6_11.1 (%Self.as_type.c84));
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @A.as.I.impl.Doit(%self.param: %A) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @B.as.I.impl.Doit(%self.param: %B) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: generic fn @F(%T.loc20_7.2: %I.type) {
|
||||
// CHECK:STDOUT: %T.patt.loc20_7.2: %pattern_type.6cb = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc20_7.2 (constants.%T.patt)]
|
||||
// CHECK:STDOUT: %T.loc20_7.1: %I.type = symbolic_binding T, 0 [symbolic = %T.loc20_7.1 (constants.%T)]
|
||||
// CHECK:STDOUT: %T.as_type.loc20_16.1: type = facet_access_type %T.loc20_7.1 [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)]
|
||||
// CHECK:STDOUT: %pattern_type: type = pattern_type %T.as_type.loc20_16.1 [symbolic = %pattern_type (constants.%pattern_type.b3a)]
|
||||
// CHECK:STDOUT: %t.param_patt.loc20_14.2: @F.%pattern_type (%pattern_type.b3a) = value_param_pattern [symbolic = %t.param_patt.loc20_14.2 (constants.%t.param_patt.5db)]
|
||||
// CHECK:STDOUT: %t.patt.loc20_14.2: @F.%pattern_type (%pattern_type.b3a) = at_binding_pattern t, %t.param_patt.loc20_14.2 [symbolic = %t.patt.loc20_14.2 (constants.%t.patt.030)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %require_complete: <witness> = require_complete_type %T.as_type.loc20_16.1 [symbolic = %require_complete (constants.%require_complete)]
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%T.loc20_7.1) [symbolic = %I.WithSelf.Doit.type (constants.%I.WithSelf.Doit.type.860)]
|
||||
// CHECK:STDOUT: %.loc21_4: type = fn_type_with_self_type %I.WithSelf.Doit.type, %T.loc20_7.1 [symbolic = %.loc21_4 (constants.%.8a9)]
|
||||
// CHECK:STDOUT: %I.lookup_impl_witness: <witness> = lookup_impl_witness %T.loc20_7.1, @I [symbolic = %I.lookup_impl_witness (constants.%I.lookup_impl_witness)]
|
||||
// CHECK:STDOUT: %impl.elem0.loc21_4.2: @F.%.loc21_4 (%.8a9) = impl_witness_access %I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc21_4.2 (constants.%impl.elem0)]
|
||||
// CHECK:STDOUT: %specific_impl_fn.loc21_4.2: <specific function> = specific_impl_function %impl.elem0.loc21_4.2, @I.WithSelf.Doit(%T.loc20_7.1) [symbolic = %specific_impl_fn.loc21_4.2 (constants.%specific_impl_fn)]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn(%t.param: @F.%T.as_type.loc20_16.1 (%T.as_type)) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %t.ref: @F.%T.as_type.loc20_16.1 (%T.as_type) = name_ref t, %t
|
||||
// CHECK:STDOUT: %Doit.ref: %I.assoc_type = name_ref Doit, @I.WithSelf.%assoc0 [concrete = constants.%assoc0.628]
|
||||
// CHECK:STDOUT: %impl.elem0.loc21_4.1: @F.%.loc21_4 (%.8a9) = impl_witness_access constants.%I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc21_4.2 (constants.%impl.elem0)]
|
||||
// CHECK:STDOUT: %bound_method.loc21_4: <bound method> = bound_method %t.ref, %impl.elem0.loc21_4.1
|
||||
// CHECK:STDOUT: %.loc21_10.1: %I.type = converted constants.%T.as_type, constants.%T [symbolic = %T.loc20_7.1 (constants.%T)]
|
||||
// CHECK:STDOUT: %.loc21_10.2: %I.type = converted constants.%T.as_type, constants.%T [symbolic = %T.loc20_7.1 (constants.%T)]
|
||||
// CHECK:STDOUT: %specific_impl_fn.loc21_4.1: <specific function> = specific_impl_function %impl.elem0.loc21_4.1, @I.WithSelf.Doit(constants.%T) [symbolic = %specific_impl_fn.loc21_4.2 (constants.%specific_impl_fn)]
|
||||
// CHECK:STDOUT: %bound_method.loc21_10: <bound method> = bound_method %t.ref, %specific_impl_fn.loc21_4.1
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.call: init %empty_tuple.type = call %bound_method.loc21_10(%t.ref)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @A.__destroy_thunk(%self.param: ref %A) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %impl.elem0: %.dca = impl_witness_access constants.%custom_witness.df9cc1.2, element0 [concrete = constants.%Destroy.Op.1a2547.2]
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %self.param, %impl.elem0
|
||||
// CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %bound_method(%self.param)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc9_9.1(%self.param: ref %empty_struct_type) = "no_op";
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc9_9.2(%self.param: ref %A) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @B.__destroy_thunk(%self.param: ref %B) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %impl.elem0: %.3d9 = impl_witness_access constants.%custom_witness.df9cc1.3, element0 [concrete = constants.%Destroy.Op.1a2547.3]
|
||||
// CHECK:STDOUT: %bound_method: <bound method> = bound_method %self.param, %impl.elem0
|
||||
// CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %bound_method(%self.param)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Destroy.Op.loc14(%self.param: ref %B) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F__carbon_thunkinst64000035(%_.param: ref %A) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %F__carbon_thunkinst64000035.ref: %F.type = name_ref F__carbon_thunkinst64000035, file.%F.decl [concrete = constants.%F]
|
||||
// CHECK:STDOUT: %I.facet.loc20_19.1: %I.type = facet_value constants.%A, (constants.%I.impl_witness.6ad) [concrete = constants.%I.facet.64b]
|
||||
// CHECK:STDOUT: %.loc20_19.1: %I.type = converted constants.%A, %I.facet.loc20_19.1 [concrete = constants.%I.facet.64b]
|
||||
// CHECK:STDOUT: %I.facet.loc20_19.2: %I.type = facet_value constants.%A, (constants.%I.impl_witness.6ad) [concrete = constants.%I.facet.64b]
|
||||
// CHECK:STDOUT: %.loc20_19.2: %I.type = converted constants.%A, %I.facet.loc20_19.2 [concrete = constants.%I.facet.64b]
|
||||
// CHECK:STDOUT: %F.specific_fn: <specific function> = specific_function %F__carbon_thunkinst64000035.ref, @F(constants.%I.facet.64b) [concrete = constants.%F.specific_fn.f33]
|
||||
// CHECK:STDOUT: %.loc20_19.3: %A = acquire_value %_.param
|
||||
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.specific_fn(%.loc20_19.3)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F__carbon_thunkinst64000050(%_.param: ref %B) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %F__carbon_thunkinst64000050.ref: %F.type = name_ref F__carbon_thunkinst64000050, file.%F.decl [concrete = constants.%F]
|
||||
// CHECK:STDOUT: %I.facet.loc20_19.1: %I.type = facet_value constants.%B, (constants.%I.impl_witness.5b8) [concrete = constants.%I.facet.9f8]
|
||||
// CHECK:STDOUT: %.loc20_19.1: %I.type = converted constants.%B, %I.facet.loc20_19.1 [concrete = constants.%I.facet.9f8]
|
||||
// CHECK:STDOUT: %I.facet.loc20_19.2: %I.type = facet_value constants.%B, (constants.%I.impl_witness.5b8) [concrete = constants.%I.facet.9f8]
|
||||
// CHECK:STDOUT: %.loc20_19.2: %I.type = converted constants.%B, %I.facet.loc20_19.2 [concrete = constants.%I.facet.9f8]
|
||||
// CHECK:STDOUT: %F.specific_fn: <specific function> = specific_function %F__carbon_thunkinst64000050.ref, @F(constants.%I.facet.9f8) [concrete = constants.%F.specific_fn.db2]
|
||||
// CHECK:STDOUT: %.loc20_19.3: %B = acquire_value %_.param
|
||||
// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.specific_fn(%.loc20_19.3)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf(constants.%Self.37e) {
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %Self => constants.%Self.37e
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.26f
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.11f
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%Self.37e) {
|
||||
// CHECK:STDOUT: %Self => constants.%Self.37e
|
||||
// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%Self.as_type.c84
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.c60
|
||||
// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.a33
|
||||
// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.696
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf(constants.%I.facet.64b) {
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %Self => constants.%I.facet.64b
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.5b3
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.dab
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%I.facet.64b) {
|
||||
// CHECK:STDOUT: %Self => constants.%I.facet.64b
|
||||
// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%A
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.9ef
|
||||
// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.04e
|
||||
// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.312
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf(constants.%I.facet.9f8) {
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %Self => constants.%I.facet.9f8
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.2ce
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.450
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%I.facet.9f8) {
|
||||
// CHECK:STDOUT: %Self => constants.%I.facet.9f8
|
||||
// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%B
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.e39
|
||||
// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.f1f
|
||||
// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.4eb
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @F(constants.%T) {
|
||||
// CHECK:STDOUT: %T.patt.loc20_7.2 => constants.%T.patt
|
||||
// CHECK:STDOUT: %T.loc20_7.1 => constants.%T
|
||||
// CHECK:STDOUT: %T.as_type.loc20_16.1 => constants.%T.as_type
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.b3a
|
||||
// CHECK:STDOUT: %t.param_patt.loc20_14.2 => constants.%t.param_patt.5db
|
||||
// CHECK:STDOUT: %t.patt.loc20_14.2 => constants.%t.patt.030
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf(constants.%T) {
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %Self => constants.%T
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.860
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.45d
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%T) {
|
||||
// CHECK:STDOUT: %Self => constants.%T
|
||||
// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%T.as_type
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.b3a
|
||||
// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.58e
|
||||
// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.300
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @F(constants.%I.facet.64b) {
|
||||
// CHECK:STDOUT: %T.patt.loc20_7.2 => constants.%T.patt
|
||||
// CHECK:STDOUT: %T.loc20_7.1 => constants.%I.facet.64b
|
||||
// CHECK:STDOUT: %T.as_type.loc20_16.1 => constants.%A
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.9ef
|
||||
// CHECK:STDOUT: %t.param_patt.loc20_14.2 => constants.%t.param_patt.169
|
||||
// CHECK:STDOUT: %t.patt.loc20_14.2 => constants.%t.patt.ee8
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %require_complete => constants.%complete_type
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.5b3
|
||||
// CHECK:STDOUT: %.loc21_4 => constants.%.660
|
||||
// CHECK:STDOUT: %I.lookup_impl_witness => constants.%I.impl_witness.6ad
|
||||
// CHECK:STDOUT: %impl.elem0.loc21_4.2 => constants.%A.as.I.impl.Doit
|
||||
// CHECK:STDOUT: %specific_impl_fn.loc21_4.2 => constants.%A.as.I.impl.Doit
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: specific @F(constants.%I.facet.9f8) {
|
||||
// CHECK:STDOUT: %T.patt.loc20_7.2 => constants.%T.patt
|
||||
// CHECK:STDOUT: %T.loc20_7.1 => constants.%I.facet.9f8
|
||||
// CHECK:STDOUT: %T.as_type.loc20_16.1 => constants.%B
|
||||
// CHECK:STDOUT: %pattern_type => constants.%pattern_type.e39
|
||||
// CHECK:STDOUT: %t.param_patt.loc20_14.2 => constants.%t.param_patt.267
|
||||
// CHECK:STDOUT: %t.patt.loc20_14.2 => constants.%t.patt.062
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !definition:
|
||||
// CHECK:STDOUT: %require_complete => constants.%complete_type
|
||||
// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.2ce
|
||||
// CHECK:STDOUT: %.loc21_4 => constants.%.545
|
||||
// CHECK:STDOUT: %I.lookup_impl_witness => constants.%I.impl_witness.5b8
|
||||
// CHECK:STDOUT: %impl.elem0.loc21_4.2 => constants.%B.as.I.impl.Doit
|
||||
// CHECK:STDOUT: %specific_impl_fn.loc21_4.2 => constants.%B.as.I.impl.Doit
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -0,0 +1,329 @@
|
||||
// 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-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/function/export/generic.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/function/export/generic.carbon
|
||||
|
||||
// --- generic_type_impls_interface.carbon
|
||||
library "[[@TEST_NAME]]";
|
||||
import Cpp;
|
||||
|
||||
interface I {
|
||||
fn Doit(self);
|
||||
}
|
||||
|
||||
class A {
|
||||
impl as I {
|
||||
fn Doit(unused self) {}
|
||||
}
|
||||
}
|
||||
class B {
|
||||
impl as I {
|
||||
fn Doit(unused self) {}
|
||||
}
|
||||
}
|
||||
|
||||
fn F[T:! I](t: T) {
|
||||
t.Doit();
|
||||
}
|
||||
|
||||
inline Cpp '''
|
||||
void G() {
|
||||
Carbon::A a;
|
||||
Carbon::B b;
|
||||
Carbon::F(a);
|
||||
Carbon::F(b);
|
||||
}
|
||||
''';
|
||||
|
||||
fn Run() {
|
||||
Cpp.G();
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: ; ---
|
||||
// CHECK:STDOUT: ; ModuleID = 'generic_type_impls_interface.carbon'
|
||||
// CHECK:STDOUT: source_filename = "generic_type_impls_interface.carbon"
|
||||
// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
|
||||
// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu"
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: %"class.Carbon::A" = type {}
|
||||
// CHECK:STDOUT: %"class.Carbon::B" = type {}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon1AD2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon1BD2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable
|
||||
// CHECK:STDOUT: define dso_local void @_Z1Gv() #0 personality ptr @__gxx_personality_v0 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %a = alloca %"class.Carbon::A", align 1
|
||||
// CHECK:STDOUT: %b = alloca %"class.Carbon::B", align 1
|
||||
// CHECK:STDOUT: %agg.tmp = alloca %"class.Carbon::A", align 1
|
||||
// CHECK:STDOUT: %exn.slot = alloca ptr, align 8
|
||||
// CHECK:STDOUT: %ehselector.slot = alloca i32, align 4
|
||||
// CHECK:STDOUT: %agg.tmp1 = alloca %"class.Carbon::B", align 1
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b) #4
|
||||
// CHECK:STDOUT: invoke void @_ZN6CarbonL1FENS_1AE()
|
||||
// CHECK:STDOUT: to label %invoke.cont unwind label %lpad
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: invoke.cont: ; preds = %entry
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %agg.tmp) #4
|
||||
// CHECK:STDOUT: invoke void @_ZN6CarbonL1FENS_1BE()
|
||||
// CHECK:STDOUT: to label %invoke.cont3 unwind label %lpad2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: invoke.cont3: ; preds = %invoke.cont
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %agg.tmp1) #4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %b) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %b) #4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %a) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %a) #4
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: lpad: ; preds = %entry
|
||||
// CHECK:STDOUT: %0 = landingpad { ptr, i32 }
|
||||
// CHECK:STDOUT: cleanup
|
||||
// CHECK:STDOUT: %1 = extractvalue { ptr, i32 } %0, 0
|
||||
// CHECK:STDOUT: store ptr %1, ptr %exn.slot, align 8
|
||||
// CHECK:STDOUT: %2 = extractvalue { ptr, i32 } %0, 1
|
||||
// CHECK:STDOUT: store i32 %2, ptr %ehselector.slot, align 4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %agg.tmp) #4
|
||||
// CHECK:STDOUT: br label %ehcleanup
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: lpad2: ; preds = %invoke.cont
|
||||
// CHECK:STDOUT: %3 = landingpad { ptr, i32 }
|
||||
// CHECK:STDOUT: cleanup
|
||||
// CHECK:STDOUT: %4 = extractvalue { ptr, i32 } %3, 0
|
||||
// CHECK:STDOUT: store ptr %4, ptr %exn.slot, align 8
|
||||
// CHECK:STDOUT: %5 = extractvalue { ptr, i32 } %3, 1
|
||||
// CHECK:STDOUT: store i32 %5, ptr %ehselector.slot, align 4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %agg.tmp1) #4
|
||||
// CHECK:STDOUT: br label %ehcleanup
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ehcleanup: ; preds = %lpad2, %lpad
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %b) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %b) #4
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %a) #4
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %a) #4
|
||||
// CHECK:STDOUT: br label %eh.resume
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: eh.resume: ; preds = %ehcleanup
|
||||
// CHECK:STDOUT: %exn = load ptr, ptr %exn.slot, align 8
|
||||
// CHECK:STDOUT: %sel = load i32, ptr %ehselector.slot, align 4
|
||||
// CHECK:STDOUT: %lpad.val = insertvalue { ptr, i32 } poison, ptr %exn, 0
|
||||
// CHECK:STDOUT: %lpad.val7 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1
|
||||
// CHECK:STDOUT: resume { ptr, i32 } %lpad.val7
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; uselistorder directives
|
||||
// CHECK:STDOUT: uselistorder ptr %a, { 0, 2, 1, 3, 4 }
|
||||
// CHECK:STDOUT: uselistorder ptr %b, { 0, 2, 1, 3, 4 }
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define internal void @_ZN6CarbonL1FENS_1AE() #2 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %0 = alloca %"class.Carbon::A", align 1
|
||||
// CHECK:STDOUT: call void @_CF__carbon_thunkinst70000035.Main(ptr noundef nonnull align 1 %0)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare i32 @__gxx_personality_v0(...)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %this) unnamed_addr #3 comdat align 2 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !11
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.A.Main"(ptr noundef nonnull align 1 %this1)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define internal void @_ZN6CarbonL1FENS_1BE() #2 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %0 = alloca %"class.Carbon::B", align 1
|
||||
// CHECK:STDOUT: call void @_CF__carbon_thunkinst70000050.Main(ptr noundef nonnull align 1 %0)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %this) unnamed_addr #3 comdat align 2 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !14
|
||||
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.B.Main"(ptr noundef nonnull align 1 %this1)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.end.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @"_CDoit.A.Main:I.Main"(ptr %self) #4 !dbg !16 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !22
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @"_CDoit.B.Main:I.Main"(ptr %self) #4 !dbg !23 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !26
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.A.Main"(ptr %self) #5 !dbg !27 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.68011419f123494e:core.Destroy.Core"(ptr %self), !dbg !30
|
||||
// CHECK:STDOUT: ret void, !dbg !30
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.68011419f123494e:core.Destroy.Core"(ptr %self) #4 !dbg !31 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !34
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.B.Main"(ptr %self) #5 !dbg !35 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.6c3865e9cbd9f6de:core.Destroy.Core"(ptr %self), !dbg !38
|
||||
// CHECK:STDOUT: ret void, !dbg !38
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.6c3865e9cbd9f6de:core.Destroy.Core"(ptr %self) #4 !dbg !39 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !42
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CF__carbon_thunkinst70000035.Main(ptr %_) #4 !dbg !43 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @_CF.Main.3e1f7ed08cd9ee58(ptr %_), !dbg !46
|
||||
// CHECK:STDOUT: ret void, !dbg !46
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_CF__carbon_thunkinst70000050.Main(ptr %_) #4 !dbg !47 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @_CF.Main.bd1b6d59f703c190(ptr %_), !dbg !50
|
||||
// CHECK:STDOUT: ret void, !dbg !50
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define i32 @main() #4 !dbg !51 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @_Z1Gv(), !dbg !55
|
||||
// CHECK:STDOUT: ret i32 0, !dbg !56
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define linkonce_odr void @_CF.Main.3e1f7ed08cd9ee58(ptr %t) #4 !dbg !57 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_CDoit.A.Main:I.Main"(ptr %t), !dbg !60
|
||||
// CHECK:STDOUT: ret void, !dbg !61
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define linkonce_odr void @_CF.Main.bd1b6d59f703c190(ptr %t) #4 !dbg !62 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_CDoit.B.Main:I.Main"(ptr %t), !dbg !65
|
||||
// CHECK:STDOUT: ret void, !dbg !66
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; uselistorder directives
|
||||
// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 1, 0 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon1AD2Ev, { 0, 2, 1, 3 }
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon1BD2Ev, { 0, 2, 1, 3 }
|
||||
// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.end.p0, { 3, 1, 2, 0 }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
// CHECK:STDOUT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT: attributes #2 = { alwaysinline mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||
// CHECK:STDOUT: attributes #4 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #5 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!0}
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6}
|
||||
// CHECK:STDOUT: !llvm.errno.tbaa = !{!7}
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
|
||||
// CHECK:STDOUT: !1 = !DIFile(filename: "generic_type_impls_interface.carbon", directory: "")
|
||||
// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2}
|
||||
// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2}
|
||||
// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2}
|
||||
// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5}
|
||||
// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
// CHECK:STDOUT: !7 = !{!8, !8, i64 0}
|
||||
// CHECK:STDOUT: !8 = !{!"int", !9, i64 0}
|
||||
// CHECK:STDOUT: !9 = !{!"omnipotent char", !10, i64 0}
|
||||
// CHECK:STDOUT: !10 = !{!"Simple C++ TBAA"}
|
||||
// CHECK:STDOUT: !11 = !{!12, !12, i64 0}
|
||||
// CHECK:STDOUT: !12 = !{!"p1 _ZTSN6Carbon1AE", !13, i64 0}
|
||||
// CHECK:STDOUT: !13 = !{!"any pointer", !9, i64 0}
|
||||
// CHECK:STDOUT: !14 = !{!15, !15, i64 0}
|
||||
// CHECK:STDOUT: !15 = !{!"p1 _ZTSN6Carbon1BE", !13, i64 0}
|
||||
// CHECK:STDOUT: !16 = distinct !DISubprogram(name: "Doit", linkageName: "_CDoit.A.Main:I.Main", scope: null, file: !1, line: 10, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20)
|
||||
// CHECK:STDOUT: !17 = !DISubroutineType(types: !18)
|
||||
// CHECK:STDOUT: !18 = !{null, !19}
|
||||
// CHECK:STDOUT: !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
|
||||
// CHECK:STDOUT: !20 = !{!21}
|
||||
// CHECK:STDOUT: !21 = !DILocalVariable(arg: 1, scope: !16, type: !19)
|
||||
// CHECK:STDOUT: !22 = !DILocation(line: 10, column: 5, scope: !16)
|
||||
// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "Doit", linkageName: "_CDoit.B.Main:I.Main", scope: null, file: !1, line: 15, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !24)
|
||||
// CHECK:STDOUT: !24 = !{!25}
|
||||
// CHECK:STDOUT: !25 = !DILocalVariable(arg: 1, scope: !23, type: !19)
|
||||
// CHECK:STDOUT: !26 = !DILocation(line: 15, column: 5, scope: !23)
|
||||
// CHECK:STDOUT: !27 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.A.Main", scope: null, file: !1, line: 8, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !28)
|
||||
// CHECK:STDOUT: !28 = !{!29}
|
||||
// CHECK:STDOUT: !29 = !DILocalVariable(arg: 1, scope: !27, type: !19)
|
||||
// CHECK:STDOUT: !30 = !DILocation(line: 8, column: 1, scope: !27)
|
||||
// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "Op", linkageName: "_COp.68011419f123494e:core.Destroy.Core", scope: null, file: !1, line: 8, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !32)
|
||||
// CHECK:STDOUT: !32 = !{!33}
|
||||
// CHECK:STDOUT: !33 = !DILocalVariable(arg: 1, scope: !31, type: !19)
|
||||
// CHECK:STDOUT: !34 = !DILocation(line: 8, column: 1, scope: !31)
|
||||
// CHECK:STDOUT: !35 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.B.Main", scope: null, file: !1, line: 13, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !36)
|
||||
// CHECK:STDOUT: !36 = !{!37}
|
||||
// CHECK:STDOUT: !37 = !DILocalVariable(arg: 1, scope: !35, type: !19)
|
||||
// CHECK:STDOUT: !38 = !DILocation(line: 13, column: 1, scope: !35)
|
||||
// CHECK:STDOUT: !39 = distinct !DISubprogram(name: "Op", linkageName: "_COp.6c3865e9cbd9f6de:core.Destroy.Core", scope: null, file: !1, line: 13, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !40)
|
||||
// CHECK:STDOUT: !40 = !{!41}
|
||||
// CHECK:STDOUT: !41 = !DILocalVariable(arg: 1, scope: !39, type: !19)
|
||||
// CHECK:STDOUT: !42 = !DILocation(line: 13, column: 1, scope: !39)
|
||||
// CHECK:STDOUT: !43 = distinct !DISubprogram(name: "F__carbon_thunkinst70000035", linkageName: "_CF__carbon_thunkinst70000035.Main", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !44)
|
||||
// CHECK:STDOUT: !44 = !{!45}
|
||||
// CHECK:STDOUT: !45 = !DILocalVariable(arg: 1, scope: !43, type: !19)
|
||||
// CHECK:STDOUT: !46 = !DILocation(line: 19, column: 1, scope: !43)
|
||||
// CHECK:STDOUT: !47 = distinct !DISubprogram(name: "F__carbon_thunkinst70000050", linkageName: "_CF__carbon_thunkinst70000050.Main", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !48)
|
||||
// CHECK:STDOUT: !48 = !{!49}
|
||||
// CHECK:STDOUT: !49 = !DILocalVariable(arg: 1, scope: !47, type: !19)
|
||||
// CHECK:STDOUT: !50 = !DILocation(line: 19, column: 1, scope: !47)
|
||||
// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "Run", linkageName: "main", scope: null, file: !1, line: 32, type: !52, spFlags: DISPFlagDefinition, unit: !0)
|
||||
// CHECK:STDOUT: !52 = !DISubroutineType(types: !53)
|
||||
// CHECK:STDOUT: !53 = !{!54}
|
||||
// CHECK:STDOUT: !54 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
// CHECK:STDOUT: !55 = !DILocation(line: 33, column: 3, scope: !51)
|
||||
// CHECK:STDOUT: !56 = !DILocation(line: 32, column: 1, scope: !51)
|
||||
// CHECK:STDOUT: !57 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main.3e1f7ed08cd9ee58", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !58)
|
||||
// CHECK:STDOUT: !58 = !{!59}
|
||||
// CHECK:STDOUT: !59 = !DILocalVariable(arg: 1, scope: !57, type: !19)
|
||||
// CHECK:STDOUT: !60 = !DILocation(line: 20, column: 3, scope: !57)
|
||||
// CHECK:STDOUT: !61 = !DILocation(line: 19, column: 1, scope: !57)
|
||||
// CHECK:STDOUT: !62 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main.bd1b6d59f703c190", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !63)
|
||||
// CHECK:STDOUT: !63 = !{!64}
|
||||
// CHECK:STDOUT: !64 = !DILocalVariable(arg: 1, scope: !62, type: !19)
|
||||
// CHECK:STDOUT: !65 = !DILocation(line: 20, column: 3, scope: !62)
|
||||
// CHECK:STDOUT: !66 = !DILocation(line: 19, column: 1, scope: !62)
|
||||
// CHECK:STDOUT:
|
||||
Reference in New Issue
Block a user