forked from OSchip/llvm-project
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:
parent
a6e2edcc3a
commit
4700099719
|
@ -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<
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue