Skip to content

Commit

Permalink
SemaOverload: Complete candidates before emitting the error, to ensur…
Browse files Browse the repository at this point in the history
…e diagnostics emitted (or suppressed) during completion don't interfere with the overload notes

Because diagnostics and their notes are not connected at the API level,
if the error message for an overload is emitted, then the overload
candidates are completed - if a diagnostic is emitted during that work,
the notes related to overload candidates would be attached to the latter
diagnostic, not the original error. Sort of worse, if the latter
diagnostic was disabled, the notes are disabled.

Reviewers: rsmith

Differential Revision: https://reviews.llvm.org/D61357

llvm-svn: 359854
  • Loading branch information
dwblaikie committed May 3, 2019
1 parent d45df09 commit 5e32805
Show file tree
Hide file tree
Showing 10 changed files with 338 additions and 179 deletions.
3 changes: 3 additions & 0 deletions clang/include/clang/AST/TemplateName.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class NamedDecl;
class NestedNameSpecifier;
enum OverloadedOperatorKind : int;
class OverloadedTemplateStorage;
class PartialDiagnostic;
struct PrintingPolicy;
class QualifiedTemplateName;
class SubstTemplateTemplateParmPackStorage;
Expand Down Expand Up @@ -319,6 +320,8 @@ class TemplateName {
/// into a diagnostic with <<.
const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
TemplateName N);
const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
TemplateName N);

/// A structure for storing the information associated with a
/// substituted template template parameter.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/PartialDiagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define LLVM_CLANG_BASIC_PARTIALDIAGNOSTIC_H

#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/SmallVector.h"
Expand Down
22 changes: 16 additions & 6 deletions clang/include/clang/Sema/Overload.h
Original file line number Diff line number Diff line change
Expand Up @@ -961,13 +961,23 @@ class Sema;
OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
OverloadCandidateSet::iterator& Best);

void NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
ArrayRef<Expr *> Args,
SmallVector<OverloadCandidate *, 32> CompleteCandidates(
Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args,
SourceLocation OpLoc = SourceLocation(),
llvm::function_ref<bool(OverloadCandidate &)> Filter =
[](OverloadCandidate &) { return true; });

void NoteCandidates(
PartialDiagnosticAt PA, Sema &S, OverloadCandidateDisplayKind OCD,
ArrayRef<Expr *> Args, StringRef Opc = "",
SourceLocation Loc = SourceLocation(),
llvm::function_ref<bool(OverloadCandidate &)> Filter =
[](OverloadCandidate &) { return true; });

void NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
ArrayRef<OverloadCandidate *> Cands,
StringRef Opc = "",
SourceLocation Loc = SourceLocation(),
llvm::function_ref<bool(OverloadCandidate&)> Filter =
[](OverloadCandidate&) { return true; });
SourceLocation OpLoc = SourceLocation());
};

bool isBetterOverloadCandidate(Sema &S,
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/TemplateName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,20 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << NameStr;
}

const PartialDiagnostic&clang::operator<<(const PartialDiagnostic &PD,
TemplateName N) {
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
OS << '\'';
N.print(OS, PrintingPolicy(LO));
OS << '\'';
OS.flush();
return PD << NameStr;
}

void TemplateName::dump(raw_ostream &OS) const {
LangOptions LO; // FIXME!
LO.CPlusPlus = true;
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Sema/SemaCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,11 +399,11 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
break;
}

S.Diag(range.getBegin(), msg)
<< CT << srcType << destType
<< range << src->getSourceRange();

candidates.NoteCandidates(S, howManyCandidates, src);
candidates.NoteCandidates(
PartialDiagnosticAt(range.getBegin(),
S.PDiag(msg) << CT << srcType << destType << range
<< src->getSourceRange()),
S, howManyCandidates, src);

return true;
}
Expand Down
49 changes: 29 additions & 20 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2301,8 +2301,8 @@ static bool resolveAllocationOverload(
}

