[cfe-commits] r83175 - in /cfe/trunk: lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/copy-assignment.cpp test/SemaCXX/namespace.cpp test/SemaCXX/overloaded-builtin-operators.cpp test/SemaCXX/overloaded-operator.cpp test/SemaTemplate/qualified-names-diag.cpp

Douglas Gregor dgregor at apple.com
Wed Sep 30 14:46:02 PDT 2009


Author: dgregor
Date: Wed Sep 30 16:46:01 2009
New Revision: 83175

URL: http://llvm.org/viewvc/llvm-project?rev=83175&view=rev
Log:
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.


Modified:
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/copy-assignment.cpp
    cfe/trunk/test/SemaCXX/namespace.cpp
    cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp
    cfe/trunk/test/SemaCXX/overloaded-operator.cpp
    cfe/trunk/test/SemaTemplate/qualified-names-diag.cpp

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=83175&r1=83174&r2=83175&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Sep 30 16:46:01 2009
@@ -1599,11 +1599,19 @@
       }
     }
 
-    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)

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=83175&r1=83174&r2=83175&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Sep 30 16:46:01 2009
@@ -3998,10 +3998,11 @@
 
         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 @@
       }
     }
 
-    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 @@
       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]);
 }
 

Modified: cfe/trunk/test/SemaCXX/copy-assignment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/copy-assignment.cpp?rev=83175&r1=83174&r2=83175&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/copy-assignment.cpp (original)
+++ cfe/trunk/test/SemaCXX/copy-assignment.cpp Wed Sep 30 16:46:01 2009
@@ -11,7 +11,7 @@
 };
 
 struct B {
-  B& operator=(B&);
+  B& operator=(B&);  // expected-note 4 {{candidate function}}
 };
 
 struct ConvertibleToB {

Modified: cfe/trunk/test/SemaCXX/namespace.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/namespace.cpp?rev=83175&r1=83174&r2=83175&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/namespace.cpp (original)
+++ cfe/trunk/test/SemaCXX/namespace.cpp Wed Sep 30 16:46:01 2009
@@ -8,7 +8,8 @@
 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}}

Modified: cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp?rev=83175&r1=83174&r2=83175&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp Wed Sep 30 16:46:01 2009
@@ -59,7 +59,7 @@
   // FIXME: should pass (void)static_cast<no&>(islong(e1 % e2));
 }
 
-struct ShortRef {
+struct ShortRef { // expected-note{{candidate function}}
   operator short&();
 };
 
@@ -67,7 +67,7 @@
   operator volatile long&();
 };
 
-struct XpmfRef {
+struct XpmfRef { // expected-note{{candidate function}}
   operator pmf&();
 };
 

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=83175&r1=83174&r2=83175&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Wed Sep 30 16:46:01 2009
@@ -28,12 +28,12 @@
 }
 
 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;

Modified: cfe/trunk/test/SemaTemplate/qualified-names-diag.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/qualified-names-diag.cpp?rev=83175&r1=83174&r2=83175&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/qualified-names-diag.cpp (original)
+++ cfe/trunk/test/SemaTemplate/qualified-names-diag.cpp Wed Sep 30 16:46:01 2009
@@ -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;





More information about the cfe-commits mailing list