// 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());
ICS.Ambiguous.addConversion(Cand->Function);
} else {
ICS.setBad();
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
}
return ICS;
bool InOverloadResolution) {
if (ToType->isReferenceType()) {
ImplicitConversionSequence ICS;
+ ICS.Bad.init(BadConversionSequence::no_conversion, From, ToType);
CheckReferenceInit(From, ToType,
/*FIXME:*/From->getLocStart(),
SuppressUserConversions,
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.
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();
if ((NumArgs + (PartialOverloading && NumArgs)) > NumArgsInProto &&
!Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
if (NumArgs < MinRequiredArgs && !PartialOverloading) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
if (NumArgs < MinRequiredArgs) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
= TryObjectArgumentInitialization(ObjectType, Method, ActingContext);
if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
}
/*InOverloadResolution=*/true);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
OverloadCandidate &Candidate = CandidateSet.back();
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_deduction;
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
return;
Candidate.Conversions[0].Standard.Second = ICK_Identity;
if (Candidate.Conversions[0].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
default:
= TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext);
if (ObjectInit.isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
return;
}
// list (8.3.5).
if (NumArgs > NumArgsInProto && !Proto->isVariadic()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_many_arguments;
return;
}
if (NumArgs < NumArgsInProto) {
// Not enough arguments.
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_too_few_arguments;
return;
}
/*InOverloadResolution=*/false);
if (Candidate.Conversions[ArgIdx + 1].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
} else {
}
if (Candidate.Conversions[ArgIdx].isBad()) {
Candidate.Viable = false;
+ Candidate.FailureKind = ovl_fail_bad_conversion;
break;
}
}
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,
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);
-
- // 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();
- }
+ switch (Cand->FailureKind) {
+ case ovl_fail_too_many_arguments:
+ case ovl_fail_too_few_arguments:
+ return DiagnoseArityMismatch(S, Cand, NumArgs);
- S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
- << (unsigned) FnKind << Description << mode << modeCount << NumFormalArgs;
- return;
- }
-
- // 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;
+ case ovl_fail_bad_deduction:
+ return S.NoteOverloadCandidate(Fn);
- DiagnoseBadConversion(S, Cand, I, Args, NumArgs);
- 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);
}
-
- // Give up and give the generic message.
- S.NoteOverloadCandidate(Fn);
}
void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
#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"
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),
/// 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) {}
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;
}
}
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
/// 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