if (Diagnose) {
S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
<< R.getLookupName() << Range;
PartialDiagnosticAt PD(R.getNameLoc(), S.PDiag(diag::err_ovl_no_viable_function_in_call)
<< R.getLookupName() << Range);

// If we have aligned candidates, only note the align_val_t candidates
// from AlignedCandidates and the non-align_val_t candidates from
Expand All @@ -2317,30 +2317,34 @@ static bool resolveAllocationOverload(
// This was an overaligned allocation, so list the aligned candidates
// first.
Args.insert(Args.begin() + 1, AlignArg);
AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "",
AlignedCandidates->NoteCandidates(PD, S, OCD_AllCandidates, Args, "",
R.getNameLoc(), IsAligned);
Args.erase(Args.begin() + 1);
Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(),
Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args, "", R.getNameLoc(),
IsUnaligned);
} else {
Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
Candidates.NoteCandidates(PD, S, OCD_AllCandidates, Args);
}
}
return true;

case OR_Ambiguous:
if (Diagnose) {
S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range;
Candidates.NoteCandidates(S, OCD_ViableCandidates, Args);
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
S, OCD_ViableCandidates, Args);
}
return true;

case OR_Deleted: {
if (Diagnose) {
S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call)
<< R.getLookupName() << Range;
Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_deleted_call)
<< R.getLookupName() << Range),
S, OCD_AllCandidates, Args);
}
return true;
}
Expand Down Expand Up @@ -3504,21 +3508,26 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall,
}

case OR_No_Viable_Function:
S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
<< R.getLookupName() << Range;
Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_no_viable_function_in_call)
<< R.getLookupName() << Range),
S, OCD_AllCandidates, Args);
return true;

case OR_Ambiguous:
S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range;
Candidates.NoteCandidates(S, OCD_ViableCandidates, Args);
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(),
S.PDiag(diag::err_ovl_ambiguous_call)
<< R.getLookupName() << Range),
S, OCD_ViableCandidates, Args);
return true;

case OR_Deleted: {
S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call)
<< R.getLookupName() << Range;
Candidates.NoteCandidates(S, OCD_AllCandidates, Args);
Candidates.NoteCandidates(
PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call)
<< R.getLookupName() << Range),
S, OCD_AllCandidates, Args);
return true;
}
}
Expand Down
97 changes: 57 additions & 40 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5971,21 +5971,25 @@ static ExprResult CopyObject(Sema &S,
break;

case OR_No_Viable_Function:
S.Diag(Loc, IsExtraneousCopy && !S.isSFINAEContext()
? diag::ext_rvalue_to_reference_temp_copy_no_viable
: diag::err_temp_copy_no_viable)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
CandidateSet.NoteCandidates(
PartialDiagnosticAt(
Loc, S.PDiag(IsExtraneousCopy && !S.isSFINAEContext()
? diag::ext_rvalue_to_reference_temp_copy_no_viable
: diag::err_temp_copy_no_viable)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange()),
S, OCD_AllCandidates, CurInitExpr);
if (!IsExtraneousCopy || S.isSFINAEContext())
return ExprError();
return CurInit;

case OR_Ambiguous:
S.Diag(Loc, diag::err_temp_copy_ambiguous)
<< (int)Entity.getKind() << CurInitExpr->getType()
<< CurInitExpr->getSourceRange();
CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr);
CandidateSet.NoteCandidates(
PartialDiagnosticAt(Loc, S.PDiag(diag::err_temp_copy_ambiguous)
<< (int)Entity.getKind()
<< CurInitExpr->getType()
<< CurInitExpr->getSourceRange()),
S, OCD_ViableCandidates, CurInitExpr);
return ExprError();

case OR_Deleted:
Expand Down Expand Up @@ -6120,13 +6124,13 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
break;

case OR_No_Viable_Function:
S.Diag(Loc, Diag);
CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr);
CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
OCD_AllCandidates, CurInitExpr);
break;

