[AST][RecoveryExpr] Preserve type for broken overrload member call expr.
authorHaojian Wu <hokein.wu@gmail.com>
Mon, 14 Dec 2020 07:45:13 +0000 (08:45 +0100)
committerHaojian Wu <hokein.wu@gmail.com>
Mon, 14 Dec 2020 07:50:41 +0000 (08:50 +0100)
Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D80109

clang/lib/Sema/SemaOverload.cpp
clang/test/AST/ast-dump-recovery.cpp
clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp

index 5689efe..13d2125 100644 (file)
@@ -14300,6 +14300,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
     UnbridgedCasts.restore();
 
     OverloadCandidateSet::iterator Best;
+    bool Succeeded = false;
     switch (CandidateSet.BestViableFunction(*this, UnresExpr->getBeginLoc(),
                                             Best)) {
     case OR_Success:
@@ -14307,7 +14308,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
       FoundDecl = Best->FoundDecl;
       CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
       if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
-        return ExprError();
+        break;
       // If FoundDecl is different from Method (such as if one is a template
       // and the other a specialization), make sure DiagnoseUseOfDecl is
       // called on both.
@@ -14316,7 +14317,8 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
       // being used.
       if (Method != FoundDecl.getDecl() &&
                       DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc()))
-        return ExprError();
+        break;
+      Succeeded = true;
       break;
 
     case OR_No_Viable_Function:
@@ -14326,27 +14328,25 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
               PDiag(diag::err_ovl_no_viable_member_function_in_call)
                   << DeclName << MemExprE->getSourceRange()),
           *this, OCD_AllCandidates, Args);
-      // FIXME: Leaking incoming expressions!
-      return ExprError();
-
+      break;
     case OR_Ambiguous:
       CandidateSet.NoteCandidates(
           PartialDiagnosticAt(UnresExpr->getMemberLoc(),
                               PDiag(diag::err_ovl_ambiguous_member_call)
                                   << DeclName << MemExprE->getSourceRange()),
           *this, OCD_AmbiguousCandidates, Args);
-      // FIXME: Leaking incoming expressions!
-      return ExprError();
-
+      break;
     case OR_Deleted:
       CandidateSet.NoteCandidates(
           PartialDiagnosticAt(UnresExpr->getMemberLoc(),
                               PDiag(diag::err_ovl_deleted_member_call)
                                   << DeclName << MemExprE->getSourceRange()),
           *this, OCD_AllCandidates, Args);
-      // FIXME: Leaking incoming expressions!
-      return ExprError();
+      break;
     }
+    // Overload resolution fails, try to recover.
+    if (!Succeeded)
+      return BuildRecoveryExpr(chooseRecoveryType(CandidateSet, &Best));
 
     MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method);
 
index 2a8346e..a8da2b8 100644 (file)
@@ -125,6 +125,9 @@ struct Foo2 {
   double func();
   class ForwardClass;
   ForwardClass createFwd();
+
+  int overload();
+  int overload(int, int);
 };
 void test2(Foo2 f) {
   // CHECK:      RecoveryExpr {{.*}} 'double'
@@ -136,6 +139,11 @@ void test2(Foo2 f) {
   // CHECK-NEXT: `-MemberExpr {{.*}} '<bound member function type>' .createFwd
   // CHECK-NEXT:   `-DeclRefExpr {{.*}} 'f'
   f.createFwd();
+  // CHECK:      RecoveryExpr {{.*}} 'int' contains-errors
+  // CHECK-NEXT: |-UnresolvedMemberExpr
+  // CHECK-NEXT:    `-DeclRefExpr {{.*}} 'Foo2'
+  // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1
+  f.overload(1);
 }
 
 // CHECK:     |-AlignedAttr {{.*}} alignas
index ce43720..f12e008 100644 (file)
@@ -9,7 +9,7 @@
 //   parameter types in a base class (rather than conflicting).
 
 template <unsigned n> struct Opaque {};
-template <unsigned n> void expect(Opaque<n> _) {}
+template <unsigned n> void expect(Opaque<n> _) {} // expected-note 4 {{candidate function template not viable}}
 
 // PR5727
 // This just shouldn't crash.
@@ -134,14 +134,14 @@ namespace test3 {
   void test() {
     expect<0>(Base().foo<int>());
     expect<1>(Base().foo<0>());
-    expect<0>(Derived1().foo<int>()); // expected-error {{no matching member function for call to 'foo'}}
+    expect<0>(Derived1().foo<int>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}}
     expect<2>(Derived1().foo<0>());
-    expect<0>(Derived2().foo<int>()); // expected-error {{no matching member function for call to 'foo'}}
+    expect<0>(Derived2().foo<int>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}}
     expect<2>(Derived2().foo<0>());
     expect<3>(Derived3().foo<int>());
-    expect<1>(Derived3().foo<0>()); // expected-error {{no matching member function for call to 'foo'}}
+    expect<1>(Derived3().foo<0>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}}
     expect<3>(Derived4().foo<int>());
-    expect<1>(Derived4().foo<0>()); // expected-error {{no matching member function for call to 'foo'}}
+    expect<1>(Derived4().foo<0>()); // expected-error {{no matching member function for call to 'foo'}} expected-error {{no matching function for call to 'expect'}}
   }
 }