From 1d314c7c4da5a8acb3106a9f66b5f744f1de0dec Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Wed, 6 Aug 2025 14:02:38 +0200 Subject: [PATCH] Import C++ constructors of class `Type` `fn Type(...) -> Type` (#5879) Only supports classes with a single (non copy non move) constructor (without default values), until overloading is supported. Based on #5878. C++ Interop Demo: ```c++ // hello_world.h #include class C { public: C(int x, int y) : x_(x), y_(y) {} int x() const { return x_;} int y() const { return y_;} private: int x_; int y_; }; void hello_world(C* _Nonnull c); ``` ```c++ // hello_world.cpp #include "hello_world.h" #include void hello_world(C* _Nonnull c) { printf("C.x = %d. C.y = %d\n", c->x(), c->y()); } ``` ```carbon // main.carbon library "Main"; import Cpp library "hello_world.h"; fn Run() -> i32 { var c : Cpp.C = Cpp.C.C(1, 2); Cpp.hello_world(&c); 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 C.x = 1. C.y = 2 ``` Part of #5880. --- toolchain/check/import_cpp.cpp | 218 ++++- toolchain/check/import_cpp.h | 3 +- .../interop/cpp/class/constructor.carbon | 750 ++++++++++++++++++ toolchain/lower/BUILD | 2 + toolchain/lower/clang_global_decl.cpp | 18 + toolchain/lower/clang_global_decl.h | 19 + toolchain/lower/file_context.cpp | 3 +- toolchain/lower/mangler.cpp | 3 +- .../testdata/interop/cpp/constructor.carbon | 101 +++ 9 files changed, 1074 insertions(+), 43 deletions(-) create mode 100644 toolchain/check/testdata/interop/cpp/class/constructor.carbon create mode 100644 toolchain/lower/clang_global_decl.cpp create mode 100644 toolchain/lower/clang_global_decl.h create mode 100644 toolchain/lower/testdata/interop/cpp/constructor.carbon diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index 9df4855339aa..4e9def1f584b 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -45,6 +45,7 @@ #include "toolchain/diagnostics/format_providers.h" #include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/clang_decl.h" +#include "toolchain/sem_ir/class.h" #include "toolchain/sem_ir/function.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" @@ -455,10 +456,10 @@ auto ImportCppFiles(Context& context, return std::move(generated_ast); } -// Look ups the given name in the Clang AST in a specific scope. Returns the +// Looks up the given name in the Clang AST in a specific scope. Returns the // lookup result if lookup was successful. -static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, - SemIR::NameId name_id) +static auto ClangLookupName(Context& context, SemIR::NameScopeId scope_id, + SemIR::NameId name_id) -> std::optional { std::optional name = context.names().GetAsStringIfIdentifier(name_id); @@ -497,6 +498,112 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, return lookup; } +// Looks up for constructors in the class scope and returns the lookup result. +static auto ClangConstructorLookup(const Context& context, + SemIR::NameScopeId scope_id) + -> clang::DeclContextLookupResult { + const SemIR::NameScope& scope = context.sem_ir().name_scopes().Get(scope_id); + + clang::Sema& sema = context.sem_ir().cpp_ast()->getSema(); + clang::Decl* decl = + context.sem_ir().clang_decls().Get(scope.clang_decl_context_id()).decl; + return sema.LookupConstructors(cast(decl)); +} + +// Returns true if the given Clang declaration is the implicit injected class +// name within the class. +static auto IsDeclInjectedClassName(const Context& context, + SemIR::NameScopeId scope_id, + SemIR::NameId name_id, + const clang::NamedDecl* named_decl) + -> bool { + if (!named_decl->isImplicit()) { + return false; + } + + const auto* record_decl = dyn_cast(named_decl); + if (!record_decl) { + return false; + } + + const SemIR::ClangDecl& clang_decl = context.sem_ir().clang_decls().Get( + context.sem_ir().name_scopes().Get(scope_id).clang_decl_context_id()); + const auto* scope_record_decl = cast(clang_decl.decl); + + const clang::ASTContext& ast_context = + context.sem_ir().cpp_ast()->getASTContext(); + CARBON_CHECK( + ast_context.getCanonicalType( + ast_context.getRecordType(scope_record_decl)) == + ast_context.getCanonicalType(ast_context.getRecordType(record_decl))); + + auto class_decl = + context.sem_ir().insts().GetAs(clang_decl.inst_id); + CARBON_CHECK(name_id == + context.sem_ir().classes().Get(class_decl.class_id).name_id); + return true; +} + +// Looks up the given name in the Clang AST in a specific scope, and returns the +// found declaration and its access. If the found declaration is the injected +// class name, looks up constructors instead. If not found, returns `nullopt`. +// If there's not a single result, returns `nullptr` and default access. +// Otherwise, returns the single declaration and its access. +static auto ClangLookup(Context& context, SemIR::LocId loc_id, + SemIR::NameScopeId scope_id, SemIR::NameId name_id) + -> std::optional> { + auto lookup = ClangLookupName(context, scope_id, name_id); + if (!lookup) { + return std::nullopt; + } + + std::tuple result{ + nullptr, clang::AccessSpecifier::AS_none}; + + // Access checks are performed separately by the Carbon name lookup logic. + lookup->suppressAccessDiagnostics(); + + if (!lookup->isSingleResult()) { + // Clang will diagnose ambiguous lookup results for us. + if (!lookup->isAmbiguous()) { + context.TODO(loc_id, + llvm::formatv("Unsupported: Lookup succeeded but couldn't " + "find a single result; LookupResultKind: {0}", + static_cast(lookup->getResultKind()))); + } + + return result; + } + + if (!IsDeclInjectedClassName(context, scope_id, name_id, + lookup->getFoundDecl())) { + result = {lookup->getFoundDecl(), lookup->begin().getAccess()}; + return result; + } + + clang::DeclContextLookupResult constructors_lookup = + ClangConstructorLookup(context, scope_id); + + llvm::SmallVector constructors; + for (clang::Decl* decl : constructors_lookup) { + auto* constructor = cast(decl); + if (constructor->isDeleted() || constructor->isCopyOrMoveConstructor()) { + continue; + } + constructors.push_back(constructor); + } + if (constructors.size() != 1) { + context.TODO( + loc_id, + llvm::formatv("Unsupported: Constructors lookup succeeded but couldn't " + "find a single result; Found {0} constructors", + constructors.size())); + return result; + } + result = {constructors[0], constructors[0]->getAccess()}; + return result; +} + // Returns whether `decl` already mapped to an instruction. static auto IsClangDeclImported(const Context& context, clang::Decl* decl) -> bool { @@ -1109,7 +1216,8 @@ static auto MakeImplicitParamPatternsBlockId( Context& context, SemIR::LocId loc_id, const clang::FunctionDecl& clang_decl) -> SemIR::InstBlockId { const auto* method_decl = dyn_cast(&clang_decl); - if (!method_decl || method_decl->isStatic()) { + if (!method_decl || method_decl->isStatic() || + isa(clang_decl)) { return SemIR::InstBlockId::Empty; } @@ -1229,22 +1337,54 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, return context.inst_blocks().Add(params); } -// Returns the return type of the given function declaration. In case of an -// unsupported return type, it produces a diagnostic and returns -// `SemIR::ErrorInst::InstId`. +// Returns the return `TypeExpr` of the given function declaration. In case of +// an unsupported return type, returns `SemIR::ErrorInst::InstId`. Constructors +// are treated as returning a class instance. // TODO: Support more return types. -static auto GetReturnType(Context& context, SemIR::LocId loc_id, - const clang::FunctionDecl* clang_decl) - -> SemIR::InstId { +static auto GetReturnTypeExpr(Context& context, SemIR::LocId loc_id, + clang::FunctionDecl* clang_decl) -> TypeExpr { clang::QualType ret_type = clang_decl->getReturnType(); - if (ret_type->isVoidType()) { - return SemIR::InstId::None; + if (!ret_type->isVoidType()) { + TypeExpr mapped_type = MapType(context, loc_id, ret_type); + if (!mapped_type.inst_id.has_value()) { + return {.inst_id = SemIR::ErrorInst::TypeInstId, + .type_id = SemIR::ErrorInst::TypeId}; + } + return mapped_type; } - auto [type_inst_id, type_id] = MapType(context, loc_id, ret_type); + if (!isa(clang_decl)) { + // void. + return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None}; + } + + // TODO: Make this a `PartialType`. + SemIR::TypeInstId record_type_inst_id = context.types().GetAsTypeInstId( + context.sem_ir() + .clang_decls() + .Get(context.sem_ir().clang_decls().Lookup( + cast(clang_decl->getParent()))) + .inst_id); + return { + .inst_id = record_type_inst_id, + .type_id = context.types().GetTypeIdForTypeInstId(record_type_inst_id)}; +} + +// Returns the return pattern of the given function declaration. In case of an +// unsupported return type, it produces a diagnostic and returns +// `SemIR::ErrorInst::InstId`. Constructors are treated as returning a class +// instance. +static auto GetReturnPattern(Context& context, SemIR::LocId loc_id, + clang::FunctionDecl* clang_decl) -> SemIR::InstId { + auto [type_inst_id, type_id] = GetReturnTypeExpr(context, loc_id, clang_decl); if (!type_inst_id.has_value()) { - context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}", - ret_type.getAsString())); + // void. + return SemIR::InstId::None; + } + if (type_inst_id == SemIR::ErrorInst::TypeInstId) { + context.TODO(loc_id, + llvm::formatv("Unsupported: return type: {0}", + clang_decl->getReturnType().getAsString())); return SemIR::ErrorInst::InstId; } auto pattern_type_id = GetPatternType(context, type_id); @@ -1283,10 +1423,10 @@ struct FunctionParamsInsts { // Produces a diagnostic and returns `std::nullopt` if the function declaration // has an unsupported parameter type. static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id, - const clang::FunctionDecl* clang_decl) + clang::FunctionDecl* clang_decl) -> std::optional { - if (isa(clang_decl)) { - context.TODO(loc_id, "Unsupported: Constructor/Destructor"); + if (isa(clang_decl)) { + context.TODO(loc_id, "Unsupported: Destructor"); return std::nullopt; } @@ -1300,7 +1440,7 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id, if (!param_patterns_id.has_value()) { return std::nullopt; } - auto return_slot_pattern_id = GetReturnType(context, loc_id, clang_decl); + auto return_slot_pattern_id = GetReturnPattern(context, loc_id, clang_decl); if (SemIR::ErrorInst::InstId == return_slot_pattern_id) { return std::nullopt; } @@ -1343,8 +1483,19 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id, AddPlaceholderInstInNoBlock(context, Parse::NodeId::None, function_decl); context.imports().push_back(decl_id); + SemIR::NameId function_name_id = + isa(clang_decl) + ? context.classes() + .Get(context.insts() + .GetAs(LookupClangDeclInstId( + context, + cast(clang_decl->getParent()))) + .class_id) + .name_id + : AddIdentifierName(context, clang_decl->getName()); + auto function_info = SemIR::Function{ - {.name_id = AddIdentifierName(context, clang_decl->getName()), + {.name_id = function_name_id, .parent_scope_id = GetParentNameScopeId(context, clang_decl), .generic_id = SemIR::GenericId::None, .first_param_node_id = Parse::NodeId::None, @@ -1526,8 +1677,7 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id, } context.TODO(loc_id, llvm::formatv("Unsupported: Declaration type {0}", - clang_decl->getDeclKindName()) - .str()); + clang_decl->getDeclKindName())); return SemIR::InstId::None; } @@ -1600,31 +1750,19 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, builder.Note(loc_id, InCppNameLookup, name_id); }); - auto lookup = ClangLookup(context, scope_id, name_id); - if (!lookup) { + auto decl_and_access = ClangLookup(context, loc_id, scope_id, name_id); + if (!decl_and_access) { return SemIR::ScopeLookupResult::MakeNotFound(); } - - // Access checks are performed separately by the Carbon name lookup logic. - lookup->suppressAccessDiagnostics(); - - if (!lookup->isSingleResult()) { - // Clang will diagnose ambiguous lookup results for us. - if (!lookup->isAmbiguous()) { - context.TODO(loc_id, - llvm::formatv("Unsupported: Lookup succeeded but couldn't " - "find a single result; LookupResultKind: {0}", - static_cast(lookup->getResultKind())) - .str()); - } + auto [decl, access] = *decl_and_access; + if (!decl) { context.name_scopes().AddRequiredName(scope_id, name_id, SemIR::ErrorInst::InstId); return SemIR::ScopeLookupResult::MakeError(); } - return ImportNameDeclIntoScope(context, loc_id, scope_id, name_id, - lookup->getFoundDecl(), - lookup->begin().getAccess()); + return ImportNameDeclIntoScope(context, loc_id, scope_id, name_id, decl, + access); } } // namespace Carbon::Check diff --git a/toolchain/check/import_cpp.h b/toolchain/check/import_cpp.h index 375847c3ca56..6fc337970807 100644 --- a/toolchain/check/import_cpp.h +++ b/toolchain/check/import_cpp.h @@ -25,7 +25,8 @@ auto ImportCppFiles(Context& context, -> std::unique_ptr; // Looks up the given name in the Clang AST generated when importing C++ code -// and returns a lookup result. +// and returns a lookup result. If using the injected class name (`X.X()`), +// imports the class constructor as a function named as the class. auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, SemIR::NameScopeId scope_id, SemIR::NameId name_id) -> SemIR::ScopeLookupResult; diff --git a/toolchain/check/testdata/interop/cpp/class/constructor.carbon b/toolchain/check/testdata/interop/cpp/class/constructor.carbon new file mode 100644 index 000000000000..17255b56505e --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/class/constructor.carbon @@ -0,0 +1,750 @@ +// 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/class/constructor.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/constructor.carbon + +// ============================================================================ +// Default constructor +// ============================================================================ + +// --- default.h + +class C { + public: + C(); +}; + +// --- import_default.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "default.h"; + +fn F() { + //@dump-sem-ir-begin + let c: Cpp.C = Cpp.C.C(); + //@dump-sem-ir-end +} + +// ============================================================================ +// Non default constructor +// ============================================================================ + +// --- non_default.h + +class C { + public: + C(int x, int y); +}; + +// --- import_non_default.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "non_default.h"; + +fn F() { + //@dump-sem-ir-begin + let c: Cpp.C = Cpp.C.C(123, 456); + //@dump-sem-ir-end +} + +// ============================================================================ +// Multiple constructors +// ============================================================================ + +// --- multiple.h + +class C { + public: + C(); + C(int x, int y); +}; + +// --- fail_todo_import_multiple.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "multiple.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_multiple.carbon:[[@LINE+7]]:19: error: semantics TODO: `Unsupported: Constructors lookup succeeded but couldn't find a single result; Found 2 constructors` [SemanticsTodo] + // CHECK:STDERR: let c1: Cpp.C = Cpp.C.C(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_multiple.carbon:[[@LINE+4]]:19: note: in `Cpp` name lookup for `C` [InCppNameLookup] + // CHECK:STDERR: let c1: Cpp.C = Cpp.C.C(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + let c1: Cpp.C = Cpp.C.C(); + let c2: Cpp.C = Cpp.C.C(123, 456); + //@dump-sem-ir-end +} + +// ============================================================================ +// Constructor with default values +// ============================================================================ + +// --- default_values.h + +class C { + public: + C(int x, int y = 8); +}; + +// --- fail_todo_import_default_values.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "default_values.h"; + +fn F() { + //@dump-sem-ir-begin + let c1: Cpp.C = Cpp.C.C(8, 9); + // CHECK:STDERR: fail_todo_import_default_values.carbon:[[@LINE+5]]:19: error: 1 argument passed to function expecting 2 arguments [CallArgCountMismatch] + // CHECK:STDERR: let c2: Cpp.C = Cpp.C.C(8); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: fail_todo_import_default_values.carbon: note: calling function declared here [InCallToEntity] + // CHECK:STDERR: + let c2: Cpp.C = Cpp.C.C(8); + //@dump-sem-ir-end +} + +// ============================================================================ +// No constructors +// ============================================================================ + +// --- none.h + +class C { + public: + C() = delete; +}; + +// --- fail_import_none.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "none.h"; + +fn F() { + // CHECK:STDERR: fail_import_none.carbon:[[@LINE+7]]:18: error: semantics TODO: `Unsupported: Constructors lookup succeeded but couldn't find a single result; Found 0 constructors` [SemanticsTodo] + // CHECK:STDERR: let c: Cpp.C = Cpp.C.C(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_import_none.carbon:[[@LINE+4]]:18: note: in `Cpp` name lookup for `C` [InCppNameLookup] + // CHECK:STDERR: let c: Cpp.C = Cpp.C.C(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + let c: Cpp.C = Cpp.C.C(); +} + +// ============================================================================ +// Implicit single argument constructor +// ============================================================================ + +// --- implicit_single_argument.h + +class C { + public: + C(int x); +}; + +// --- fail_todo_import_implicit_single_argument.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "implicit_single_argument.h"; + +fn F() { + //@dump-sem-ir-begin + let c1: Cpp.C = Cpp.C.C(8); + // CHECK:STDERR: fail_todo_import_implicit_single_argument.carbon:[[@LINE+7]]:19: error: cannot implicitly convert expression of type `i32` to `Cpp.C` [ConversionFailure] + // CHECK:STDERR: let c2: Cpp.C = 8 as i32; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_todo_import_implicit_single_argument.carbon:[[@LINE+4]]:19: note: type `i32` does not implement interface `Core.ImplicitAs(Cpp.C)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: let c2: Cpp.C = 8 as i32; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + let c2: Cpp.C = 8 as i32; + //@dump-sem-ir-end +} + +// ============================================================================ +// Implicit multi arguments constructor +// ============================================================================ + +// --- implicit_multi_arguments.h + +class C { + public: + C(int x, int y = 8); +}; + +// --- fail_todo_import_implicit_multi_arguments.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "implicit_multi_arguments.h"; + +fn F() { + //@dump-sem-ir-begin + let c1: Cpp.C = Cpp.C.C(8, 9); + // CHECK:STDERR: fail_todo_import_implicit_multi_arguments.carbon:[[@LINE+5]]:19: error: 1 argument passed to function expecting 2 arguments [CallArgCountMismatch] + // CHECK:STDERR: let c2: Cpp.C = Cpp.C.C(8); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: fail_todo_import_implicit_multi_arguments.carbon: note: calling function declared here [InCallToEntity] + // CHECK:STDERR: + let c2: Cpp.C = Cpp.C.C(8); + // CHECK:STDERR: fail_todo_import_implicit_multi_arguments.carbon:[[@LINE+7]]:19: error: cannot implicitly convert expression of type `i32` to `Cpp.C` [ConversionFailure] + // CHECK:STDERR: let c3: Cpp.C = 8 as i32; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_todo_import_implicit_multi_arguments.carbon:[[@LINE+4]]:19: note: type `i32` does not implement interface `Core.ImplicitAs(Cpp.C)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: let c3: Cpp.C = 8 as i32; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + let c3: Cpp.C = 8 as i32; + //@dump-sem-ir-end +} + +// CHECK:STDOUT: --- import_default.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: %pattern_type.217: type = pattern_type %C [concrete] +// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete] +// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.217 = binding_pattern c [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc8_18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_21: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc8_23: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C] +// CHECK:STDOUT: %.loc8_26.1: ref %C = temporary_storage +// CHECK:STDOUT: %C.C.call: init %C = call %C.ref.loc8_23() to %.loc8_26.1 +// CHECK:STDOUT: %.loc8_13: type = splice_block %C.ref.loc8_13 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc8_10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_13: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_26.2: ref %C = temporary %.loc8_26.1, %C.C.call +// CHECK:STDOUT: %.loc8_26.3: %C = bind_value %.loc8_26.2 +// CHECK:STDOUT: %c: %C = bind_name c, %.loc8_26.3 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_26.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc8_26.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_26.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_non_default.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: %pattern_type.217: type = pattern_type %C [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete] +// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete] +// CHECK:STDOUT: %int_123.fff: Core.IntLiteral = int_value 123 [concrete] +// CHECK:STDOUT: %int_456.010: Core.IntLiteral = int_value 456 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete] +// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.f06: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.c75: = impl_witness imports.%ImplicitAs.impl_witness_table.a2f, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.956: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.c75) [concrete] +// CHECK:STDOUT: %.9c3: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.2cc: = bound_method %int_123.fff, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.956, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.3aa: = bound_method %int_123.fff, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_123.f7f: %i32 = int_value 123 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.3bd: = bound_method %int_456.010, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete] +// CHECK:STDOUT: %bound_method.6b8: = bound_method %int_456.010, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_456.d17: %i32 = int_value 456 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import_ref.a5b: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f06)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c.patt: %pattern_type.217 = binding_pattern c [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc8_18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_21: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc8_23: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C] +// CHECK:STDOUT: %int_123: Core.IntLiteral = int_value 123 [concrete = constants.%int_123.fff] +// CHECK:STDOUT: %int_456: Core.IntLiteral = int_value 456 [concrete = constants.%int_456.010] +// CHECK:STDOUT: %.loc8_34.1: ref %C = temporary_storage +// CHECK:STDOUT: %impl.elem0.loc8_26: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956] +// CHECK:STDOUT: %bound_method.loc8_26.1: = bound_method %int_123, %impl.elem0.loc8_26 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.2cc] +// CHECK:STDOUT: %specific_fn.loc8_26: = specific_function %impl.elem0.loc8_26, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_26.2: = bound_method %int_123, %specific_fn.loc8_26 [concrete = constants.%bound_method.3aa] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_26: init %i32 = call %bound_method.loc8_26.2(%int_123) [concrete = constants.%int_123.f7f] +// CHECK:STDOUT: %.loc8_26.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_26 [concrete = constants.%int_123.f7f] +// CHECK:STDOUT: %.loc8_26.2: %i32 = converted %int_123, %.loc8_26.1 [concrete = constants.%int_123.f7f] +// CHECK:STDOUT: %impl.elem0.loc8_31: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956] +// CHECK:STDOUT: %bound_method.loc8_31.1: = bound_method %int_456, %impl.elem0.loc8_31 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.3bd] +// CHECK:STDOUT: %specific_fn.loc8_31: = specific_function %impl.elem0.loc8_31, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_31.2: = bound_method %int_456, %specific_fn.loc8_31 [concrete = constants.%bound_method.6b8] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_31: init %i32 = call %bound_method.loc8_31.2(%int_456) [concrete = constants.%int_456.d17] +// CHECK:STDOUT: %.loc8_31.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_31 [concrete = constants.%int_456.d17] +// CHECK:STDOUT: %.loc8_31.2: %i32 = converted %int_456, %.loc8_31.1 [concrete = constants.%int_456.d17] +// CHECK:STDOUT: %C.C.call: init %C = call %C.ref.loc8_23(%.loc8_26.2, %.loc8_31.2) to %.loc8_34.1 +// CHECK:STDOUT: %.loc8_13: type = splice_block %C.ref.loc8_13 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc8_10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_13: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_34.2: ref %C = temporary %.loc8_34.1, %C.C.call +// CHECK:STDOUT: %.loc8_34.3: %C = bind_value %.loc8_34.2 +// CHECK:STDOUT: %c: %C = bind_name c, %.loc8_34.3 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_34.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_34: = bound_method %.loc8_34.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_34.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_34(%addr) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_multiple.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %pattern_type: type = pattern_type %C [concrete] +// CHECK:STDOUT: %int_123: Core.IntLiteral = int_value 123 [concrete] +// CHECK:STDOUT: %int_456: Core.IntLiteral = int_value 456 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// 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() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c1.patt: %pattern_type = binding_pattern c1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc15_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc15_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc15_24: = name_ref C, [concrete = ] +// CHECK:STDOUT: %.loc15: type = splice_block %C.ref.loc15_14 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc15_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc15_14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %c1: %C = bind_name c1, [concrete = ] +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c2.patt: %pattern_type = binding_pattern c2 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc16_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc16_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc16_24: = name_ref C, [concrete = ] +// CHECK:STDOUT: %int_123: Core.IntLiteral = int_value 123 [concrete = constants.%int_123] +// CHECK:STDOUT: %int_456: Core.IntLiteral = int_value 456 [concrete = constants.%int_456] +// CHECK:STDOUT: %.loc16: type = splice_block %C.ref.loc16_14 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc16_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc16_14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %c2: %C = bind_name c2, [concrete = ] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_default_values.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: %pattern_type.217: type = pattern_type %C [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete] +// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete] +// CHECK:STDOUT: %int_8.b85: Core.IntLiteral = int_value 8 [concrete] +// CHECK:STDOUT: %int_9.988: Core.IntLiteral = int_value 9 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete] +// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.f06: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.c75: = impl_witness imports.%ImplicitAs.impl_witness_table.a2f, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.956: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.c75) [concrete] +// CHECK:STDOUT: %.9c3: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.e09: = bound_method %int_8.b85, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.956, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.02d: = bound_method %int_8.b85, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_8.98c: %i32 = int_value 8 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.9e2: = bound_method %int_9.988, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete] +// CHECK:STDOUT: %bound_method.cd3: = bound_method %int_9.988, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_9.f88: %i32 = int_value 9 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import_ref.a5b: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f06)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c1.patt: %pattern_type.217 = binding_pattern c1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc8_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc8_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C] +// CHECK:STDOUT: %int_8.loc8: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %int_9: Core.IntLiteral = int_value 9 [concrete = constants.%int_9.988] +// CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage +// CHECK:STDOUT: %impl.elem0.loc8_27: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956] +// CHECK:STDOUT: %bound_method.loc8_27.1: = bound_method %int_8.loc8, %impl.elem0.loc8_27 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.e09] +// CHECK:STDOUT: %specific_fn.loc8_27: = specific_function %impl.elem0.loc8_27, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_27.2: = bound_method %int_8.loc8, %specific_fn.loc8_27 [concrete = constants.%bound_method.02d] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_27: init %i32 = call %bound_method.loc8_27.2(%int_8.loc8) [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc8_27.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_27 [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc8_27.2: %i32 = converted %int_8.loc8, %.loc8_27.1 [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %impl.elem0.loc8_30: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956] +// CHECK:STDOUT: %bound_method.loc8_30.1: = bound_method %int_9, %impl.elem0.loc8_30 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.9e2] +// CHECK:STDOUT: %specific_fn.loc8_30: = specific_function %impl.elem0.loc8_30, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_30.2: = bound_method %int_9, %specific_fn.loc8_30 [concrete = constants.%bound_method.cd3] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_30: init %i32 = call %bound_method.loc8_30.2(%int_9) [concrete = constants.%int_9.f88] +// CHECK:STDOUT: %.loc8_30.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_30 [concrete = constants.%int_9.f88] +// CHECK:STDOUT: %.loc8_30.2: %i32 = converted %int_9, %.loc8_30.1 [concrete = constants.%int_9.f88] +// CHECK:STDOUT: %C.C.call: init %C = call %C.ref.loc8_24(%.loc8_27.2, %.loc8_30.2) to %.loc8_31.1 +// CHECK:STDOUT: %.loc8_14: type = splice_block %C.ref.loc8_14 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc8_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_31.2: ref %C = temporary %.loc8_31.1, %C.C.call +// CHECK:STDOUT: %.loc8_31.3: %C = bind_value %.loc8_31.2 +// CHECK:STDOUT: %c1: %C = bind_name c1, %.loc8_31.3 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c2.patt: %pattern_type.217 = binding_pattern c2 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc14_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc14_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc14_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C] +// CHECK:STDOUT: %int_8.loc14: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %.loc14: type = splice_block %C.ref.loc14_14 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc14_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc14_14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %c2: %C = bind_name c2, [concrete = ] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_31.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_31: = bound_method %.loc8_31.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_31.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_31(%addr) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_implicit_single_argument.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: %pattern_type.217: type = pattern_type %C [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete] +// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete] +// CHECK:STDOUT: %int_8.b85: Core.IntLiteral = int_value 8 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete] +// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.f06: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9 = struct_value () [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.062: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.527: %Core.IntLiteral.as.As.impl.Convert.type.062 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.c75: = impl_witness imports.%ImplicitAs.impl_witness_table.a2f, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.956: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.c75) [concrete] +// CHECK:STDOUT: %.9c3: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: = bound_method %int_8.b85, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.956, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.02d: = bound_method %int_8.b85, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_8.98c: %i32 = int_value 8 [concrete] +// CHECK:STDOUT: %As.type.fd4: type = facet_type <@As, @As(%i32)> [concrete] +// CHECK:STDOUT: %As.Convert.type.99b: type = fn_type @As.Convert, @As(%i32) [concrete] +// CHECK:STDOUT: %As.impl_witness.6b4: = impl_witness imports.%As.impl_witness_table.eb4, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.4fd: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.197: %Core.IntLiteral.as.As.impl.Convert.type.4fd = struct_value () [concrete] +// CHECK:STDOUT: %As.facet: %As.type.fd4 = facet_value Core.IntLiteral, (%As.impl_witness.6b4) [concrete] +// CHECK:STDOUT: %.982: type = fn_type_with_self_type %As.Convert.type.99b, %As.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.bound: = bound_method %int_8.b85, %Core.IntLiteral.as.As.impl.Convert.197 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.197, @Core.IntLiteral.as.As.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.3a8: = bound_method %int_8.b85, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import_ref.a5b: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f06)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] +// CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c1.patt: %pattern_type.217 = binding_pattern c1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc8_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc8_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C] +// CHECK:STDOUT: %int_8.loc8: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %.loc8_28.1: ref %C = temporary_storage +// CHECK:STDOUT: %impl.elem0.loc8: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956] +// CHECK:STDOUT: %bound_method.loc8_27.1: = bound_method %int_8.loc8, %impl.elem0.loc8 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn.loc8: = specific_function %impl.elem0.loc8, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_27.2: = bound_method %int_8.loc8, %specific_fn.loc8 [concrete = constants.%bound_method.02d] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc8_27.2(%int_8.loc8) [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc8_27.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc8_27.2: %i32 = converted %int_8.loc8, %.loc8_27.1 [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %C.C.call: init %C = call %C.ref.loc8_24(%.loc8_27.2) to %.loc8_28.1 +// CHECK:STDOUT: %.loc8_14: type = splice_block %C.ref.loc8_14 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc8_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_28.2: ref %C = temporary %.loc8_28.1, %C.C.call +// CHECK:STDOUT: %.loc8_28.3: %C = bind_value %.loc8_28.2 +// CHECK:STDOUT: %c1: %C = bind_name c1, %.loc8_28.3 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c2.patt: %pattern_type.217 = binding_pattern c2 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_8.loc16: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %impl.elem0.loc16: %.982 = impl_witness_access constants.%As.impl_witness.6b4, element0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.197] +// CHECK:STDOUT: %bound_method.loc16_21.1: = bound_method %int_8.loc16, %impl.elem0.loc16 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn.loc16: = specific_function %impl.elem0.loc16, @Core.IntLiteral.as.As.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc16_21.2: = bound_method %int_8.loc16, %specific_fn.loc16 [concrete = constants.%bound_method.3a8] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i32 = call %bound_method.loc16_21.2(%int_8.loc16) [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc16_21.1: %i32 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc16_21.2: %i32 = converted %int_8.loc16, %.loc16_21.1 [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc16_14: type = splice_block %C.ref.loc16 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc16: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc16: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc16_21.3: %C = converted %.loc16_21.2, [concrete = ] +// CHECK:STDOUT: %c2: %C = bind_name c2, [concrete = ] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_28.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_28: = bound_method %.loc8_28.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_28.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_28(%addr) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_implicit_multi_arguments.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: %pattern_type.217: type = pattern_type %C [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %C.C.type: type = fn_type @C.C [concrete] +// CHECK:STDOUT: %C.C: %C.C.type = struct_value () [concrete] +// CHECK:STDOUT: %int_8.b85: Core.IntLiteral = int_value 8 [concrete] +// CHECK:STDOUT: %int_9.988: Core.IntLiteral = int_value 9 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.205: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete] +// CHECK:STDOUT: %ImplicitAs.Convert.type.1b6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.f06: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9 = struct_value () [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.062: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.527: %Core.IntLiteral.as.As.impl.Convert.type.062 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.c75: = impl_witness imports.%ImplicitAs.impl_witness_table.a2f, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.956: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.035 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.205 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.c75) [concrete] +// CHECK:STDOUT: %.9c3: type = fn_type_with_self_type %ImplicitAs.Convert.type.1b6, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.e09: = bound_method %int_8.b85, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.956, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.02d: = bound_method %int_8.b85, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_8.98c: %i32 = int_value 8 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.9e2: = bound_method %int_9.988, %Core.IntLiteral.as.ImplicitAs.impl.Convert.956 [concrete] +// CHECK:STDOUT: %bound_method.cd3: = bound_method %int_9.988, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_9.f88: %i32 = int_value 9 [concrete] +// CHECK:STDOUT: %As.type.fd4: type = facet_type <@As, @As(%i32)> [concrete] +// CHECK:STDOUT: %As.Convert.type.99b: type = fn_type @As.Convert, @As(%i32) [concrete] +// CHECK:STDOUT: %As.impl_witness.6b4: = impl_witness imports.%As.impl_witness_table.eb4, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.4fd: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.197: %Core.IntLiteral.as.As.impl.Convert.type.4fd = struct_value () [concrete] +// CHECK:STDOUT: %As.facet: %As.type.fd4 = facet_value Core.IntLiteral, (%As.impl_witness.6b4) [concrete] +// CHECK:STDOUT: %.982: type = fn_type_with_self_type %As.Convert.type.99b, %As.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.bound: = bound_method %int_8.b85, %Core.IntLiteral.as.As.impl.Convert.197 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.197, @Core.IntLiteral.as.As.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.3a8: = bound_method %int_8.b85, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %C.C.decl: %C.C.type = fn_decl @C.C [concrete = constants.%C.C] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import_ref.a5b: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f06)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] +// CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c1.patt: %pattern_type.217 = binding_pattern c1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc8_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc8_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C] +// CHECK:STDOUT: %int_8.loc8: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %int_9: Core.IntLiteral = int_value 9 [concrete = constants.%int_9.988] +// CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage +// CHECK:STDOUT: %impl.elem0.loc8_27: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956] +// CHECK:STDOUT: %bound_method.loc8_27.1: = bound_method %int_8.loc8, %impl.elem0.loc8_27 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.e09] +// CHECK:STDOUT: %specific_fn.loc8_27: = specific_function %impl.elem0.loc8_27, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_27.2: = bound_method %int_8.loc8, %specific_fn.loc8_27 [concrete = constants.%bound_method.02d] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_27: init %i32 = call %bound_method.loc8_27.2(%int_8.loc8) [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc8_27.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_27 [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc8_27.2: %i32 = converted %int_8.loc8, %.loc8_27.1 [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %impl.elem0.loc8_30: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956] +// CHECK:STDOUT: %bound_method.loc8_30.1: = bound_method %int_9, %impl.elem0.loc8_30 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.9e2] +// CHECK:STDOUT: %specific_fn.loc8_30: = specific_function %impl.elem0.loc8_30, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_30.2: = bound_method %int_9, %specific_fn.loc8_30 [concrete = constants.%bound_method.cd3] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_30: init %i32 = call %bound_method.loc8_30.2(%int_9) [concrete = constants.%int_9.f88] +// CHECK:STDOUT: %.loc8_30.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc8_30 [concrete = constants.%int_9.f88] +// CHECK:STDOUT: %.loc8_30.2: %i32 = converted %int_9, %.loc8_30.1 [concrete = constants.%int_9.f88] +// CHECK:STDOUT: %C.C.call: init %C = call %C.ref.loc8_24(%.loc8_27.2, %.loc8_30.2) to %.loc8_31.1 +// CHECK:STDOUT: %.loc8_14: type = splice_block %C.ref.loc8_14 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc8_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc8_14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc8_31.2: ref %C = temporary %.loc8_31.1, %C.C.call +// CHECK:STDOUT: %.loc8_31.3: %C = bind_value %.loc8_31.2 +// CHECK:STDOUT: %c1: %C = bind_name c1, %.loc8_31.3 +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c2.patt: %pattern_type.217 = binding_pattern c2 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref.loc14_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc14_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %C.ref.loc14_24: %C.C.type = name_ref C, imports.%C.C.decl [concrete = constants.%C.C] +// CHECK:STDOUT: %int_8.loc14: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %.loc14: type = splice_block %C.ref.loc14_14 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc14_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc14_14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %c2: %C = bind_name c2, [concrete = ] +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %c3.patt: %pattern_type.217 = binding_pattern c3 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: %int_8.loc22: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %impl.elem0.loc22: %.982 = impl_witness_access constants.%As.impl_witness.6b4, element0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.197] +// CHECK:STDOUT: %bound_method.loc22_21.1: = bound_method %int_8.loc22, %impl.elem0.loc22 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn.loc22: = specific_function %impl.elem0.loc22, @Core.IntLiteral.as.As.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc22_21.2: = bound_method %int_8.loc22, %specific_fn.loc22 [concrete = constants.%bound_method.3a8] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i32 = call %bound_method.loc22_21.2(%int_8.loc22) [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc22_21.1: %i32 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc22_21.2: %i32 = converted %int_8.loc22, %.loc22_21.1 [concrete = constants.%int_8.98c] +// CHECK:STDOUT: %.loc22_14: type = splice_block %C.ref.loc22 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc22: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc22: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: } +// CHECK:STDOUT: %.loc22_21.3: %C = converted %.loc22_21.2, [concrete = ] +// CHECK:STDOUT: %c3: %C = bind_name c3, [concrete = ] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_31.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_31: = bound_method %.loc8_31.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_31.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_31(%addr) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/lower/BUILD b/toolchain/lower/BUILD index 06c6dbf679d8..75528aa0d15f 100644 --- a/toolchain/lower/BUILD +++ b/toolchain/lower/BUILD @@ -29,6 +29,8 @@ cc_library( cc_library( name = "context", srcs = [ + "clang_global_decl.cpp", + "clang_global_decl.h", "constant.cpp", "constant.h", "context.cpp", diff --git a/toolchain/lower/clang_global_decl.cpp b/toolchain/lower/clang_global_decl.cpp new file mode 100644 index 000000000000..aa6deb30b781 --- /dev/null +++ b/toolchain/lower/clang_global_decl.cpp @@ -0,0 +1,18 @@ +// 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/lower/clang_global_decl.h" +namespace Carbon::Lower { + +auto CreateGlobalDecl(const clang::NamedDecl* decl) -> clang::GlobalDecl { + if (const auto* constructor_decl = + dyn_cast(decl)) { + return clang::GlobalDecl(constructor_decl, + clang::CXXCtorType::Ctor_Complete); + } + + return clang::GlobalDecl(decl); +} + +} // namespace Carbon::Lower diff --git a/toolchain/lower/clang_global_decl.h b/toolchain/lower/clang_global_decl.h new file mode 100644 index 000000000000..fc4052c10115 --- /dev/null +++ b/toolchain/lower/clang_global_decl.h @@ -0,0 +1,19 @@ +// 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_LOWER_CLANG_GLOBAL_DECL_H_ +#define CARBON_TOOLCHAIN_LOWER_CLANG_GLOBAL_DECL_H_ + +#include "clang/AST/Decl.h" +#include "clang/AST/GlobalDecl.h" + +namespace Carbon::Lower { + +// Returns `clang::GlobalDecl` with special handling of constructors, assuming +// they're complete. +auto CreateGlobalDecl(const clang::NamedDecl* decl) -> clang::GlobalDecl; + +} // namespace Carbon::Lower + +#endif // CARBON_TOOLCHAIN_LOWER_CLANG_GLOBAL_DECL_H_ diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 8b616399afb2..f1020fab6743 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -19,6 +19,7 @@ #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "toolchain/base/kind_switch.h" +#include "toolchain/lower/clang_global_decl.h" #include "toolchain/lower/constant.h" #include "toolchain/lower/function_context.h" #include "toolchain/lower/mangler.h" @@ -380,7 +381,7 @@ auto FileContext::HandleReferencedCppFunction(clang::FunctionDecl* cpp_decl) // function name (`CodeGenModule::getMangledName()`), and will generate // its definition. llvm::Constant* function_address = - cpp_code_generator_->GetAddrOfGlobal(clang::GlobalDecl(cpp_def), + cpp_code_generator_->GetAddrOfGlobal(CreateGlobalDecl(cpp_def), /*isForDefinition=*/false); CARBON_CHECK(function_address); diff --git a/toolchain/lower/mangler.cpp b/toolchain/lower/mangler.cpp index 99be2a4c6fd5..3491688c746d 100644 --- a/toolchain/lower/mangler.cpp +++ b/toolchain/lower/mangler.cpp @@ -8,6 +8,7 @@ #include "common/raw_string_ostream.h" #include "toolchain/base/kind_switch.h" +#include "toolchain/lower/clang_global_decl.h" #include "toolchain/sem_ir/entry_point.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/pattern.h" @@ -218,7 +219,7 @@ auto Mangler::MangleGlobalVariable(SemIR::InstId pattern_id) -> std::string { auto Mangler::MangleCppClang(const clang::NamedDecl* decl) -> std::string { return file_context_.cpp_code_generator() - .GetMangledName(clang::GlobalDecl(decl)) + .GetMangledName(CreateGlobalDecl(decl)) .str(); } diff --git a/toolchain/lower/testdata/interop/cpp/constructor.carbon b/toolchain/lower/testdata/interop/cpp/constructor.carbon new file mode 100644 index 000000000000..14130124c309 --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/constructor.carbon @@ -0,0 +1,101 @@ +// 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/lower/testdata/interop/cpp/constructor.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/constructor.carbon + +// ============================================================================ +// Default constructor +// ============================================================================ + +// --- default.h + +class C { + public: + C() : x_(8), y_(9) {} + + private: + int x_; + int y_; +}; + +// --- import_default.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "default.h"; + +fn F() { + let c: Cpp.C = Cpp.C.C(); +} + +// CHECK:STDOUT: ; ModuleID = 'import_default.carbon' +// CHECK:STDOUT: source_filename = "import_default.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.C = type { i32, i32 } +// CHECK:STDOUT: +// CHECK:STDOUT: $_ZN1CC1Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_ZN1CC2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CF.Main() !dbg !7 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc7_26.1.temp = alloca [8 x i8], align 1, !dbg !10 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 8, ptr %.loc7_26.1.temp), !dbg !10 +// CHECK:STDOUT: call void @_ZN1CC1Ev(ptr %.loc7_26.1.temp), !dbg !10 +// CHECK:STDOUT: ret void, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN1CC1Ev(ptr nonnull align 4 dereferenceable(8) %this) #1 comdat align 2 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %this.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8 +// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK:STDOUT: call void @_ZN1CC2Ev(ptr nonnull align 4 dereferenceable(8) %this1) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress noinline nounwind optnone +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN1CC2Ev(ptr nonnull align 4 dereferenceable(8) %this) unnamed_addr #2 comdat align 2 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %this.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8 +// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK:STDOUT: %x_ = getelementptr inbounds nuw %class.C, ptr %this1, i32 0, i32 0 +// CHECK:STDOUT: store i32 8, ptr %x_, align 4 +// CHECK:STDOUT: %y_ = getelementptr inbounds nuw %class.C, ptr %this1, i32 0, i32 1 +// CHECK:STDOUT: store i32 9, ptr %y_, align 4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #1 = { mustprogress noinline optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #2 = { mustprogress noinline nounwind optnone "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "import_default.carbon", directory: "") +// CHECK:STDOUT: !7 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main", scope: null, file: !6, line: 6, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !8 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !9 = !{} +// CHECK:STDOUT: !10 = !DILocation(line: 7, column: 18, scope: !7) +// CHECK:STDOUT: !11 = !DILocation(line: 6, column: 1, scope: !7)