diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-30 21:46:01 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-30 21:46:01 +0000 |
commit | 3307475eb0dd6e5d88be9392ea8247d0b6b812df (patch) | |
tree | 682b4d57612577b8e8b6890bbddc3d52ec8f83f7 | |
parent | 60a90cc99ac24f9117d376c55d3c699296b23963 (diff) |
When overload resolution fails for an overloaded operator, show the
overload candidates (but not the built-in ones). We still rely on the
underlying built-in semantic analysis to produce the initial
diagnostic, then print the candidates following that diagnostic.
One side advantage of this approach is that we can perform more validation
of C++'s operator overloading with built-in candidates vs. the
semantic analysis for those built-in operators: when there are no
viable candidates, we know to expect an error from the built-in
operator handling code. Otherwise, we are not modeling the built-in
semantics properly within operator overloading. This is checked as:
assert(Result.isInvalid() &&
"C++ binary operator overloading is missing
candidates!");
if (Result.isInvalid())
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
The assert() catches cases where we're wrong in a +Asserts build. The
"if" makes sure that, if this happens in a production clang
(-Asserts), we still build the proper built-in operator and continue
on our merry way. This is effectively what happened before this
change, but we've added the assert() to catch more flies.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83175 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 18 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 34 | ||||
-rw-r--r-- | test/SemaCXX/copy-assignment.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/namespace.cpp | 3 | ||||
-rw-r--r-- | test/SemaCXX/overloaded-builtin-operators.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/overloaded-operator.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/qualified-names-diag.cpp | 2 |
7 files changed, 45 insertions, 22 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2f653b5320..414525d6c3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1599,11 +1599,19 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, } } - case OR_No_Viable_Function: - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. - break; - + case OR_No_Viable_Function: { + // No viable function; try checking this as a built-in operator, which + // will fail and provide a diagnostic. Then, print the overload + // candidates. + OwningExprResult Result = CreateBuiltinUnaryOp(OpLoc, Opc, move(Input)); + assert(Result.isInvalid() && + "C++ postfix-unary operator overloading is missing candidates!"); + if (Result.isInvalid()) + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + + return move(Result); + } + case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) << UnaryOperator::getOpcodeStr(Opc) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index aaf76b1a0e..6966926e9e 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3998,10 +3998,11 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, Diag(Cand->Surrogate->getLocation(), diag::err_ovl_surrogate_cand) << FnType; - } else { + } else if (OnlyViable) { // FIXME: We need to get the identifier in here // FIXME: Do we want the error message to point at the operator? // (built-ins won't have a location) + // FIXME: can we get some kind of stable location for this? QualType FnType = Context.getFunctionType(Cand->BuiltinTypes.ResultTy, Cand->BuiltinTypes.ParamTypes, @@ -4631,19 +4632,34 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } } - case OR_No_Viable_Function: + case OR_No_Viable_Function: { + // C++ [over.match.oper]p9: + // If the operator is the operator , [...] and there are no + // viable functions, then the operator is assumed to be the + // built-in operator and interpreted according to clause 5. + if (Opc == BinaryOperator::Comma) + break; + // For class as left operand for assignment or compound assigment operator // do not fall through to handling in built-in, but report that no overloaded // assignment operator found - if (Args[0]->getType()->isRecordType() && Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) { + OwningExprResult Result = ExprError(); + if (Args[0]->getType()->isRecordType() && + Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - return ExprError(); + } else { + // No viable function; try to create a built-in operation, which will + // produce an error. Then, show the non-viable candidates. + Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. - break; + assert(Result.isInvalid() && + "C++ binary operator overloading is missing candidates!"); + if (Result.isInvalid()) + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + return move(Result); + } case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) @@ -4661,9 +4677,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return ExprError(); } - // Either we found no viable overloaded operator or we matched a - // built-in operator. In either case, try to build a built-in - // operation. + // We matched a built-in operator; build it. return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } diff --git a/test/SemaCXX/copy-assignment.cpp b/test/SemaCXX/copy-assignment.cpp index 6e5012f5a7..413e4d1933 100644 --- a/test/SemaCXX/copy-assignment.cpp +++ b/test/SemaCXX/copy-assignment.cpp @@ -11,7 +11,7 @@ struct ConvertibleToConstA { }; struct B { - B& operator=(B&); + B& operator=(B&); // expected-note 4 {{candidate function}} }; struct ConvertibleToB { diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp index 696ea818f6..ae8dfc5813 100644 --- a/test/SemaCXX/namespace.cpp +++ b/test/SemaCXX/namespace.cpp @@ -8,7 +8,8 @@ void f() { A = 0; } // expected-error {{unexpected namespace name 'A': expected int A; // expected-error {{redefinition of 'A' as different kind of symbol}} class A; // expected-error {{redefinition of 'A' as different kind of symbol}} -class B {}; // expected-note {{previous definition is here}} +class B {}; // expected-note {{previous definition is here}} \ + // FIXME: ugly expected-note{{candidate function}} void C(); // expected-note {{previous definition is here}} namespace C {} // expected-error {{redefinition of 'C' as different kind of symbol}} diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp index a8c94f1822..0284b2929b 100644 --- a/test/SemaCXX/overloaded-builtin-operators.cpp +++ b/test/SemaCXX/overloaded-builtin-operators.cpp @@ -59,7 +59,7 @@ void f(Short s, Long l, Enum1 e1, Enum2 e2, Xpmf pmf) { // FIXME: should pass (void)static_cast<no&>(islong(e1 % e2)); } -struct ShortRef { +struct ShortRef { // expected-note{{candidate function}} operator short&(); }; @@ -67,7 +67,7 @@ struct LongRef { operator volatile long&(); }; -struct XpmfRef { +struct XpmfRef { // expected-note{{candidate function}} operator pmf&(); }; diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp index 8471f3c936..8f71ad5381 100644 --- a/test/SemaCXX/overloaded-operator.cpp +++ b/test/SemaCXX/overloaded-operator.cpp @@ -28,12 +28,12 @@ void g(Y y, Z z) { } struct A { - bool operator==(Z&); // expected-note{{candidate function}} + bool operator==(Z&); // expected-note 2{{candidate function}} }; A make_A(); -bool operator==(A&, Z&); // expected-note{{candidate function}} +bool operator==(A&, Z&); // expected-note 2{{candidate function}} void h(A a, const A ac, Z z) { make_A() == z; diff --git a/test/SemaTemplate/qualified-names-diag.cpp b/test/SemaTemplate/qualified-names-diag.cpp index c875332905..1d53e5cb98 100644 --- a/test/SemaTemplate/qualified-names-diag.cpp +++ b/test/SemaTemplate/qualified-names-diag.cpp @@ -1,7 +1,7 @@ // RUN: clang-cc -fsyntax-only -verify %s namespace std { - template<typename T> class vector { }; + template<typename T> class vector { }; // expected-note{{candidate}} } typedef int INT; |