Record some basic information about bad conversion sequences. Use that

information to feed diagnostics instead of regenerating it.  Much room for
improvement here, but fixes some unfortunate problems reporting on method calls.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93316 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2010-01-13 09:16:55 +00:00
Родитель a6c058dd75
Коммит adbb8f8aa4
6 изменённых файлов: 184 добавлений и 65 удалений

Просмотреть файл

@ -4389,7 +4389,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase);
// Most paths end in a failed conversion.
if (ICS) ICS->setBad();
if (ICS) {
ICS->setBad();
ICS->Bad.init(BadConversionSequence::no_conversion, Init, DeclType);
}
// C++ [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression

Просмотреть файл

@ -1076,6 +1076,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
bool Elidable,
ImplicitConversionSequence& ICS) {
ICS.setBad();
ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
if (Elidable && getLangOptions().CPlusPlus0x) {
ICS = TryImplicitConversion(From, ToType,
/*SuppressUserConversions=*/false,
@ -1942,7 +1943,7 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
ImplicitConversionSequence E1ToC2, E2ToC2;
E1ToC2.setBad();
E2ToC2.setBad();
E2ToC2.setBad();
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
E1ToC2 = TryImplicitConversion(E1, Composite2,

Просмотреть файл

@ -489,8 +489,10 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
// of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
// 13.3.1.6 in all cases, only standard conversion sequences and
// ellipsis conversion sequences are allowed.
if (SuppressUserConversions && ICS.isUserDefined())
if (SuppressUserConversions && ICS.isUserDefined()) {
ICS.setBad();
ICS.Bad.init(BadConversionSequence::suppressed_user, From, ToType);
}
} else if (UserDefResult == OR_Ambiguous) {
ICS.setAmbiguous();
ICS.Ambiguous.setFromType(From->getType());
@ -501,6 +503,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType,
ICS.Ambiguous.addConversion(Cand->Function);
} else {
ICS.setBad();
ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
}
return ICS;
@ -2129,6 +2132,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType,
bool InOverloadResolution) {
if (ToType->isReferenceType()) {
ImplicitConversionSequence ICS;
ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
CheckReferenceInit(From, ToType,
/*FIXME:*/From->getLocStart(),
SuppressUserConversions,
@ -2223,8 +2227,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
QualType FromTypeCanon = Context.getCanonicalType(FromType);
if (ImplicitParamType.getCVRQualifiers()
!= FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon))
!ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
ICS.Bad.init(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType);
return ICS;
}
// Check that we have either the same type or a derived type. It
// affects the conversion rank.
@ -2233,8 +2239,10 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
ICS.Standard.Second = ICK_Identity;
else if (IsDerivedFrom(FromType, ClassType))
ICS.Standard.Second = ICK_Derived_To_Base;
else
else {
ICS.Bad.init(BadConversionSequence::unrelated_class, FromType, ImplicitParamType);
return ICS;
}
// Success. Mark this as a reference binding.
ICS.setStandard();
@ -2385,6 +2393,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto &&
!Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@ -2397,6 +2406,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (NumArgs < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@ -2416,6 +2426,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
@ -2532,6 +2543,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@ -2544,6 +2556,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
if (NumArgs < MinRequiredArgs) {
// Not enough arguments.
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@ -2560,6 +2573,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
= TryObjectArgumentInitialization(ObjectType, Method, ActingContext);
if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
}
@ -2579,6 +2593,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, CXXRecordDecl *ActingContext,
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
@ -2670,6 +2685,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
OverloadCandidate &Candidate = CandidateSet.back();
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
return;
@ -2726,6 +2742,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.Conversions[0].Standard.Second = ICK_Identity;
if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
@ -2737,6 +2754,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
@ -2774,6 +2792,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
break;
default:
@ -2847,6 +2866,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
= TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext);
if (ObjectInit.isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
@ -2869,6 +2889,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
@ -2877,6 +2898,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
if (NumArgs < NumArgsInProto) {
// Not enough arguments.
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
@ -2896,6 +2918,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
/*InOverloadResolution=*/false);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
@ -3038,6 +3061,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
}
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
}
@ -4336,36 +4360,69 @@ void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS,
namespace {
void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I,
Expr **Args, unsigned NumArgs) {
void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
const ImplicitConversionSequence &Conv = Cand->Conversions[I];
assert(Conv.isBad());
assert(Cand->Function && "for now, candidate must be a function");
FunctionDecl *Fn = Cand->Function;
// There's a conversion slot for the object argument if this is a
// non-constructor method. Note that 'I' corresponds the
// conversion-slot index.
bool isObjectArgument = false;
if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn)) {
// FIXME: talk usefully about bad conversions for object arguments.
if (I == 0) return S.NoteOverloadCandidate(Fn);
else I--;
if (I == 0)
isObjectArgument = true;
else
I--;
}
// FIXME: can we have a bad conversion on an ellipsis parameter?
assert(I < NumArgs && "index exceeds number of formal arguments");
assert(I < Fn->getType()->getAs<FunctionProtoType>()->getNumArgs() &&
"index exceeds number of formal parameters");
std::string FnDesc;
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
QualType FromTy = Args[I]->getType();
QualType ToTy = Fn->getType()->getAs<FunctionProtoType>()->getArgType(I);
Expr *FromExpr = Conv.Bad.FromExpr;
QualType FromTy = Conv.Bad.getFromType();
QualType ToTy = Conv.Bad.getToType();
// TODO: specialize based on the kind of mismatch
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
<< (unsigned) FnKind << FnDesc
<< Args[I]->getSourceRange() << FromTy << ToTy
<< I+1;
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << I+1;
}
void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumFormalArgs) {
// TODO: treat calls to a missing default constructor as a special case
FunctionDecl *Fn = Cand->Function;
const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredArguments();
// at least / at most / exactly
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
assert(Cand->FailureKind == ovl_fail_too_few_arguments);
if (MinParams != FnTy->getNumArgs() || FnTy->isVariadic())
mode = 0; // "at least"
else
mode = 2; // "exactly"
modeCount = MinParams;
} else {
assert(Cand->FailureKind == ovl_fail_too_many_arguments);
if (MinParams != FnTy->getNumArgs())
mode = 1; // "at most"
else
mode = 2; // "exactly"
modeCount = FnTy->getNumArgs();
}
std::string Description;
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
<< (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
}
void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
@ -4388,52 +4445,24 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
// Diagnose arity mismatches.
// TODO: treat calls to a missing default constructor as a special case
unsigned NumFormalArgs = NumArgs;
if (isa<CXXMethodDecl>(Fn) && !isa<CXXConstructorDecl>(Fn))
NumFormalArgs--;
const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>();
unsigned MinParams = Fn->getMinRequiredArguments();
if (NumFormalArgs < MinParams ||
(NumFormalArgs > FnTy->getNumArgs() && !FnTy->isVariadic())) {
std::string Description;
OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
switch (Cand->FailureKind) {
case ovl_fail_too_many_arguments:
case ovl_fail_too_few_arguments:
return DiagnoseArityMismatch(S, Cand, NumArgs);
// at least / at most / exactly
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
if (MinParams != FnTy->getNumArgs())
mode = 0; // "at least"
else
mode = 2; // "exactly"
modeCount = MinParams;
} else {
if (MinParams != FnTy->getNumArgs())
mode = 1; // "at most"
else
mode = 2; // "exactly"
modeCount = FnTy->getNumArgs();
}
case ovl_fail_bad_deduction:
return S.NoteOverloadCandidate(Fn);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
<< (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
return;
case ovl_fail_bad_conversion:
for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I)
if (Cand->Conversions[I].isBad())
return DiagnoseBadConversion(S, Cand, I);
// FIXME: this currently happens when we're called from SemaInit
// when user-conversion overload fails. Figure out how to handle
// those conditions and diagnose them well.
return S.NoteOverloadCandidate(Fn);
}
// Look for bad conversions.
if (!Cand->Conversions.empty()) {
for (unsigned I = 0, N = Cand->Conversions.size(); I != N; ++I) {
if (!Cand->Conversions[I].isBad())
continue;
DiagnoseBadConversion(S, Cand, I, Args, NumArgs);
return;
}
}
// Give up and give the generic message.
S.NoteOverloadCandidate(Fn);
}
void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {

Просмотреть файл

@ -16,6 +16,7 @@
#define LLVM_CLANG_SEMA_OVERLOAD_H
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@ -241,6 +242,51 @@ namespace clang {
void copyFrom(const AmbiguousConversionSequence &);
};
/// BadConversionSequence - Records information about an invalid
/// conversion sequence.
struct BadConversionSequence {
enum FailureKind {
no_conversion,
unrelated_class,
suppressed_user,
bad_qualifiers
};
// This can be null, e.g. for implicit object arguments.
Expr *FromExpr;
FailureKind Kind;
private:
// The type we're converting from (an opaque QualType).
void *FromTy;
// The type we're converting to (an opaque QualType).
void *ToTy;
public:
void init(FailureKind K, Expr *From, QualType To) {
init(K, From->getType(), To);
FromExpr = From;
}
void init(FailureKind K, QualType From, QualType To) {
Kind = K;
FromExpr = 0;
setFromType(From);
setToType(To);
}
QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); }
QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); }
void setFromExpr(Expr *E) {
FromExpr = E;
setFromType(E->getType());
}
void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); }
void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); }
};
/// ImplicitConversionSequence - Represents an implicit conversion
/// sequence, which may be a standard conversion sequence
/// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2),
@ -280,6 +326,10 @@ namespace clang {
/// When ConversionKind == AmbiguousConversion, provides the
/// details of the ambiguous conversion.
AmbiguousConversionSequence Ambiguous;
/// When ConversionKind == BadConversion, provides the details
/// of the bad conversion.
BadConversionSequence Bad;
};
ImplicitConversionSequence() : ConversionKind(BadConversion) {}
@ -294,7 +344,7 @@ namespace clang {
case UserDefinedConversion: UserDefined = Other.UserDefined; break;
case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break;
case EllipsisConversion: break;
case BadConversion: break;
case BadConversion: Bad = Other.Bad; break;
}
}
@ -336,6 +386,13 @@ namespace clang {
void DebugPrint() const;
};
enum OverloadFailureKind {
ovl_fail_too_many_arguments,
ovl_fail_too_few_arguments,
ovl_fail_bad_conversion,
ovl_fail_bad_deduction
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
struct OverloadCandidate {
/// Function - The actual function that this candidate
@ -376,6 +433,10 @@ namespace clang {
/// object argument.
bool IgnoreObjectArgument;
/// FailureKind - The reason why this candidate is not viable.
/// Actually an OverloadFailureKind.
unsigned char FailureKind;
/// FinalConversion - For a conversion function (where Function is
/// a CXXConversionDecl), the standard conversion that occurs
/// after the call to the overload candidate to convert the result

Просмотреть файл

@ -304,10 +304,16 @@ namespace PR5756 {
// Tests the exact text used to note the candidates
namespace test1 {
template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int]}}
void foo(int n, char N); // expected-note {{candidate function}}
template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'char const [6]' to 'unsigned int' for argument 2}}
void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'char const [6]' to 'char' for argument 2}}
void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}}
void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}}
void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
void test() {
foo(4, "hello"); //expected-error {{no matching function for call to 'foo'}}
}
}

Просмотреть файл

@ -66,3 +66,22 @@ void test_X2(X2 *x2p, const X2 *cx2p) {
int &ir = x2p->member();
float &fr = cx2p->member();
}
// Tests the exact text used to note the candidates
namespace test1 {
class A {
template <class T> void foo(T t, unsigned N); // expected-note {{candidate function [with T = int] not viable: no known conversion from 'char const [6]' to 'unsigned int' for argument 2}}
void foo(int n, char N); // expected-note {{candidate function not viable: no known conversion from 'char const [6]' to 'char' for argument 2}}
void foo(int n); // expected-note {{candidate function not viable: requires 1 argument, but 2 were provided}}
void foo(unsigned n = 10); // expected-note {{candidate function not viable: requires at most 1 argument, but 2 were provided}}
void foo(int n, const char *s, int t); // expected-note {{candidate function not viable: requires 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, ...); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
void foo(int n, const char *s, int t, int u = 0); // expected-note {{candidate function not viable: requires at least 3 arguments, but 2 were provided}}
};
void test() {
A a;
a.foo(4, "hello"); //expected-error {{no matching member function for call to 'foo'}}
}
}