Improve overload diagnostics some more by calling out qualifier mismatches

for special diagnostics.  Unfortunately, the non-overload diagnostics are not
this good.

llvm-svn: 93420
This commit is contained in:
John McCall 2010-01-14 03:28:57 +00:00
parent a6e2edcc3a
commit 4700099719
3 changed files with 86 additions and 5 deletions

View File

@ -925,6 +925,30 @@ def note_ovl_candidate_bad_conv : Note<"candidate "
"function (the implicit copy assignment operator)}0%1"
" not viable: no known conversion from %2 to %3 for "
"%select{%ordinal5 argument|object argument}4">;
def note_ovl_candidate_bad_addrspace : Note<"candidate "
"%select{function|function|constructor|"
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
"function (the implicit copy assignment operator)}0%1 not viable: "
"%select{%ordinal6|'this'}5 argument (%2) is in "
"address space %3, but parameter must be in address space %4">;
def note_ovl_candidate_bad_cvr_this : Note<"candidate "
"%select{|function|||function||||"
"function (the implicit copy assignment operator)}0 not viable: "
"'this' argument has type %2, but method is not marked "
"%select{const|volatile|const or volatile|restrict|const or restrict|"
"volatile or restrict|const, volatile, or restrict}3">;
def note_ovl_candidate_bad_cvr : Note<"candidate "
"%select{function|function|constructor|"
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
"function (the implicit copy assignment operator)}0%1 not viable: "
"%ordinal4 argument (%2) would lose "
"%select{const|volatile|const and volatile|restrict|const and restrict|"
"volatile and restrict|const, volatile, and restrict}3 qualifier"
"%select{||s||s|s|s}3">;
def note_ambiguous_type_conversion: Note<
"because of ambiguity in conversion of %0 to %1">;
def note_ovl_builtin_binary_candidate : Note<

View File

@ -2191,7 +2191,7 @@ bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
/// parameter of the given member function (@c Method) from the
/// expression @p From.
ImplicitConversionSequence
Sema::TryObjectArgumentInitialization(QualType FromType,
Sema::TryObjectArgumentInitialization(QualType OrigFromType,
CXXMethodDecl *Method,
CXXRecordDecl *ActingContext) {
QualType ClassType = Context.getTypeDeclType(ActingContext);
@ -2208,6 +2208,7 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
ICS.setBad();
// We need to have an object of class type.
QualType FromType = OrigFromType;
if (const PointerType *PT = FromType->getAs<PointerType>())
FromType = PT->getPointeeType();
@ -2228,7 +2229,8 @@ Sema::TryObjectArgumentInitialization(QualType FromType,
if (ImplicitParamType.getCVRQualifiers()
!= FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
ICS.Bad.init(BadConversionSequence::bad_qualifiers, FromType, ImplicitParamType);
ICS.Bad.init(BadConversionSequence::bad_qualifiers,
OrigFromType, ImplicitParamType);
return ICS;
}
@ -4384,7 +4386,57 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
QualType FromTy = Conv.Bad.getFromType();
QualType ToTy = Conv.Bad.getToType();
// TODO: specialize based on the kind of mismatch
// Do some hand-waving analysis to see if the non-viability is due to a
CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
CanQualType CToTy = S.Context.getCanonicalType(ToTy);
if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>())
CToTy = RT->getPointeeType();
else {
// TODO: detect and diagnose the full richness of const mismatches.
if (CanQual<PointerType> FromPT = CFromTy->getAs<PointerType>())
if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>())
CFromTy = FromPT->getPointeeType(), CToTy = ToPT->getPointeeType();
}
if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
!CToTy.isAtLeastAsQualifiedAs(CFromTy)) {
// It is dumb that we have to do this here.
while (isa<ArrayType>(CFromTy))
CFromTy = CFromTy->getAs<ArrayType>()->getElementType();
while (isa<ArrayType>(CToTy))
CToTy = CFromTy->getAs<ArrayType>()->getElementType();
Qualifiers FromQs = CFromTy.getQualifiers();
Qualifiers ToQs = CToTy.getQualifiers();
if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace)
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy
<< FromQs.getAddressSpace() << ToQs.getAddressSpace()
<< (unsigned) isObjectArgument << I+1;
return;
}
unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers();
assert(CVR && "unexpected qualifiers mismatch");
if (isObjectArgument) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr_this)
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << (CVR - 1);
} else {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_cvr)
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << (CVR - 1) << I+1;
}
return;
}
// TODO: specialize more based on the kind of mismatch
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())

View File

@ -78,8 +78,11 @@ namespace test1 {
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 bar(double d); //expected-note {{candidate function not viable: no known conversion from 'class test1::A const' to 'class test1::A' for object argument}}
void bar(int i); //expected-note {{candidate function not viable: no known conversion from 'class test1::A const' to 'class test1::A' for object argument}}
void bar(double d); //expected-note {{candidate function not viable: 'this' argument has type 'class test1::A const', but method is not marked const}}
void bar(int i); //expected-note {{candidate function not viable: 'this' argument has type 'class test1::A const', but method is not marked const}}
void baz(A &d); // expected-note {{candidate function not viable: 1st argument ('class test1::A const') would lose const qualifier}}
void baz(int i); // expected-note {{candidate function not viable: no known conversion from 'class test1::A const' to 'int' for 1st argument}}
};
void test() {
@ -88,6 +91,8 @@ namespace test1 {
const A b;
b.bar(0); //expected-error {{no matching member function for call to 'bar'}}
a.baz(b); //expected-error {{no matching member function for call to 'baz'}}
}
}