mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Improve diagnostics for overload resolution failure. (#6091)
Include notes listing the candidates and explaining why they didn't work. Rather than duplicating the (substantial) logic for this, use the Clang machinery to generate these diagnostics. In order to support this, add a mechanism to map `SemIR::LocId`s to `clang::SourceLocation`s. This works by creating source buffers in Clang that refer into the Carbon source file so that `SourceLocation`s can point into them. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
parent
ef488f00fa
commit
925250f8f9
@@ -4,15 +4,27 @@
|
||||
|
||||
#include "toolchain/check/cpp/overload_resolution.h"
|
||||
|
||||
#include "clang/Basic/DiagnosticSema.h"
|
||||
#include "clang/Sema/Overload.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "toolchain/check/cpp/import.h"
|
||||
#include "toolchain/check/cpp/location.h"
|
||||
#include "toolchain/check/cpp/type_mapping.h"
|
||||
#include "toolchain/sem_ir/ids.h"
|
||||
#include "toolchain/sem_ir/typed_insts.h"
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
// Map a Carbon name into a C++ name.
|
||||
static auto GetCppName(Context& context, SemIR::NameId name_id)
|
||||
-> clang::DeclarationName {
|
||||
// TODO: Some special names should probably use different formatting. In
|
||||
// particular, NameId::CppOperator should probably map back to a
|
||||
// CXXOperatorName.
|
||||
auto name_str = context.names().GetFormatted(name_id);
|
||||
return clang::DeclarationName(&context.ast_context().Idents.get(name_str));
|
||||
}
|
||||
|
||||
// Adds the given overload candidates to the candidate set.
|
||||
static auto AddOverloadCandidataes(clang::Sema& sema,
|
||||
clang::OverloadCandidateSet& candidate_set,
|
||||
@@ -67,13 +79,6 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::InstId self_id,
|
||||
llvm::ArrayRef<SemIR::InstId> arg_ids)
|
||||
-> SemIR::InstId {
|
||||
Diagnostics::AnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(InCallToCppFunction, Note,
|
||||
"in call to Cpp function here");
|
||||
builder.Note(loc_id, InCallToCppFunction);
|
||||
});
|
||||
|
||||
// Map Carbon call argument types to C++ types.
|
||||
clang::Expr* self_expr = nullptr;
|
||||
if (self_id.has_value()) {
|
||||
@@ -82,67 +87,63 @@ auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
}
|
||||
auto arg_exprs = InventClangArgs(context, arg_ids);
|
||||
if (!arg_exprs.has_value()) {
|
||||
auto maybe_arg_exprs = InventClangArgs(context, arg_ids);
|
||||
if (!maybe_arg_exprs.has_value()) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
auto& arg_exprs = *maybe_arg_exprs;
|
||||
|
||||
const SemIR::CppOverloadSet& overload_set =
|
||||
context.cpp_overload_sets().Get(overload_set_id);
|
||||
|
||||
clang::SourceLocation loc = GetCppLocation(context, loc_id);
|
||||
|
||||
// Add candidate functions from the name lookup.
|
||||
clang::OverloadCandidateSet candidate_set(
|
||||
// TODO: Add location accordingly.
|
||||
clang::SourceLocation(),
|
||||
clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal);
|
||||
loc, clang::OverloadCandidateSet::CandidateSetKind::CSK_Normal);
|
||||
|
||||
clang::ASTUnit* ast = context.sem_ir().clang_ast_unit();
|
||||
CARBON_CHECK(ast);
|
||||
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;
|
||||
clang::OverloadingResult overloading_result =
|
||||
// TODO: Add location accordingly.
|
||||
candidate_set.BestViableFunction(sema, clang::SourceLocation(),
|
||||
best_viable_fn);
|
||||
candidate_set.BestViableFunction(sema, loc, best_viable_fn);
|
||||
|
||||
switch (overloading_result) {
|
||||
case clang::OverloadingResult::OR_Success: {
|
||||
// TODO: Handle the cases when Function is null.
|
||||
CARBON_CHECK(best_viable_fn->Function);
|
||||
sema.MarkFunctionReferenced(clang::SourceLocation(),
|
||||
best_viable_fn->Function);
|
||||
sema.MarkFunctionReferenced(loc, best_viable_fn->Function);
|
||||
SemIR::InstId result =
|
||||
ImportCppFunctionDecl(context, loc_id, best_viable_fn->Function);
|
||||
return result;
|
||||
}
|
||||
case clang::OverloadingResult::OR_No_Viable_Function: {
|
||||
// TODO: Add notes with the candidates.
|
||||
CARBON_DIAGNOSTIC(CppOverloadingNoViableFunctionFound, Error,
|
||||
"no matching function for call to `{0}`",
|
||||
SemIR::NameId);
|
||||
context.emitter().Emit(loc_id, CppOverloadingNoViableFunctionFound,
|
||||
overload_set.name_id);
|
||||
candidate_set.NoteCandidates(
|
||||
clang::PartialDiagnosticAt(
|
||||
loc, sema.PDiag(clang::diag::err_ovl_no_viable_function_in_call)
|
||||
<< GetCppName(context, overload_set.name_id)),
|
||||
sema, clang::OCD_AllCandidates, arg_exprs);
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
case clang::OverloadingResult::OR_Ambiguous: {
|
||||
// TODO: Add notes with the candidates.
|
||||
CARBON_DIAGNOSTIC(CppOverloadingAmbiguousCandidatesFound, Error,
|
||||
"call to `{0}` is ambiguous", SemIR::NameId);
|
||||
context.emitter().Emit(loc_id, CppOverloadingAmbiguousCandidatesFound,
|
||||
overload_set.name_id);
|
||||
candidate_set.NoteCandidates(
|
||||
clang::PartialDiagnosticAt(
|
||||
loc, sema.PDiag(clang::diag::err_ovl_ambiguous_call)
|
||||
<< GetCppName(context, overload_set.name_id)),
|
||||
sema, clang::OCD_AmbiguousCandidates, arg_exprs);
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
case clang::OverloadingResult::OR_Deleted: {
|
||||
// TODO: Add notes with the candidates.
|
||||
CARBON_DIAGNOSTIC(CppOverloadingDeletedFunctionFound, Error,
|
||||
"call to deleted function `{0}`", SemIR::NameId);
|
||||
context.emitter().Emit(loc_id, CppOverloadingDeletedFunctionFound,
|
||||
overload_set.name_id);
|
||||
sema.DiagnoseUseOfDeletedFunction(
|
||||
loc, clang::SourceRange(loc, loc),
|
||||
GetCppName(context, overload_set.name_id), candidate_set,
|
||||
best_viable_fn->Function, arg_exprs);
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user