case OR_Ambiguous:
S.Diag(Loc, Diag);
CandidateSet.NoteCandidates(S, OCD_ViableCandidates, CurInitExpr);
CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S,
OCD_ViableCandidates, CurInitExpr);
break;

case OR_Deleted:
Expand Down Expand Up @@ -8399,19 +8403,22 @@ bool InitializationSequence::Diagnose(Sema &S,
case FK_UserConversionOverloadFailed:
switch (FailedOverloadResult) {
case OR_Ambiguous:
if (Failure == FK_UserConversionOverloadFailed)
S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
<< OnlyArg->getType() << DestType
<< Args[0]->getSourceRange();
else
S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous)
<< DestType << OnlyArg->getType()
<< Args[0]->getSourceRange();

FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args);
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
Failure == FK_UserConversionOverloadFailed
? (S.PDiag(diag::err_typecheck_ambiguous_condition)
<< OnlyArg->getType() << DestType
<< Args[0]->getSourceRange())
: (S.PDiag(diag::err_ref_init_ambiguous)
<< DestType << OnlyArg->getType()
<< Args[0]->getSourceRange())),
S, OCD_ViableCandidates, Args);
break;

case OR_No_Viable_Function:
case OR_No_Viable_Function: {
auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args);
if (!S.RequireCompleteType(Kind.getLocation(),
DestType.getNonReferenceType(),
diag::err_typecheck_nonviable_condition_incomplete,
Expand All @@ -8421,9 +8428,9 @@ bool InitializationSequence::Diagnose(Sema &S,
<< OnlyArg->getType() << Args[0]->getSourceRange()
<< DestType.getNonReferenceType();

FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args);
FailedCandidateSet.NoteCandidates(S, Args, Cands);
break;

}
case OR_Deleted: {
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
<< OnlyArg->getType() << DestType.getNonReferenceType()
Expand Down Expand Up @@ -8587,9 +8594,11 @@ bool InitializationSequence::Diagnose(Sema &S,
// bad.
switch (FailedOverloadResult) {
case OR_Ambiguous:
S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange;
FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args);
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(Kind.getLocation(),
S.PDiag(diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange),
S, OCD_ViableCandidates, Args);
break;

case OR_No_Viable_Function:
Expand Down Expand Up @@ -8638,9 +8647,12 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}

S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange;
FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args);
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
S.PDiag(diag::err_ovl_no_viable_function_in_init)
<< DestType << ArgsRange),
S, OCD_AllCandidates, Args);
break;

case OR_Deleted: {
Expand Down Expand Up @@ -9438,24 +9450,29 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(

switch (Result) {
case OR_Ambiguous:
Diag(Kind.getLocation(), diag::err_deduced_class_template_ctor_ambiguous)
<< TemplateName;
// FIXME: For list-initialization candidates, it'd usually be better to
// list why they were not viable when given the initializer list itself as
// an argument.
Candidates.NoteCandidates(*this, OCD_ViableCandidates, Inits);
Candidates.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
PDiag(diag::err_deduced_class_template_ctor_ambiguous)
<< TemplateName),
*this, OCD_ViableCandidates, Inits);
return QualType();

case OR_No_Viable_Function: {
CXXRecordDecl *Primary =
cast<ClassTemplateDecl>(Template)->getTemplatedDecl();
bool Complete =
isCompleteType(Kind.getLocation(), Context.getTypeDeclType(Primary));
Diag(Kind.getLocation(),
Complete ? diag::err_deduced_class_template_ctor_no_viable
: diag::err_deduced_class_template_incomplete)
<< TemplateName << !Guides.empty();
Candidates.NoteCandidates(*this, OCD_AllCandidates, Inits);
Candidates.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
PDiag(Complete ? diag::err_deduced_class_template_ctor_no_viable
: diag::err_deduced_class_template_incomplete)
<< TemplateName << !Guides.empty()),
*this, OCD_AllCandidates, Inits);
return QualType();
}

Expand Down
Loading

0 comments on commit 5e32805

Please sign in to comment.