diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 58932a2be1d2..5af9869bce0a 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -23,6 +23,7 @@ cc_library( "convert.cpp", "cpp/custom_type_mapping.cpp", "cpp/import.cpp", + "cpp/operators.cpp", "cpp/overload_resolution.cpp", "cpp/thunk.cpp", "cpp/type_mapping.cpp", @@ -72,6 +73,7 @@ cc_library( "convert.h", "cpp/custom_type_mapping.h", "cpp/import.h", + "cpp/operators.h", "cpp/overload_resolution.h", "cpp/thunk.h", "cpp/type_mapping.h", diff --git a/toolchain/check/cpp/import.cpp b/toolchain/check/cpp/import.cpp index 18c91f24d4b4..0d053962d033 100644 --- a/toolchain/check/cpp/import.cpp +++ b/toolchain/check/cpp/import.cpp @@ -527,41 +527,6 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, return lookup; } -// Looks up the given declaration name in the Clang AST in a specific scope. -// Returns the found declaration and its access. If not found, returns -// `nullopt`. If there's not a single result, returns `nullptr` and default -// access. -static auto ClangLookupDeclarationName(Context& context, SemIR::LocId loc_id, - SemIR::NameScopeId scope_id, - clang::DeclarationName name) - -> std::optional> { - auto lookup = ClangLookup(context, scope_id, name); - 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; - } - - result = {lookup->getFoundDecl(), lookup->begin().getAccess()}; - return result; -} - // Looks up for constructors in the class scope and returns the lookup result. static auto ClangConstructorLookup(Context& context, SemIR::NameScopeId scope_id) @@ -1894,11 +1859,8 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id, // Attempts to import a set of declarations. Returns `false` if an error was // produced, `true` otherwise. -// TODO: Merge overload set and operators and remove the `is_overload_set` -// param. static auto ImportDeclSet(Context& context, SemIR::LocId loc_id, - ImportWorklist& worklist, - bool is_overload_set = false) -> bool { + ImportWorklist& worklist) -> bool { // Walk the dependency graph in depth-first order, and import declarations // once we've imported all of their dependencies. while (!worklist.empty()) { @@ -1924,7 +1886,7 @@ static auto ImportDeclSet(Context& context, SemIR::LocId loc_id, // Functions that are part of the overload set are imported at a later // point, once the overload resolution has selected the suitable function // for the call. - if (is_overload_set && decl->getAsFunction()) { + if (decl->getAsFunction()) { continue; } auto inst_id = ImportDeclAfterDependencies(context, loc_id, decl); @@ -2056,10 +2018,9 @@ static auto LookupBuiltinTypes(Context& context, SemIR::LocId loc_id, return inst_id; } -// Imports an overloaded function set from Clang to Carbon. -static auto ImportCppOverloadSet(Context& context, SemIR::NameScopeId scope_id, - SemIR::NameId name_id, - const clang::UnresolvedSet<4>& overload_set) +auto ImportCppOverloadSet(Context& context, SemIR::NameScopeId scope_id, + SemIR::NameId name_id, + const clang::UnresolvedSet<4>& overload_set) -> SemIR::InstId { SemIR::CppOverloadSetId overload_set_id = context.cpp_overload_sets().Add( SemIR::CppOverloadSet{.name_id = name_id, @@ -2102,7 +2063,7 @@ static auto ImportOverloadSetAndDependencies( for (clang::NamedDecl* fn_decl : overloaded_set) { AddDependentDecl(context, fn_decl, worklist); } - if (!ImportDeclSet(context, loc_id, worklist, true)) { + if (!ImportDeclSet(context, loc_id, worklist)) { return SemIR::ErrorInst::InstId; } return ImportCppOverloadSet(context, scope_id, name_id, overloaded_set); @@ -2213,187 +2174,6 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, overload_set); } -static auto GetClangOperatorKind(Context& context, SemIR::LocId loc_id, - llvm::StringLiteral interface_name, - llvm::StringLiteral op_name) - -> std::optional { - // Unary operators. - if (interface_name == "Destroy" || interface_name == "As" || - interface_name == "ImplicitAs") { - // TODO: Support destructors and conversions. - return std::nullopt; - } - - // Increment and Decrement. - if (interface_name == "Inc") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_PlusPlus; - } - if (interface_name == "Dec") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_MinusMinus; - } - - // Arithmetic. - if (interface_name == "Negate") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Minus; - } - - // Binary operators. - - // Arithmetic Operators. - if (interface_name == "AddWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Plus; - } - if (interface_name == "SubWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Minus; - } - if (interface_name == "MulWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Star; - } - if (interface_name == "DivWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Slash; - } - if (interface_name == "ModWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Percent; - } - - // Bitwise Operators. - if (interface_name == "BitAndWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Amp; - } - if (interface_name == "BitOrWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Pipe; - } - if (interface_name == "BitXorWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_Caret; - } - if (interface_name == "LeftShiftWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_LessLess; - } - if (interface_name == "RightShiftWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_GreaterGreater; - } - - // Compound Assignment Arithmetic Operators. - if (interface_name == "AddAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_PlusEqual; - } - if (interface_name == "SubAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_MinusEqual; - } - if (interface_name == "MulAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_StarEqual; - } - if (interface_name == "DivAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_SlashEqual; - } - if (interface_name == "ModAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_PercentEqual; - } - - // Compound Assignment Bitwise Operators. - if (interface_name == "BitAndAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_AmpEqual; - } - if (interface_name == "BitOrAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_PipeEqual; - } - if (interface_name == "BitXorAssignWith") { - CARBON_CHECK(op_name == "Op"); - return clang::OO_CaretEqual; - } - // TODO: Add support for `LeftShiftAssignWith` (`OO_LessLessEqual`) and - // `RightShiftAssignWith` (`OO_GreaterGreaterEqual`) when references are - // supported. - - // Relational Operators. - if (interface_name == "EqWith") { - if (op_name == "Equal") { - return clang::OO_EqualEqual; - } - CARBON_CHECK(op_name == "NotEqual"); - return clang::OO_ExclaimEqual; - } - if (interface_name == "OrderedWith") { - if (op_name == "Less") { - return clang::OO_Less; - } - if (op_name == "Greater") { - return clang::OO_Greater; - } - if (op_name == "LessOrEquivalent") { - return clang::OO_LessEqual; - } - CARBON_CHECK(op_name == "GreaterOrEquivalent"); - return clang::OO_GreaterEqual; - } - - context.TODO(loc_id, llvm::formatv("Unsupported operator interface `{0}`", - interface_name)); - return std::nullopt; -} - -auto ImportOperatorFromCpp(Context& context, SemIR::LocId loc_id, - SemIR::NameScopeId scope_id, Operator op) - -> SemIR::ScopeLookupResult { - Diagnostics::AnnotationScope annotate_diagnostics( - &context.emitter(), [&](auto& builder) { - CARBON_DIAGNOSTIC(InCppOperatorLookup, Note, - "in `Cpp` operator `{0}` lookup", std::string); - builder.Note(loc_id, InCppOperatorLookup, op.interface_name.str()); - }); - - auto op_kind = - GetClangOperatorKind(context, loc_id, op.interface_name, op.op_name); - if (!op_kind) { - return SemIR::ScopeLookupResult::MakeNotFound(); - } - - // TODO: We should do ADL-only lookup for operators - // (`Sema::ArgumentDependentLookup`), when we support mapping Carbon types - // into C++ types. See - // https://github.com/carbon-language/carbon-lang/pull/5996/files/5d01fa69511b76f87efbc0387f5e40abcf4c911a#r2316950123 - auto decl_and_access = ClangLookupDeclarationName( - context, loc_id, scope_id, - context.ast_context().DeclarationNames.getCXXOperatorName(*op_kind)); - - if (!decl_and_access) { - return SemIR::ScopeLookupResult::MakeNotFound(); - } - auto [decl, access] = *decl_and_access; - if (!decl) { - return SemIR::ScopeLookupResult::MakeError(); - } - - SemIR::InstId inst_id = ImportDeclAndDependencies(context, loc_id, decl); - if (!inst_id.has_value()) { - return SemIR::ScopeLookupResult::MakeNotFound(); - } - - SemIR::AccessKind access_kind = MapAccess(access); - return SemIR::ScopeLookupResult::MakeWrappedLookupResult(inst_id, - access_kind); -} - auto ImportClassDefinitionForClangDecl(Context& context, SemIR::LocId loc_id, SemIR::ClassId class_id, SemIR::ClangDeclId clang_decl_id) diff --git a/toolchain/check/cpp/import.h b/toolchain/check/cpp/import.h index e64dab8f4b04..eb96d82212f7 100644 --- a/toolchain/check/cpp/import.h +++ b/toolchain/check/cpp/import.h @@ -11,7 +11,6 @@ #include "llvm/Support/VirtualFileSystem.h" #include "toolchain/check/context.h" #include "toolchain/check/diagnostic_helpers.h" -#include "toolchain/check/operator.h" #include "toolchain/diagnostics/diagnostic_emitter.h" namespace Carbon::Check { @@ -31,6 +30,12 @@ auto ImportCppFiles(Context& context, auto ImportCppFunctionDecl(Context& context, SemIR::LocId loc_id, clang::FunctionDecl* clang_decl) -> SemIR::InstId; +// Imports an overloaded function set from Clang to Carbon. +auto ImportCppOverloadSet(Context& context, SemIR::NameScopeId scope_id, + SemIR::NameId name_id, + const clang::UnresolvedSet<4>& overload_set) + -> SemIR::InstId; + // Looks up the given name in the Clang AST generated when importing C++ code // and returns a lookup result. If using the injected class name (`X.X()`), // imports the class constructor as a function named as the class. @@ -38,12 +43,6 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, SemIR::NameScopeId scope_id, SemIR::NameId name_id) -> SemIR::ScopeLookupResult; -// Looks up the given operator in the Clang AST generated when importing C++ -// code and returns a lookup result. -auto ImportOperatorFromCpp(Context& context, SemIR::LocId loc_id, - SemIR::NameScopeId scope_id, Operator op) - -> SemIR::ScopeLookupResult; - // Given a Carbon class declaration that was imported from some kind of C++ // declaration, such as a class or enum, attempt to import a corresponding class // definition. Returns true if nothing went wrong (whether or not a definition diff --git a/toolchain/check/cpp/operators.cpp b/toolchain/check/cpp/operators.cpp new file mode 100644 index 000000000000..31a8c058d459 --- /dev/null +++ b/toolchain/check/cpp/operators.cpp @@ -0,0 +1,197 @@ +// 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/check/cpp/operators.h" + +#include "clang/Sema/Overload.h" +#include "clang/Sema/Sema.h" +#include "toolchain/check/cpp/import.h" +#include "toolchain/check/cpp/type_mapping.h" +#include "toolchain/check/inst.h" +#include "toolchain/check/type.h" +#include "toolchain/sem_ir/ids.h" + +namespace Carbon::Check { + +// Maps Carbon operator interface and operator names to Clang operator kinds. +static auto GetClangOperatorKind(Context& context, SemIR::LocId loc_id, + llvm::StringLiteral interface_name, + llvm::StringLiteral op_name) + -> std::optional { + // Unary operators. + if (interface_name == "Destroy" || interface_name == "As" || + interface_name == "ImplicitAs") { + // TODO: Support destructors and conversions. + return std::nullopt; + } + + // Increment and Decrement. + if (interface_name == "Inc") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_PlusPlus; + } + if (interface_name == "Dec") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_MinusMinus; + } + + // Arithmetic. + if (interface_name == "Negate") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Minus; + } + + // Binary operators. + + // Arithmetic Operators. + if (interface_name == "AddWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Plus; + } + if (interface_name == "SubWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Minus; + } + if (interface_name == "MulWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Star; + } + if (interface_name == "DivWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Slash; + } + if (interface_name == "ModWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Percent; + } + + // Bitwise Operators. + if (interface_name == "BitAndWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Amp; + } + if (interface_name == "BitOrWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Pipe; + } + if (interface_name == "BitXorWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_Caret; + } + if (interface_name == "LeftShiftWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_LessLess; + } + if (interface_name == "RightShiftWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_GreaterGreater; + } + + // Compound Assignment Arithmetic Operators. + if (interface_name == "AddAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_PlusEqual; + } + if (interface_name == "SubAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_MinusEqual; + } + if (interface_name == "MulAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_StarEqual; + } + if (interface_name == "DivAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_SlashEqual; + } + if (interface_name == "ModAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_PercentEqual; + } + + // Compound Assignment Bitwise Operators. + if (interface_name == "BitAndAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_AmpEqual; + } + if (interface_name == "BitOrAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_PipeEqual; + } + if (interface_name == "BitXorAssignWith") { + CARBON_CHECK(op_name == "Op"); + return clang::OO_CaretEqual; + } + // TODO: Add support for `LeftShiftAssignWith` (`OO_LessLessEqual`) and + // `RightShiftAssignWith` (`OO_GreaterGreaterEqual`) when references are + // supported. + + // Relational Operators. + if (interface_name == "EqWith") { + if (op_name == "Equal") { + return clang::OO_EqualEqual; + } + CARBON_CHECK(op_name == "NotEqual"); + return clang::OO_ExclaimEqual; + } + if (interface_name == "OrderedWith") { + if (op_name == "Less") { + return clang::OO_Less; + } + if (op_name == "Greater") { + return clang::OO_Greater; + } + if (op_name == "LessOrEquivalent") { + return clang::OO_LessEqual; + } + CARBON_CHECK(op_name == "GreaterOrEquivalent"); + return clang::OO_GreaterEqual; + } + + context.TODO(loc_id, llvm::formatv("Unsupported operator interface `{0}`", + interface_name)); + return std::nullopt; +} + +auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op, + llvm::ArrayRef arg_ids) -> SemIR::InstId { + Diagnostics::AnnotationScope annotate_diagnostics( + &context.emitter(), [&](auto& builder) { + CARBON_DIAGNOSTIC(InCppOperatorLookup, Note, + "in `Cpp` operator `{0}` lookup", std::string); + builder.Note(loc_id, InCppOperatorLookup, op.interface_name.str()); + }); + + auto op_kind = + GetClangOperatorKind(context, loc_id, op.interface_name, op.op_name); + if (!op_kind) { + return SemIR::InstId::None; + } + + auto arg_exprs = InventClangArgs(context, arg_ids); + if (!arg_exprs.has_value()) { + return SemIR::ErrorInst::InstId; + } + + clang::Sema& sema = context.sem_ir().clang_ast_unit()->getSema(); + + clang::UnresolvedSet<4> functions; + // TODO: Add location accordingly. + clang::OverloadCandidateSet candidate_set( + clang::SourceLocation(), clang::OverloadCandidateSet::CSK_Operator); + // This works for both unary and binary operators. + sema.LookupOverloadedBinOp(candidate_set, *op_kind, functions, *arg_exprs); + + for (auto& it : candidate_set) { + if (!it.Function) { + continue; + } + functions.addDecl(it.Function, it.FoundDecl.getAccess()); + } + + return ImportCppOverloadSet(context, SemIR::NameScopeId::None, + SemIR::NameId::CppOperator, functions); +} + +} // namespace Carbon::Check diff --git a/toolchain/check/cpp/operators.h b/toolchain/check/cpp/operators.h new file mode 100644 index 000000000000..bf4c22f2cd38 --- /dev/null +++ b/toolchain/check/cpp/operators.h @@ -0,0 +1,22 @@ +// 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_CHECK_CPP_OPERATORS_H_ +#define CARBON_TOOLCHAIN_CHECK_CPP_OPERATORS_H_ + +#include "toolchain/check/context.h" +#include "toolchain/check/operator.h" +#include "toolchain/sem_ir/ids.h" + +namespace Carbon::Check { + +// Looks up the given operator in the Clang AST generated when importing C++ +// code using argument dependent lookup (ADL) and return overload set +// instruction. +auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op, + llvm::ArrayRef arg_ids) -> SemIR::InstId; + +} // namespace Carbon::Check + +#endif // CARBON_TOOLCHAIN_CHECK_CPP_OPERATORS_H_ diff --git a/toolchain/check/cpp/overload_resolution.cpp b/toolchain/check/cpp/overload_resolution.cpp index a8defbcdc2f0..4c70f6546407 100644 --- a/toolchain/check/cpp/overload_resolution.cpp +++ b/toolchain/check/cpp/overload_resolution.cpp @@ -8,63 +8,11 @@ #include "clang/Sema/Sema.h" #include "toolchain/check/cpp/import.h" #include "toolchain/check/cpp/type_mapping.h" -#include "toolchain/sem_ir/expr_info.h" +#include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/typed_insts.h" namespace Carbon::Check { -// Invents a Clang argument expression to use in overload resolution to -// represent the given Carbon argument instruction. -static auto InventClangArg(Context& context, SemIR::InstId arg_id) - -> clang::Expr* { - clang::ExprValueKind value_kind; - switch (SemIR::GetExprCategory(context.sem_ir(), arg_id)) { - case SemIR::ExprCategory::NotExpr: - CARBON_FATAL("Should not see these here"); - - case SemIR::ExprCategory::Error: - return nullptr; - - case SemIR::ExprCategory::DurableRef: - value_kind = clang::ExprValueKind::VK_LValue; - break; - - case SemIR::ExprCategory::EphemeralRef: - value_kind = clang::ExprValueKind::VK_XValue; - break; - - case SemIR::ExprCategory::Value: - case SemIR::ExprCategory::Initializing: - value_kind = clang::ExprValueKind::VK_PRValue; - break; - - case SemIR::ExprCategory::Mixed: - // TODO: Handle this by creating an InitListExpr. - value_kind = clang::ExprValueKind::VK_PRValue; - break; - } - - if (context.insts().Get(arg_id).type_id() == SemIR::ErrorInst::TypeId) { - // The argument error has already been diagnosed. - return nullptr; - } - - clang::QualType arg_cpp_type = MapToCppType(context, arg_id); - if (arg_cpp_type.isNull()) { - CARBON_DIAGNOSTIC(CppCallArgTypeNotSupported, Error, - "call argument of type {0} is not supported", - TypeOfInstId); - context.emitter().Emit(arg_id, CppCallArgTypeNotSupported, arg_id); - return nullptr; - } - - // TODO: Avoid heap allocating more of these on every call. Either cache them - // somewhere or put them on the stack. - return new (context.ast_context()) clang::OpaqueValueExpr( - // TODO: Add location accordingly. - clang::SourceLocation(), arg_cpp_type.getNonReferenceType(), value_kind); -} - // Adds the given overload candidates to the candidate set. static auto AddOverloadCandidataes(clang::Sema& sema, clang::OverloadCandidateSet& candidate_set, @@ -134,14 +82,9 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id, return SemIR::ErrorInst::InstId; } } - llvm::SmallVector arg_exprs; - arg_exprs.reserve(arg_ids.size()); - for (SemIR::InstId arg_id : arg_ids) { - auto* arg_expr = InventClangArg(context, arg_id); - if (!arg_expr) { - return SemIR::ErrorInst::InstId; - } - arg_exprs.push_back(arg_expr); + auto arg_exprs = InventClangArgs(context, arg_ids); + if (!arg_exprs.has_value()) { + return SemIR::ErrorInst::InstId; } const SemIR::CppOverloadSet& overload_set = @@ -158,7 +101,7 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id, clang::Sema& sema = ast->getSema(); AddOverloadCandidataes(sema, candidate_set, overload_set.candidate_functions, - self_expr, arg_exprs); + self_expr, *arg_exprs); // Find best viable function among the candidates. clang::OverloadCandidateSet::iterator best_viable_fn; diff --git a/toolchain/check/cpp/type_mapping.cpp b/toolchain/check/cpp/type_mapping.cpp index 2996ce5a2be6..636ab083a6d9 100644 --- a/toolchain/check/cpp/type_mapping.cpp +++ b/toolchain/check/cpp/type_mapping.cpp @@ -18,6 +18,7 @@ #include "toolchain/check/convert.h" #include "toolchain/check/literal.h" #include "toolchain/sem_ir/class.h" +#include "toolchain/sem_ir/expr_info.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/type.h" @@ -177,8 +178,12 @@ static auto MapNonWrapperType(Context& context, SemIR::InstId inst_id, } } +// Maps a Carbon type to a C++ type. Accepts an InstId, representing a value +// whose type is mapped to a C++ type. Returns `clang::QualType` if the mapping +// succeeds, or `clang::QualType::isNull()` if the type is not supported. // TODO: unify this with the C++ to Carbon type mapping function. -auto MapToCppType(Context& context, SemIR::InstId inst_id) -> clang::QualType { +static auto MapToCppType(Context& context, SemIR::InstId inst_id) + -> clang::QualType { auto type_id = context.insts().Get(inst_id).type_id(); llvm::SmallVector wrapper_types; while (true) { @@ -223,4 +228,67 @@ auto MapToCppType(Context& context, SemIR::InstId inst_id) -> clang::QualType { return mapped_type; } +auto InventClangArg(Context& context, SemIR::InstId arg_id) -> clang::Expr* { + clang::ExprValueKind value_kind; + switch (SemIR::GetExprCategory(context.sem_ir(), arg_id)) { + case SemIR::ExprCategory::NotExpr: + CARBON_FATAL("Should not see these here"); + + case SemIR::ExprCategory::Error: + return nullptr; + + case SemIR::ExprCategory::DurableRef: + value_kind = clang::ExprValueKind::VK_LValue; + break; + + case SemIR::ExprCategory::EphemeralRef: + value_kind = clang::ExprValueKind::VK_XValue; + break; + + case SemIR::ExprCategory::Value: + case SemIR::ExprCategory::Initializing: + value_kind = clang::ExprValueKind::VK_PRValue; + break; + + case SemIR::ExprCategory::Mixed: + // TODO: Handle this by creating an InitListExpr. + value_kind = clang::ExprValueKind::VK_PRValue; + break; + } + + if (context.insts().Get(arg_id).type_id() == SemIR::ErrorInst::TypeId) { + // The argument error has already been diagnosed. + return nullptr; + } + + clang::QualType arg_cpp_type = MapToCppType(context, arg_id); + if (arg_cpp_type.isNull()) { + CARBON_DIAGNOSTIC(CppCallArgTypeNotSupported, Error, + "call argument of type {0} is not supported", + TypeOfInstId); + context.emitter().Emit(arg_id, CppCallArgTypeNotSupported, arg_id); + return nullptr; + } + + // TODO: Avoid heap allocating more of these on every call. Either cache them + // somewhere or put them on the stack. + return new (context.ast_context()) clang::OpaqueValueExpr( + // TODO: Add location accordingly. + clang::SourceLocation(), arg_cpp_type.getNonReferenceType(), value_kind); +} + +auto InventClangArgs(Context& context, llvm::ArrayRef arg_ids) + -> std::optional> { + llvm::SmallVector arg_exprs; + arg_exprs.reserve(arg_ids.size()); + for (SemIR::InstId arg_id : arg_ids) { + auto* arg_expr = InventClangArg(context, arg_id); + if (!arg_expr) { + return std::nullopt; + } + arg_exprs.push_back(arg_expr); + } + return arg_exprs; +} + } // namespace Carbon::Check diff --git a/toolchain/check/cpp/type_mapping.h b/toolchain/check/cpp/type_mapping.h index c467d8a5ebf3..8b6ffb0ba2d9 100644 --- a/toolchain/check/cpp/type_mapping.h +++ b/toolchain/check/cpp/type_mapping.h @@ -11,10 +11,15 @@ namespace Carbon::Check { -// Maps a Carbon type to a C++ type. Accepts an InstId, representing a value -// whose type is mapped to a C++ type. Returns `clang::QualType` if the mapping -// succeeds, or `clang::QualType::isNull()` if the type is not supported. -auto MapToCppType(Context& context, SemIR::InstId inst_id) -> clang::QualType; +// Invents a Clang argument expression to use in overload resolution to +// represent the given Carbon argument instruction. +auto InventClangArg(Context& context, SemIR::InstId arg_id) -> clang::Expr*; + +// For each arg, invents a Clang argument expression to use in overload +// resolution or argument dependent lookup (ADL) to represent the given Carbon +// argument instructions. Returns std::nullopt if any arg failed. +auto InventClangArgs(Context& context, llvm::ArrayRef arg_ids) + -> std::optional>; } // namespace Carbon::Check diff --git a/toolchain/check/operator.cpp b/toolchain/check/operator.cpp index ae2986d5a3c0..97eedcf659e8 100644 --- a/toolchain/check/operator.cpp +++ b/toolchain/check/operator.cpp @@ -8,7 +8,7 @@ #include "toolchain/check/call.h" #include "toolchain/check/context.h" -#include "toolchain/check/cpp/import.h" +#include "toolchain/check/cpp/operators.h" #include "toolchain/check/generic.h" #include "toolchain/check/member_access.h" #include "toolchain/check/name_lookup.h" @@ -39,35 +39,18 @@ static auto GetOperatorOpFunction(Context& context, SemIR::LocId loc_id, op_name_id); } -// If the instruction is a C++ class, returns its parent scope id. Otherwise -// returns `std::nullopt`. -static auto GetCppClassTypeParentScope(Context& context, SemIR::InstId inst_id) - -> std::optional { +// Returns whether the instruction is a C++ class. +static auto IsCppClassType(Context& context, SemIR::InstId inst_id) -> bool { auto class_type = context.insts().TryGetAs( context.types().GetInstId(context.insts().Get(inst_id).type_id())); if (!class_type) { // Not a class. - return std::nullopt; + return false; } const SemIR::Class& class_info = context.classes().Get(class_type->class_id); - if (!class_info.is_complete() || - !context.name_scopes().Get(class_info.scope_id).is_cpp_scope()) { - // Not a C++ class. - return std::nullopt; - } - - SemIR::NameScopeId parent_scope_id = class_info.parent_scope_id; - do { - SemIR::NameScope& scope = context.name_scopes().Get(parent_scope_id); - if (context.insts().Is(scope.inst_id())) { - break; - } - parent_scope_id = scope.parent_scope_id(); - - } while (parent_scope_id.has_value()); - - return parent_scope_id; + return class_info.is_complete() && + context.name_scopes().Get(class_info.scope_id).is_cpp_scope(); } auto BuildUnaryOperator(Context& context, SemIR::LocId loc_id, Operator op, @@ -78,16 +61,11 @@ auto BuildUnaryOperator(Context& context, SemIR::LocId loc_id, Operator op, // the C++ operator. // TODO: Change impl lookup instead. See // https://github.com/carbon-language/carbon-lang/blob/db0a00d713015436844c55e7ac190a0f95556499/toolchain/check/operator.cpp#L76 - // TODO: We should do ADL-only lookup for operators - // (`Sema::ArgumentDependentLookup`), when we support mapping Carbon types - // into C++ types. - auto cpp_parent_scope_id = GetCppClassTypeParentScope(context, operand_id); - if (cpp_parent_scope_id) { - SemIR::ScopeLookupResult cpp_lookup_result = - ImportOperatorFromCpp(context, loc_id, *cpp_parent_scope_id, op); - if (cpp_lookup_result.is_found()) { - return PerformCall(context, loc_id, cpp_lookup_result.target_inst_id(), - {operand_id}); + if (IsCppClassType(context, operand_id)) { + SemIR::InstId cpp_inst_id = + LookupCppOperator(context, loc_id, op, {operand_id}); + if (cpp_inst_id.has_value() && cpp_inst_id != SemIR::ErrorInst::InstId) { + return PerformCall(context, loc_id, cpp_inst_id, {operand_id}); } } @@ -117,22 +95,11 @@ auto BuildBinaryOperator(Context& context, SemIR::LocId loc_id, Operator op, // https://github.com/carbon-language/carbon-lang/pull/5996/files/5d01fa69511b76f87efbc0387f5e40abcf4c911a#r2308666348 // and // https://github.com/carbon-language/carbon-lang/pull/5996/files/5d01fa69511b76f87efbc0387f5e40abcf4c911a#r2308664536 - // TODO: We should do ADL-only lookup for operators - // (`Sema::ArgumentDependentLookup`), when we support mapping Carbon types - // into C++ types. - llvm::SmallVector cpp_operand_parent_scope_ids; - for (SemIR::InstId operand_id : {lhs_id, rhs_id}) { - auto cpp_parent_scope_id = GetCppClassTypeParentScope(context, operand_id); - if (!cpp_parent_scope_id || llvm::is_contained(cpp_operand_parent_scope_ids, - *cpp_parent_scope_id)) { - continue; - } - cpp_operand_parent_scope_ids.push_back(*cpp_parent_scope_id); - SemIR::ScopeLookupResult cpp_lookup_result = - ImportOperatorFromCpp(context, loc_id, *cpp_parent_scope_id, op); - if (cpp_lookup_result.is_found()) { - return PerformCall(context, loc_id, cpp_lookup_result.target_inst_id(), - {lhs_id, rhs_id}); + if (IsCppClassType(context, lhs_id) || IsCppClassType(context, rhs_id)) { + SemIR::InstId cpp_inst_id = + LookupCppOperator(context, loc_id, op, {lhs_id, rhs_id}); + if (cpp_inst_id.has_value() && cpp_inst_id != SemIR::ErrorInst::InstId) { + return PerformCall(context, loc_id, cpp_inst_id, {lhs_id, rhs_id}); } } diff --git a/toolchain/check/testdata/interop/cpp/function/operators.carbon b/toolchain/check/testdata/interop/cpp/function/operators.carbon index 2a73a8d39a51..2fc72280f82c 100644 --- a/toolchain/check/testdata/interop/cpp/function/operators.carbon +++ b/toolchain/check/testdata/interop/cpp/function/operators.carbon @@ -95,16 +95,20 @@ import Cpp library "postfix_inc_and_dec.h"; fn F() { let postfix: Cpp.Postfix = Cpp.Postfix.Postfix(); // TODO: Make the error more descriptive to clarify we call prefix operators of a class with suffix operators. - // CHECK:STDERR: fail_postfix_calling_prefix.carbon:[[@LINE+5]]:3: error: 1 argument passed to function expecting 2 arguments [CallArgCountMismatch] + // CHECK:STDERR: fail_postfix_calling_prefix.carbon:[[@LINE+7]]:3: error: no matching function for call to `` [CppOverloadingNoViableFunctionFound] + // CHECK:STDERR: ++postfix; + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: fail_postfix_calling_prefix.carbon:[[@LINE+4]]:3: note: in call to Cpp function here [InCallToCppFunction] // CHECK:STDERR: ++postfix; // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_postfix_calling_prefix.carbon: note: calling function declared here [InCallToEntity] // CHECK:STDERR: ++postfix; - // CHECK:STDERR: fail_postfix_calling_prefix.carbon:[[@LINE+5]]:3: error: 1 argument passed to function expecting 2 arguments [CallArgCountMismatch] + // CHECK:STDERR: fail_postfix_calling_prefix.carbon:[[@LINE+7]]:3: error: no matching function for call to `` [CppOverloadingNoViableFunctionFound] + // CHECK:STDERR: --postfix; + // CHECK:STDERR: ^~~~~~~~~ + // CHECK:STDERR: fail_postfix_calling_prefix.carbon:[[@LINE+4]]:3: note: in call to Cpp function here [InCallToCppFunction] // CHECK:STDERR: --postfix; // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_postfix_calling_prefix.carbon: note: calling function declared here [InCallToEntity] // CHECK:STDERR: --postfix; } @@ -225,22 +229,20 @@ import Cpp library "binary_operators.h"; fn F() { let c1: Cpp.C = Cpp.C.C(); - // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+8]]:24: error: cannot implicitly convert expression of type `Core.IntLiteral` to `Cpp.C` [ConversionFailure] + // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+7]]:19: error: no matching function for call to `` [CppOverloadingNoViableFunctionFound] // CHECK:STDERR: let c2: Cpp.C = c1 + 5; - // CHECK:STDERR: ^ - // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+5]]:24: note: type `Core.IntLiteral` does not implement interface `Core.ImplicitAs(Cpp.C)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+4]]:19: note: in call to Cpp function here [InCallToCppFunction] // CHECK:STDERR: let c2: Cpp.C = c1 + 5; - // CHECK:STDERR: ^ - // CHECK:STDERR: fail_call_with_wrong_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: let c2: Cpp.C = c1 + 5; - // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+8]]:19: error: cannot implicitly convert expression of type `Core.IntLiteral` to `Cpp.C` [ConversionFailure] + // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+7]]:19: error: no matching function for call to `` [CppOverloadingNoViableFunctionFound] // CHECK:STDERR: let c3: Cpp.C = 6 + c1; - // CHECK:STDERR: ^ - // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+5]]:19: note: type `Core.IntLiteral` does not implement interface `Core.ImplicitAs(Cpp.C)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_call_with_wrong_type.carbon:[[@LINE+4]]:19: note: in call to Cpp function here [InCallToCppFunction] // CHECK:STDERR: let c3: Cpp.C = 6 + c1; - // CHECK:STDERR: ^ - // CHECK:STDERR: fail_call_with_wrong_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: ^~~~~~ // CHECK:STDERR: let c3: Cpp.C = 6 + c1; } @@ -600,7 +602,10 @@ fn F() { //@dump-sem-ir-begin let c1: Cpp.N.C = Cpp.N.C.C(); let c2: Cpp.N.C = Cpp.N.C.C(); - // CHECK:STDERR: fail_todo_import_operands_in_namespace_operator_in_global.carbon:[[@LINE+4]]:21: error: cannot access member of interface `Core.AddWith(Cpp.N.C)` in type `Cpp.N.C` that does not implement that interface [MissingImplInMemberAccess] + // CHECK:STDERR: fail_todo_import_operands_in_namespace_operator_in_global.carbon:[[@LINE+7]]:21: error: no matching function for call to `` [CppOverloadingNoViableFunctionFound] + // CHECK:STDERR: let c3: Cpp.N.C = c1 + c2; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_operands_in_namespace_operator_in_global.carbon:[[@LINE+4]]:21: note: in call to Cpp function here [InCallToCppFunction] // CHECK:STDERR: let c3: Cpp.N.C = c1 + c2; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: @@ -672,7 +677,7 @@ class C { auto operator+(C rhs) -> C; }; -// --- fail_todo_import_member__add_with.carbon +// --- fail_todo_import_member_add_with.carbon library "[[@TEST_NAME]]"; @@ -682,7 +687,10 @@ fn F() { //@dump-sem-ir-begin let c1: Cpp.C = Cpp.C.C(); let c2: Cpp.C = Cpp.C.C(); - // CHECK:STDERR: fail_todo_import_member__add_with.carbon:[[@LINE+4]]:19: error: cannot access member of interface `Core.AddWith(Cpp.C)` in type `Cpp.C` that does not implement that interface [MissingImplInMemberAccess] + // CHECK:STDERR: fail_todo_import_member_add_with.carbon:[[@LINE+7]]:19: error: no matching function for call to `` [CppOverloadingNoViableFunctionFound] + // CHECK:STDERR: let c3: Cpp.C = c1 + c2; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_member_add_with.carbon:[[@LINE+4]]:19: note: in call to Cpp function here [InCallToCppFunction] // CHECK:STDERR: let c3: Cpp.C = c1 + c2; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: @@ -737,13 +745,48 @@ import Cpp library "not_found.h"; fn F() { let c1: Cpp.C = Cpp.C.C(); let c2: Cpp.C = Cpp.C.C(); - // CHECK:STDERR: fail_import_not_found.carbon:[[@LINE+4]]:19: error: cannot access member of interface `Core.AddWith(Cpp.C)` in type `Cpp.C` that does not implement that interface [MissingImplInMemberAccess] + // CHECK:STDERR: fail_import_not_found.carbon:[[@LINE+7]]:19: error: no matching function for call to `` [CppOverloadingNoViableFunctionFound] + // CHECK:STDERR: let c3: Cpp.C = c1 + c2; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_import_not_found.carbon:[[@LINE+4]]:19: note: in call to Cpp function here [InCallToCppFunction] // CHECK:STDERR: let c3: Cpp.C = c1 + c2; // CHECK:STDERR: ^~~~~~~ // CHECK:STDERR: let c3: Cpp.C = c1 + c2; } +// ============================================================================ +// Incomplete operand +// ============================================================================ + +// --- incomplete.h + +class Incomplete; +class Complete {}; + +auto operator+(Complete lhs, Incomplete rhs) -> Complete; + +auto foo(Complete complete) -> void; + +// --- fail_import_incomplete.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "incomplete.h"; + +fn F() { + var c1: Cpp.Complete = Cpp.Complete.Complete(); + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:40: error: invalid use of incomplete type `Cpp.Incomplete` [IncompleteTypeInConversion] + // CHECK:STDERR: let c3: Cpp.Complete = Cpp.foo(c1 + ({} as Cpp.Incomplete)); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-7]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./incomplete.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class Incomplete; + // CHECK:STDERR: ^ + // CHECK:STDERR: + let c3: Cpp.Complete = Cpp.foo(c1 + ({} as Cpp.Incomplete)); +} + // ============================================================================ // Operator overloading // ============================================================================ @@ -755,7 +798,7 @@ auto operator+(C lhs, C rhs) -> C; class D {}; auto operator+(D lhs, D rhs) -> D; -// --- fail_todo_import_overloading.carbon +// --- import_overloading.carbon library "[[@TEST_NAME]]"; @@ -764,13 +807,6 @@ import Cpp library "overloading.h"; fn F() { let c1: Cpp.C = Cpp.C.C(); let c2: Cpp.C = Cpp.C.C(); - // CHECK:STDERR: fail_todo_import_overloading.carbon:[[@LINE+7]]:19: error: semantics TODO: `Unsupported: Lookup succeeded but couldn't find a single result; LookupResultKind: 3` [SemanticsTodo] - // CHECK:STDERR: let c3: Cpp.C = c1 + c2; - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_overloading.carbon:[[@LINE+4]]:19: note: in `Cpp` operator `AddWith` lookup [InCppOperatorLookup] - // CHECK:STDERR: let c3: Cpp.C = c1 + c2; - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: let c3: Cpp.C = c1 + c2; } @@ -780,8 +816,8 @@ fn F() { // 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: %.d40: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete] +// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @operator++__carbon_thunk [concrete] +// CHECK:STDOUT: %empty_struct.e73: %.d40 = struct_value () [concrete] // CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -803,7 +839,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @operator++__carbon_thunk [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -833,7 +869,7 @@ fn F() { // 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: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_23: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %.loc8_26.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc8_26.1: %ptr.d9e = addr_of %.loc8_26.1 // CHECK:STDOUT: %C__carbon_thunk.call: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_26.1) @@ -915,8 +951,8 @@ fn F() { // 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: %.d40: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete] +// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @Copy.Op [concrete] +// CHECK:STDOUT: %empty_struct.e73: %.d40 = struct_value () [concrete] // CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -1005,7 +1041,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @Copy.Op [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -1144,7 +1180,7 @@ fn F() { // CHECK:STDOUT: %c1.var: ref %C = var %c1.var_patt // 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: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %.loc8_3.1: ref %C = splice_block %c1.var {} // CHECK:STDOUT: %addr.loc8_27: %ptr.d9e = addr_of %.loc8_3.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_27) @@ -1162,7 +1198,7 @@ fn F() { // CHECK:STDOUT: %c2.var: ref %C = var %c2.var_patt // CHECK:STDOUT: %Cpp.ref.loc9_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref.loc9_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %.loc9_3.1: ref %C = splice_block %c2.var {} // CHECK:STDOUT: %addr.loc9_27: %ptr.d9e = addr_of %.loc9_3.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_27) @@ -1792,8 +1828,8 @@ fn F() { // 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: %.d40: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete] +// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @operator+__carbon_thunk [concrete] +// CHECK:STDOUT: %empty_struct.e73: %.d40 = struct_value () [concrete] // CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -1811,7 +1847,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @operator+__carbon_thunk [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -1831,7 +1867,7 @@ fn F() { // 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: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %.loc8_27.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc8_27.1: %ptr.d9e = addr_of %.loc8_27.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_27.1) @@ -1848,7 +1884,7 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: %Cpp.ref.loc9_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref.loc9_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %.loc9_27.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc9_27.1: %ptr.d9e = addr_of %.loc9_27.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_27.1) @@ -1964,8 +2000,8 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %pattern_type.69f: type = pattern_type %C [concrete] -// CHECK:STDOUT: %.169: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.169 = struct_value () [concrete] +// CHECK:STDOUT: %.169: type = cpp_overload_set_type @C__carbon_thunk [concrete] +// CHECK:STDOUT: %empty_struct.41c: %.169 = struct_value () [concrete] // CHECK:STDOUT: %ptr.838: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -1987,7 +2023,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.c52: %.169 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.c52: %.169 = cpp_overload_set_value @C__carbon_thunk [concrete = constants.%empty_struct.41c] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -2008,7 +2044,7 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc8_21: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %N.ref.loc8_24: = name_ref N, imports.%N [concrete = imports.%N] // CHECK:STDOUT: %C.ref.loc8_26: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc8_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct.41c] // CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc8_31.1: %ptr.838 = addr_of %.loc8_31.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_31.1) @@ -2027,7 +2063,7 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc9_21: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %N.ref.loc9_24: = name_ref N, imports.%N [concrete = imports.%N] // CHECK:STDOUT: %C.ref.loc9_26: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc9_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc9_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct.41c] // CHECK:STDOUT: %.loc9_31.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc9_31.1: %ptr.838 = addr_of %.loc9_31.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_31.1) @@ -2091,14 +2127,14 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %C1: type = class_type @C1 [concrete] // CHECK:STDOUT: %pattern_type.20f: type = pattern_type %C1 [concrete] -// CHECK:STDOUT: %.eb7: type = cpp_overload_set_type @C1__carbon_thunk [concrete] +// CHECK:STDOUT: %.eb7: type = cpp_overload_set_type @C2__carbon_thunk [concrete] // CHECK:STDOUT: %empty_struct.56f: %.eb7 = struct_value () [concrete] // CHECK:STDOUT: %ptr.087: type = ptr_type %C1 [concrete] // CHECK:STDOUT: %C1__carbon_thunk.type: type = fn_type @C1__carbon_thunk [concrete] // CHECK:STDOUT: %C1__carbon_thunk: %C1__carbon_thunk.type = struct_value () [concrete] // CHECK:STDOUT: %C2: type = class_type @C2 [concrete] // CHECK:STDOUT: %pattern_type.846: type = pattern_type %C2 [concrete] -// CHECK:STDOUT: %.74f: type = cpp_overload_set_type @C2.C2 [concrete] +// CHECK:STDOUT: %.74f: type = cpp_overload_set_type @cpp_operator.1 [concrete] // CHECK:STDOUT: %empty_struct.c81: %.74f = struct_value () [concrete] // CHECK:STDOUT: %ptr.51f: type = ptr_type %C2 [concrete] // CHECK:STDOUT: %C2__carbon_thunk.type: type = fn_type @C2__carbon_thunk [concrete] @@ -2127,7 +2163,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C1.decl: type = class_decl @C1 [concrete = constants.%C1] {} {} -// CHECK:STDOUT: %.91f: %.eb7 = cpp_overload_set_value @C1__carbon_thunk [concrete = constants.%empty_struct.56f] +// CHECK:STDOUT: %.91f: %.eb7 = cpp_overload_set_value @C2__carbon_thunk [concrete = constants.%empty_struct.56f] // CHECK:STDOUT: %C1__carbon_thunk.decl: %C1__carbon_thunk.type = fn_decl @C1__carbon_thunk [concrete = constants.%C1__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -2138,7 +2174,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C2.decl: type = class_decl @C2 [concrete = constants.%C2] {} {} -// CHECK:STDOUT: %.ed5: %.74f = cpp_overload_set_value @C2.C2 [concrete = constants.%empty_struct.c81] +// CHECK:STDOUT: %.ed5: %.74f = cpp_overload_set_value @cpp_operator.1 [concrete = constants.%empty_struct.c81] // CHECK:STDOUT: %C2__carbon_thunk.decl: %C2__carbon_thunk.type = fn_decl @C2__carbon_thunk [concrete = constants.%C2__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -2275,8 +2311,8 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %pattern_type.69f: type = pattern_type %C [concrete] -// CHECK:STDOUT: %.169: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.169 = struct_value () [concrete] +// CHECK:STDOUT: %.169: type = cpp_overload_set_type @C__carbon_thunk [concrete] +// CHECK:STDOUT: %empty_struct.41c: %.169 = struct_value () [concrete] // CHECK:STDOUT: %ptr.838: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -2296,7 +2332,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.c52: %.169 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.c52: %.169 = cpp_overload_set_value @C__carbon_thunk [concrete = constants.%empty_struct.41c] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -2312,7 +2348,7 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc8_21: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %N.ref.loc8_24: = name_ref N, imports.%N [concrete = imports.%N] // CHECK:STDOUT: %C.ref.loc8_26: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc8_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct.41c] // CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc8_31.1: %ptr.838 = addr_of %.loc8_31.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_31.1) @@ -2331,7 +2367,7 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc9_21: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %N.ref.loc9_24: = name_ref N, imports.%N [concrete = imports.%N] // CHECK:STDOUT: %C.ref.loc9_26: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc9_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc9_28: %.169 = name_ref C, imports.%.c52 [concrete = constants.%empty_struct.41c] // CHECK:STDOUT: %.loc9_31.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc9_31.1: %ptr.838 = addr_of %.loc9_31.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_31.1) @@ -2349,10 +2385,10 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: %c1.ref: %C = name_ref c1, %c1 // CHECK:STDOUT: %c2.ref: %C = name_ref c2, %c2 -// CHECK:STDOUT: %.loc14: type = splice_block %C.ref.loc14 [concrete = constants.%C] { -// CHECK:STDOUT: %Cpp.ref.loc14: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %N.ref.loc14: = name_ref N, imports.%N [concrete = imports.%N] -// CHECK:STDOUT: %C.ref.loc14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %.loc17: type = splice_block %C.ref.loc17 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %N.ref.loc17: = name_ref N, imports.%N [concrete = imports.%N] +// CHECK:STDOUT: %C.ref.loc17: type = name_ref C, imports.%C.decl [concrete = constants.%C] // CHECK:STDOUT: } // CHECK:STDOUT: %c3: %C = bind_name c3, [concrete = ] // CHECK:STDOUT: %facet_value.loc9: %type_where = facet_value constants.%C, () [concrete = constants.%facet_value] @@ -2379,8 +2415,8 @@ fn F() { // CHECK:STDOUT: %O: type = class_type @O [concrete] // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %pattern_type.b28: type = pattern_type %C [concrete] -// CHECK:STDOUT: %.d80: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.d80 = struct_value () [concrete] +// CHECK:STDOUT: %.d80: type = cpp_overload_set_type @C__carbon_thunk [concrete] +// CHECK:STDOUT: %empty_struct.06f: %.d80 = struct_value () [concrete] // CHECK:STDOUT: %ptr.de2: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -2399,7 +2435,7 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.7a9: %.d80 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.7a9: %.d80 = cpp_overload_set_value @C__carbon_thunk [concrete = constants.%empty_struct.06f] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -2420,7 +2456,7 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc8_21: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %O.ref.loc8_24: type = name_ref O, imports.%O.decl [concrete = constants.%O] // CHECK:STDOUT: %C.ref.loc8_26: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc8_28: %.d80 = name_ref C, imports.%.7a9 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_28: %.d80 = name_ref C, imports.%.7a9 [concrete = constants.%empty_struct.06f] // CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc8_31.1: %ptr.de2 = addr_of %.loc8_31.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_31.1) @@ -2439,7 +2475,7 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc9_21: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %O.ref.loc9_24: type = name_ref O, imports.%O.decl [concrete = constants.%O] // CHECK:STDOUT: %C.ref.loc9_26: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc9_28: %.d80 = name_ref C, imports.%.7a9 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc9_28: %.d80 = name_ref C, imports.%.7a9 [concrete = constants.%empty_struct.06f] // CHECK:STDOUT: %.loc9_31.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc9_31.1: %ptr.de2 = addr_of %.loc9_31.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_31.1) @@ -2504,8 +2540,8 @@ fn F() { // CHECK:STDOUT: %O: type = class_type @O [concrete] // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %pattern_type.84b: type = pattern_type %C [concrete] -// CHECK:STDOUT: %.62f: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.62f = struct_value () [concrete] +// CHECK:STDOUT: %.62f: type = cpp_overload_set_type @C__carbon_thunk [concrete] +// CHECK:STDOUT: %empty_struct.e94: %.62f = struct_value () [concrete] // CHECK:STDOUT: %ptr.4b2: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -2528,7 +2564,7 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: %O.decl: type = class_decl @O [concrete = constants.%O] {} {} // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.f56: %.62f = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.f56: %.62f = cpp_overload_set_value @C__carbon_thunk [concrete = constants.%empty_struct.e94] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -2550,7 +2586,7 @@ fn F() { // CHECK:STDOUT: %N.ref.loc8_26: = name_ref N, imports.%N [concrete = imports.%N] // CHECK:STDOUT: %O.ref.loc8_28: type = name_ref O, imports.%O.decl [concrete = constants.%O] // CHECK:STDOUT: %C.ref.loc8_30: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc8_32: %.62f = name_ref C, imports.%.f56 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_32: %.62f = name_ref C, imports.%.f56 [concrete = constants.%empty_struct.e94] // CHECK:STDOUT: %.loc8_35.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc8_35.1: %ptr.4b2 = addr_of %.loc8_35.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_35.1) @@ -2571,7 +2607,7 @@ fn F() { // CHECK:STDOUT: %N.ref.loc9_26: = name_ref N, imports.%N [concrete = imports.%N] // CHECK:STDOUT: %O.ref.loc9_28: type = name_ref O, imports.%O.decl [concrete = constants.%O] // CHECK:STDOUT: %C.ref.loc9_30: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc9_32: %.62f = name_ref C, imports.%.f56 [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc9_32: %.62f = name_ref C, imports.%.f56 [concrete = constants.%empty_struct.e94] // CHECK:STDOUT: %.loc9_35.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc9_35.1: %ptr.4b2 = addr_of %.loc9_35.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_35.1) @@ -2631,14 +2667,14 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_member__add_with.carbon +// CHECK:STDOUT: --- fail_todo_import_member_add_with.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: %.d40: type = cpp_overload_set_type @C.C [concrete] -// CHECK:STDOUT: %empty_struct: %.d40 = struct_value () [concrete] +// CHECK:STDOUT: %.d40: type = cpp_overload_set_type @C__carbon_thunk [concrete] +// CHECK:STDOUT: %empty_struct.e73: %.d40 = struct_value () [concrete] // CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: %C__carbon_thunk.type: type = fn_type @C__carbon_thunk [concrete] // CHECK:STDOUT: %C__carbon_thunk: %C__carbon_thunk.type = struct_value () [concrete] @@ -2654,7 +2690,7 @@ fn F() { // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} -// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C.C [concrete = constants.%empty_struct] +// CHECK:STDOUT: %.40b: %.d40 = cpp_overload_set_value @C__carbon_thunk [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %C__carbon_thunk.decl: %C__carbon_thunk.type = fn_decl @C__carbon_thunk [concrete = constants.%C__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -2669,7 +2705,7 @@ fn F() { // 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: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc8_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %.loc8_27.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc8_27.1: %ptr.d9e = addr_of %.loc8_27.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc8: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc8_27.1) @@ -2686,7 +2722,7 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: %Cpp.ref.loc9_19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref.loc9_22: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct] +// CHECK:STDOUT: %C.ref.loc9_24: %.d40 = name_ref C, imports.%.40b [concrete = constants.%empty_struct.e73] // CHECK:STDOUT: %.loc9_27.1: ref %C = temporary_storage // CHECK:STDOUT: %addr.loc9_27.1: %ptr.d9e = addr_of %.loc9_27.1 // CHECK:STDOUT: %C__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%C__carbon_thunk.decl(%addr.loc9_27.1) @@ -2703,9 +2739,9 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: %c1.ref: %C = name_ref c1, %c1 // CHECK:STDOUT: %c2.ref: %C = name_ref c2, %c2 -// CHECK:STDOUT: %.loc14: type = splice_block %C.ref.loc14 [concrete = constants.%C] { -// CHECK:STDOUT: %Cpp.ref.loc14: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %C.ref.loc14: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %.loc17: type = splice_block %C.ref.loc17 [concrete = constants.%C] { +// CHECK:STDOUT: %Cpp.ref.loc17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref.loc17: type = name_ref C, imports.%C.decl [concrete = constants.%C] // CHECK:STDOUT: } // CHECK:STDOUT: %c3: %C = bind_name c3, [concrete = ] // CHECK:STDOUT: %facet_value.loc9: %type_where = facet_value constants.%C, () [concrete = constants.%facet_value]