From: Fariborz Jahanian Date: Mon, 12 Oct 2009 17:51:19 +0000 (+0000) Subject: If built-in operators could not be selected because of ambiguity in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=27687cf7f6fea50e592f653549a33f07bf5c0667;p=clang If built-in operators could not be selected because of ambiguity in user-defined type conversions, issue list of ambiguites in addition to the diagnostic. So, clang now issues the following: b.cpp:19:19: error: left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct C1' int i = c1->*pmf; ~~^ b.cpp:19:19: note: because of ambiguity in conversion of 'struct C1' to 'struct E *' b.cpp:5:5: note: candidate function operator E*(); ^ b.cpp:11:5: note: candidate function operator E*(); ^ git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83862 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fe8f5f29a9..b81278f037 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -780,6 +780,8 @@ def err_ovl_deleted_member_call : Error< def err_ovl_candidate : Note<"candidate function">; def err_ovl_candidate_not_viable : Note<"function not viable because" " of ambiguity in conversion of argument %0">; +def note_ambiguous_type_conversion: Note< + "because of ambiguity in conversion of %0 to %1">; def err_ovl_template_candidate : Note< "candidate function template specialization %0">; def err_ovl_candidate_deleted : Note< diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 30ac59e4ca..27d34ef434 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -464,7 +464,8 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, if (UserDefResult == OR_Ambiguous) { for (OverloadCandidateSet::iterator Cand = Conversions.begin(); Cand != Conversions.end(); ++Cand) - ICS.ConversionFunctionSet.push_back(Cand->Function); + if (Cand->Viable) + ICS.ConversionFunctionSet.push_back(Cand->Function); } } @@ -3976,6 +3977,7 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, SourceLocation OpLoc) { OverloadCandidateSet::iterator Cand = CandidateSet.begin(), LastCand = CandidateSet.end(); + bool Reported = false; for (; Cand != LastCand; ++Cand) { if (Cand->Viable || !OnlyViable) { if (Cand->Function) { @@ -4053,6 +4055,33 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, << Cand->BuiltinTypes.ParamTypes[1] << BinaryOperator::getOpcodeStr(Opc); } + else if (!Cand->Viable && !Reported) { + // Non-viability might be due to ambiguous user-defined conversions, + // needed for built-in operators. Report them as well, but only once + // as we have typically many built-in candidates. + assert(Cand->Conversions.size() == 2 && + "builtin-binary-operator-not-binary"); + for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) { + const ImplicitConversionSequence &ICS = Cand->Conversions[ArgIdx]; + if (ICS.ConversionKind != ImplicitConversionSequence::BadConversion || + ICS.ConversionFunctionSet.empty()) + continue; + if (CXXConversionDecl *Func = dyn_cast( + Cand->Conversions[ArgIdx].ConversionFunctionSet[0])) { + QualType FromTy = + QualType( + static_cast(ICS.UserDefined.Before.FromTypePtr),0); + Diag(OpLoc,diag::note_ambiguous_type_conversion) + << FromTy << Func->getConversionType(); + } + for (unsigned j = 0; j < ICS.ConversionFunctionSet.size(); j++) { + FunctionDecl *Func = + Cand->Conversions[ArgIdx].ConversionFunctionSet[j]; + Diag(Func->getLocation(),diag::err_ovl_candidate); + } + } + Reported = true; + } } } } @@ -4704,7 +4733,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, assert(Result.isInvalid() && "C++ binary operator overloading is missing candidates!"); if (Result.isInvalid()) - PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false, Opc, OpLoc); return move(Result); } diff --git a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp index 46c8ae8b6b..27ca6dc778 100644 --- a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp +++ b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp @@ -5,13 +5,13 @@ struct E {}; struct R { operator A*(); - operator E*(); + operator E*(); // expected-note{{candidate function}} }; struct S { operator A*(); - operator E*(); + operator E*(); // expected-note{{candidate function}} }; struct B : R { @@ -41,5 +41,6 @@ void foo1(C1 c1, int A::* pmf) { void foo1(C1 c1, int E::* pmf) { // FIXME. Error reporting needs much improvement here. - int i = c1->*pmf; // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct C1'}} + int i = c1->*pmf; // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct C1'}} \ + // expected-note {{because of ambiguity in conversion of 'struct C1' to 'struct E *'}} } diff --git a/test/SemaCXX/decl-init-ref.cpp b/test/SemaCXX/decl-init-ref.cpp index 9fb3f171d6..d7db647cd1 100644 --- a/test/SemaCXX/decl-init-ref.cpp +++ b/test/SemaCXX/decl-init-ref.cpp @@ -1,6 +1,6 @@ // RUN: clang-cc -fsyntax-only -verify -std=c++0x %s -struct A {}; // expected-note {{candidate function}} +struct A {}; struct BASE { operator A(); // expected-note {{candidate function}}