Implement support for copying C++ classes. (#6434)

When performing impl lookup for `Core.Copy` for a C++ class type, look
for a copy constructor. If we find one, synthesize an impl witness that
calls the constructor.

This adds initial support for impl lookup to delegate to the C++ interop
logic for queries involving C++ types. For now, we don't implement the
rules from #6166 that compare a synthesized type structure for the C++
impl against the best Carbon type structure, but the framework for
building that support is established here.

Currently there is no caching of the lookup here, and we build unique
`ImplWitnessTable`s for each lookup, which leads to each impl lookup
producing a distinct facet value. This results in some errors in generic
contexts; this will be addressed in follow-up changes. This PR aims only
to support the non-generic case.

---------

Co-authored-by: Dana Jansens <danakj@orodu.net>
Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
This commit is contained in:
Richard Smith
2025-12-02 02:52:23 +00:00
committed by GitHub
co-authored by Dana Jansens Carbon Infra Bot
parent 19660ccde0
commit 372f632d9d
16 changed files with 923 additions and 127 deletions
+26 -6
View File
@@ -25,7 +25,7 @@ static auto GetClangOperatorKind(Context& context, SemIR::LocId loc_id,
-> std::optional<clang::OverloadedOperatorKind> {
// Unary operators.
if (interface_name == "Destroy" || interface_name == "As" ||
interface_name == "ImplicitAs") {
interface_name == "ImplicitAs" || interface_name == "Copy") {
// TODO: Support destructors and conversions.
return std::nullopt;
}
@@ -280,17 +280,37 @@ auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {
return clang_method_decl && clang_method_decl->isOverloadedOperator();
}
auto IsCppOperatorMethod(Context& context, SemIR::InstId inst_id) -> bool {
static auto GetAsCppFunctionDecl(Context& context, SemIR::InstId inst_id)
-> clang::FunctionDecl* {
auto function_type = context.types().TryGetAs<SemIR::FunctionType>(
context.insts().Get(inst_id).type_id());
if (!function_type) {
return false;
return nullptr;
}
SemIR::ClangDeclId clang_decl_id =
context.functions().Get(function_type->function_id).clang_decl_id;
return clang_decl_id.has_value() &&
IsCppOperatorMethodDecl(
context.clang_decls().Get(clang_decl_id).key.decl);
return clang_decl_id.has_value()
? dyn_cast<clang::FunctionDecl>(
context.clang_decls().Get(clang_decl_id).key.decl)
: nullptr;
}
auto IsCppOperatorMethod(Context& context, SemIR::InstId inst_id) -> bool {
auto* function_decl = GetAsCppFunctionDecl(context, inst_id);
return function_decl && IsCppOperatorMethodDecl(function_decl);
}
auto IsCppConstructorOrNonMethodOperator(Context& context,
SemIR::InstId inst_id) -> bool {
auto* function_decl = GetAsCppFunctionDecl(context, inst_id);
if (!function_decl) {
return false;
}
if (isa<clang::CXXConstructorDecl>(function_decl)) {
return true;
}
return !isa<clang::CXXMethodDecl>(function_decl) &&
function_decl->isOverloadedOperator();
}
} // namespace Carbon::Check