sammccall updated this revision to Diff 199678.
sammccall added a comment.
Herald added a subscriber: arphaman.

This should work for real now: handle types properly, make tests pass, add some 
tests.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61722/new/

https://reviews.llvm.org/D61722

Files:
  include/clang/AST/ASTContext.h
  include/clang/AST/BuiltinTypes.def
  include/clang/AST/Expr.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/AST/TextNodeDumper.h
  include/clang/AST/Type.h
  include/clang/Basic/StmtNodes.td
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/ASTContext.cpp
  lib/AST/Expr.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/AST/NSAPI.cpp
  lib/AST/Stmt.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/AST/TextNodeDumper.cpp
  lib/AST/Type.cpp
  lib/AST/TypeLoc.cpp
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CodeGenTypes.cpp
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/Index/USRGeneration.cpp
  lib/Sema/SemaCast.cpp
  lib/Sema/SemaCoroutine.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExprMember.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/SemaPseudoObject.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTCommon.cpp
  lib/Serialization/ASTReader.cpp
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
  test/CodeCompletion/member-access.cpp
  test/Index/getcursor-recovery.cpp
  test/SemaCXX/constructor-initializer.cpp
  test/SemaCXX/enable_if.cpp
  test/SemaTemplate/dependent-names.cpp
  test/SemaTemplate/instantiate-function-params.cpp
  test/SemaTemplate/instantiate-init.cpp
  tools/libclang/CIndex.cpp
  tools/libclang/CXCursor.cpp

Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -288,6 +288,7 @@
   case Stmt::ObjCDictionaryLiteralClass:
   case Stmt::ObjCBoxedExprClass:
   case Stmt::ObjCSubscriptRefExprClass:
+  case Stmt::RecoveryExprClass:
     K = CXCursor_UnexposedExpr;
     break;
 
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -1516,6 +1516,7 @@
   case BuiltinType::Void:
   case BuiltinType::NullPtr:
   case BuiltinType::Dependent:
+  case BuiltinType::Recovery:
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
   case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
Index: test/SemaTemplate/instantiate-init.cpp
===================================================================
--- test/SemaTemplate/instantiate-init.cpp
+++ test/SemaTemplate/instantiate-init.cpp
@@ -100,9 +100,9 @@
     integral_c<1> ic1 = array_lengthof(Description<int>::data);
     (void)sizeof(array_lengthof(Description<float>::data));
 
-    sizeof(array_lengthof( // expected-error{{no matching function for call to 'array_lengthof'}}
-                          Description<int*>::data // expected-note{{in instantiation of static data member 'PR7985::Description<int *>::data' requested here}}
-                          ));
+    (void)sizeof(array_lengthof( // expected-error{{no matching function for call to 'array_lengthof'}}
+        Description<int *>::data // expected-note{{in instantiation of static data member 'PR7985::Description<int *>::data' requested here}}
+        ));
 
     array_lengthof(Description<float*>::data); // expected-error{{no matching function for call to 'array_lengthof'}}
   }
Index: test/SemaTemplate/instantiate-function-params.cpp
===================================================================
--- test/SemaTemplate/instantiate-function-params.cpp
+++ test/SemaTemplate/instantiate-function-params.cpp
@@ -3,7 +3,7 @@
 // PR6619
 template<bool C> struct if_c { };
 template<typename T1> struct if_ {
-  typedef if_c< static_cast<bool>(T1::value)> almost_type_; // expected-note 5{{in instantiation}}
+  typedef if_c< static_cast<bool>(T1::value)> type; // expected-note 5{{in instantiation}}
 };
 template <class Model, void (Model::*)()> struct wrap_constraints { };
 template <class Model> 
@@ -17,7 +17,9 @@
 template <class ModelFn> struct requirement_;
 template <void(*)()> struct instantiate {
 };
-template <class Model> struct requirement_<void(*)(Model)>                           : if_<       not_satisfied<Model>         >::type { // expected-note 5{{in instantiation}}
+template <class Model>
+struct requirement_<void (*)(Model)> : if_<not_satisfied<Model>>::type { // expected-note 5{{in instantiation}}
+  static void failed();
 };
 template <class Model> struct usage_requirements {
 };
Index: test/SemaTemplate/dependent-names.cpp
===================================================================
--- test/SemaTemplate/dependent-names.cpp
+++ test/SemaTemplate/dependent-names.cpp
@@ -176,7 +176,7 @@
     void f(char&); // expected-note {{candidate function not viable}}
 
     template<typename T> struct C {
-      static const int n = f(T()); // expected-error {{no matching function}}
+      static const int n = f(T()); // expected-error {{no matching function}} expected-error {{variable of type 'const int' with an lvalue of type 'void'}}
     };
   }
 
Index: test/SemaCXX/enable_if.cpp
===================================================================
--- test/SemaCXX/enable_if.cpp
+++ test/SemaCXX/enable_if.cpp
@@ -406,16 +406,16 @@
 static_assert(callNoError<1>() == 0, "");
 
 template <int N> constexpr int templated() __attribute__((enable_if(N, ""))) {
-  return 1;
+  return 1; //expected-note@-1 2 {{candidate disabled}}
 }
 
-constexpr int A = templated<0>(); // expected-error{{no matching function for call to 'templated'}} expected-note@-4{{candidate disabled}}
+constexpr int A = templated<0>(); // expected-error{{no matching function for call to 'templated'}}
 static_assert(templated<1>() == 1, "");
 
-template <int N> constexpr int callTemplated() { return templated<N>(); }
+template <int N> constexpr int callTemplated() { return templated<N>(); } // expected-error{{no matching function for call to 'templated'}} expected-note{{subexpression not valid}}
 
-constexpr int B = 10 + // the carat for the error should be pointing to the problematic call (on the next line), not here.
-    callTemplated<0>(); // expected-error{{initialized by a constant expression}} expected-error@-3{{no matching function for call to 'templated'}} expected-note{{in instantiation of function template}} expected-note@-10{{candidate disabled}}
+constexpr int B = 10 +                // expected-error{{initialized by a constant expression}}
+                  callTemplated<0>(); // expected-note{{in instantiation of function template}} expected-note{{in call to 'callTemplated()'}}
 static_assert(callTemplated<1>() == 1, "");
 }
 
Index: test/SemaCXX/constructor-initializer.cpp
===================================================================
--- test/SemaCXX/constructor-initializer.cpp
+++ test/SemaCXX/constructor-initializer.cpp
@@ -250,7 +250,7 @@
     B(const String& s, int e=0) // expected-error {{unknown type name}} 
       : A(e), m_String(s) , m_ErrorStr(__null) {} // expected-error {{no matching constructor}} expected-error {{does not name}}
     B(const B& e)
-      : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error {{does not name}} \
+      : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error 2 {{does not name}} \
       // expected-error {{no member named 'm_String' in 'test3::B'}}
     }
   };
Index: test/Index/getcursor-recovery.cpp
===================================================================
--- /dev/null
+++ test/Index/getcursor-recovery.cpp
@@ -0,0 +1,50 @@
+int foo(int, int);
+int foo(int, double);
+int x;
+
+void testTypedRecoveryExpr() {
+  // Inner foo() is a recoveryexpr of type int. Outer foo() is a regular call.
+  foo(x, foo(x));
+}
+// RUN: c-index-test -cursor-at=%s:7:3 %s | FileCheck -check-prefix=OUTER-FOO %s
+// OUTER-FOO: DeclRefExpr=foo:1:5
+// RUN: c-index-test -cursor-at=%s:7:7 %s | FileCheck -check-prefix=OUTER-X %s
+// OUTER-X: DeclRefExpr=x:3:5
+// RUN: c-index-test -cursor-at=%s:7:10 %s | FileCheck -check-prefix=INNER-FOO %s
+// INNER-FOO: OverloadedDeclRef=foo[2:5, 1:5]
+// RUN: c-index-test -cursor-at=%s:7:14 %s | FileCheck -check-prefix=INNER-X %s
+// INNER-X: DeclRefExpr=x:3:5
+
+
+
+
+int bar(int, int);
+int bar(int, double);
+int y;
+
+void testUntypedRecoveryExpr() {
+  // Inner bar() is a recoveryexpr of RecoveryTy. Outer is a dependent CallExpr.
+  bar(y, bar(y));
+}
+// RUN: c-index-test -cursor-at=%s:27:3 %s | FileCheck -check-prefix=OUTER-BAR %s
+// OUTER-BAR: DeclRefExpr=bar:21:5
+// RUN: c-index-test -cursor-at=%s:27:7 %s | FileCheck -check-prefix=OUTER-Y %s
+// OUTER-Y: DeclRefExpr=y:23:5
+// RUN: c-index-test -cursor-at=%s:27:10 %s | FileCheck -check-prefix=INNER-BAR %s
+// INNER-BAR: OverloadedDeclRef=bar[22:5, 21:5]
+// RUN: c-index-test -cursor-at=%s:27:14 %s | FileCheck -check-prefix=INNER-Y %s
+// INNER-Y: DeclRefExpr=y:23:5
+
+
+
+
+struct S{} s;
+int z;
+
+void testInvalidMember() {
+  s.mem(z);
+}
+// RUN: c-index-test -cursor-at=%s:45:3 %s | FileCheck -check-prefix=S %s
+// S: DeclRefExpr=s:41:12
+// RUN: c-index-test -cursor-at=%s:45:9 %s | FileCheck -check-prefix=Z %s
+// Z: DeclRefExpr=z:42:5
Index: test/CodeCompletion/member-access.cpp
===================================================================
--- test/CodeCompletion/member-access.cpp
+++ test/CodeCompletion/member-access.cpp
@@ -210,3 +210,14 @@
 // CHECK-CC9: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>) (requires fix-it: {181:4-181:5} to "->")
 // CHECK-CC9: memfun3 : [#int#]memfun3(<#int#>) (requires fix-it: {181:4-181:5} to "->")
 // CHECK-CC9: operator-> : [#Derived *#]operator->()[# const#]
+
+struct S { int MysteryMember; };
+S overloaded(int);
+S overloaded(double);
+void foo() {
+  // No overload matches, but we recover with the correct type.
+  overloaded().
+}
+// RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:219:16 %s -o - | FileCheck -check-prefix=CHECK-CC10 %s
+// CHECK-CC10: [#int#]MysteryMember
+
Index: test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
===================================================================
--- test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
+++ test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
@@ -124,6 +124,7 @@
   template<typename T, typename U> using U = S<T, int, U>; // expected-note 2{{template parameter is declared here}}
   template<typename...Ts> U<Ts...> &f(U<Ts...>, Ts...); // expected-error 2{{pack expansion used as argument for non-pack parameter of alias template}}
   S<int, int, double> &s1 = f({}, 0, 0.0); // expected-error {{no matching function}}
+  // f() is invalid, so: expected-error@-1 {{cannot bind to a value of unrelated type 'int'}}
 }
 
 namespace PR18401 {
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1174,6 +1174,7 @@
     case Stmt::UnresolvedLookupExprClass:
     case Stmt::UnresolvedMemberExprClass:
     case Stmt::TypoExprClass:
+    case Stmt::RecoveryExprClass:
     case Stmt::CXXNoexceptExprClass:
     case Stmt::PackExpansionExprClass:
     case Stmt::SubstNonTypeTemplateParmPackExprClass:
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -11,6 +11,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "clang/Serialization/ASTBitCodes.h"
 #include "clang/Serialization/ASTWriter.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
@@ -655,6 +656,17 @@
   Code = serialization::EXPR_CALL;
 }
 
+void ASTStmtWriter::VisitRecoveryExpr(RecoveryExpr *E) {
+  VisitExpr(E);
+  Record.push_back(std::distance(E->children().begin(), E->children().end()));
+  Record.AddSourceLocation(E->getBeginLoc());
+  Record.AddSourceLocation(E->getEndLoc());
+  Record.push_back(E->attemptedStmtClass());
+  for (Stmt* Child : E->children())
+    Record.AddStmt(Child);
+  Code = serialization::EXPR_RECOVERY;
+}
+
 void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
   // Don't call VisitExpr, we'll write everything here.
 
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -1827,6 +1827,20 @@
   llvm_unreachable("Cannot read TypoExpr nodes");
 }
 
+void ASTStmtReader::VisitRecoveryExpr(RecoveryExpr *E) {
+  VisitExpr(E);
+  unsigned NumArgs = Record.readInt();
+  E->BeginLoc = ReadSourceLocation();
+  E->EndLoc = ReadSourceLocation();
+  E->Attempted = (Stmt::StmtClass)Record.readInt();
+  assert(
+      (NumArgs == std::distance(E->children().begin(), E->children().end())) &&
+      "Wrong NumArgs!");
+  (void)NumArgs;
+  for (Stmt*& Child : E->children())
+    Child = Record.readSubStmt();
+}
+
 //===----------------------------------------------------------------------===//
 // Microsoft Expressions and Statements
 //===----------------------------------------------------------------------===//
@@ -2533,6 +2547,11 @@
           Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty);
       break;
 
+    case EXPR_RECOVERY:
+      S = RecoveryExpr::CreateEmpty(
+          Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields]);
+      break;
+
     case EXPR_MEMBER: {
       // We load everything here and fully initialize it at creation.
       // That way we can use MemberExpr::Create and don't have to duplicate its
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -6959,6 +6959,9 @@
     case PREDEF_TYPE_OVERLOAD_ID:
       T = Context.OverloadTy;
       break;
+    case PREDEF_TYPE_RECOVERY_ID:
+      T = Context.RecoveryTy;
+      break;
     case PREDEF_TYPE_BOUND_MEMBER:
       T = Context.BoundMemberTy;
       break;
Index: lib/Serialization/ASTCommon.cpp
===================================================================
--- lib/Serialization/ASTCommon.cpp
+++ lib/Serialization/ASTCommon.cpp
@@ -183,6 +183,9 @@
   case BuiltinType::Overload:
     ID = PREDEF_TYPE_OVERLOAD_ID;
     break;
+  case BuiltinType::Recovery:
+    ID = PREDEF_TYPE_RECOVERY_ID;
+    break;
   case BuiltinType::BoundMember:
     ID = PREDEF_TYPE_BOUND_MEMBER;
     break;
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -9378,6 +9378,12 @@
   return E;
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformRecoveryExpr(RecoveryExpr *E) {
+  return E;
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
Index: lib/Sema/SemaPseudoObject.cpp
===================================================================
--- lib/Sema/SemaPseudoObject.cpp
+++ lib/Sema/SemaPseudoObject.cpp
@@ -1484,7 +1484,7 @@
       S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
                               RefExpr->isArrow() ? tok::arrow : tok::period, SS,
                               SourceLocation(), GetterName, nullptr);
-  if (GetterExpr.isInvalid()) {
+  if (GetterExpr.isInvalid() || isa<RecoveryExpr>(GetterExpr.get())) {
     S.Diag(RefExpr->getMemberLoc(),
            diag::err_cannot_find_suitable_accessor) << 0 /* getter */
       << RefExpr->getPropertyDecl();
@@ -1513,7 +1513,7 @@
       S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
                               RefExpr->isArrow() ? tok::arrow : tok::period, SS,
                               SourceLocation(), SetterName, nullptr);
-  if (SetterExpr.isInvalid()) {
+  if (SetterExpr.isInvalid() || isa<RecoveryExpr>(SetterExpr.get())) {
     S.Diag(RefExpr->getMemberLoc(),
            diag::err_cannot_find_suitable_accessor) << 1 /* setter */
       << RefExpr->getPropertyDecl();
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/Type.h"
 #include "clang/Sema/Overload.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
@@ -12111,6 +12112,42 @@
   return false;
 }
 
+// Guess at what the return type for an unresolvable overload should be.
+static QualType chooseRecoveryType(OverloadCandidateSet &CS,
+                                   OverloadCandidateSet::iterator *Best) {
+  llvm::Optional<QualType> Result;
+  // Adjust Type after seeing a candidate.
+  auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) {
+    if (!Candidate.Function)
+      return;
+    QualType T = Candidate.Function->getCallResultType();
+    if (T.isNull())
+      return;
+    if (!Result)
+      Result = T;
+    else if (Result != T)
+      Result = QualType();
+  };
+
+  // Look for an unambiguous type from a progressively larger subset.
+  // e.g. if types disagree, but all *viable* overloads return int, choose int.
+  //
+  // First, consider only the best candidate.
+  if (Best && *Best != CS.end())
+    ConsiderCandidate(**Best);
+  // Next, consider only viable candidates.
+  if (!Result)
+    for (const auto& C : CS)
+      if (C.Viable)
+        ConsiderCandidate(C);
+  // Finally, consider all candidates.
+  if (!Result)
+    for (const auto& C : CS)
+      ConsiderCandidate(C);
+
+  return Result.getValueOr(QualType());
+}
+
 /// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns
 /// the completed call expression. If overload resolution fails, emits
 /// diagnostics and returns ExprError()
@@ -12201,6 +12238,17 @@
   }
 
   // Overload resolution failed.
+  if (!AllowTypoCorrection)
+    return ExprError();
+
+  // Build a RecoveryExpr so that arguments aren't orphaned in the AST.
+  // Also record the unresolved OverloadExpr, and the type (if unambiguous).
+  SmallVector<Stmt*, 8> SubExprs = {Fn};
+  SubExprs.append(Args.begin(), Args.end());
+  if (auto RE = RecoveryExpr::Create(
+             SemaRef.Context, chooseRecoveryType(*CandidateSet, Best),
+             Stmt::CallExprClass, Fn->getBeginLoc(), RParenLoc, SubExprs))
+    return *RE;
   return ExprError();
 }
 
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp
+++ lib/Sema/SemaExprMember.cpp
@@ -1022,6 +1022,23 @@
     Diag(R.getNameLoc(), diag::err_no_member)
       << MemberName << DC
       << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+
+    SourceLocation BeginLoc;
+    if (BaseExpr)
+      BeginLoc = BaseExpr->getBeginLoc();
+    if (BeginLoc.isInvalid())
+      BeginLoc = TemplateKWLoc;
+    if (BeginLoc.isInvalid())
+      BeginLoc = SS.getBeginLoc();
+    if (BeginLoc.isInvalid())
+      BeginLoc = MemberNameInfo.getBeginLoc();
+    llvm::SmallVector<Stmt*, 1> SubExprs;
+    if (BaseExpr)
+      SubExprs.push_back(BaseExpr);
+    if (auto RE = RecoveryExpr::Create(Context, QualType(),
+                                       Stmt::MemberExprClass, BeginLoc,
+                                       MemberNameInfo.getEndLoc(), SubExprs))
+      return *RE;
     return ExprError();
   }
 
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1258,6 +1258,7 @@
   case Expr::UnresolvedLookupExprClass:
   case Expr::UnresolvedMemberExprClass:
   case Expr::TypoExprClass:
+  case Expr::RecoveryExprClass:
     // FIXME: Can any of the above throw?  If so, when?
     return CT_Cannot;
 
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -1169,7 +1169,8 @@
       Expr *Arg = E.get();
       E = S.BuildCallExpr(nullptr, Get, Loc, Arg, Loc);
     }
-    if (E.isInvalid())
+    // Don't allow recovery of get() calls for now, this is a can of worms.
+    if (E.isInvalid() || isa<RecoveryExpr>(E.get()))
       return true;
     Expr *Init = E.get();
 
Index: lib/Sema/SemaCoroutine.cpp
===================================================================
--- lib/Sema/SemaCoroutine.cpp
+++ lib/Sema/SemaCoroutine.cpp
@@ -373,6 +373,8 @@
         << Base->getSourceRange();
     return ExprError();
   }
+  if (isa<RecoveryExpr>(Result.get()))
+    return ExprError();
 
   return S.BuildCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
 }
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -13,6 +13,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/OperationKinds.h"
+#include "clang/Sema/Ownership.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
Index: lib/Index/USRGeneration.cpp
===================================================================
--- lib/Index/USRGeneration.cpp
+++ lib/Index/USRGeneration.cpp
@@ -713,6 +713,7 @@
 #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
 #include "clang/AST/BuiltinTypes.def"
         case BuiltinType::Dependent:
+        case BuiltinType::Recovery:
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
         case BuiltinType::Id:
 #include "clang/Basic/OpenCLImageTypes.def"
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -2869,6 +2869,7 @@
       return false;
 
     case BuiltinType::Dependent:
+    case BuiltinType::Recovery:
 #define BUILTIN_TYPE(Id, SingletonId)
 #define PLACEHOLDER_TYPE(Id, SingletonId) \
     case BuiltinType::Id:
Index: lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- lib/CodeGen/CodeGenTypes.cpp
+++ lib/CodeGen/CodeGenTypes.cpp
@@ -513,6 +513,7 @@
       break;
 
     case BuiltinType::Dependent:
+    case BuiltinType::Recovery:
 #define BUILTIN_TYPE(Id, SingletonId)
 #define PLACEHOLDER_TYPE(Id, SingletonId) \
     case BuiltinType::Id:
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -630,6 +630,7 @@
 #define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
 #include "clang/AST/BuiltinTypes.def"
   case BuiltinType::Dependent:
+  case BuiltinType::Recovery:
     llvm_unreachable("Unexpected builtin type");
   case BuiltinType::NullPtr:
     return DBuilder.createNullPtrType();
Index: lib/AST/TypeLoc.cpp
===================================================================
--- lib/AST/TypeLoc.cpp
+++ lib/AST/TypeLoc.cpp
@@ -372,6 +372,7 @@
 
   case BuiltinType::NullPtr:
   case BuiltinType::Overload:
+  case BuiltinType::Recovery:
   case BuiltinType::Dependent:
   case BuiltinType::BoundMember:
   case BuiltinType::UnknownAny:
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2843,6 +2843,8 @@
     return "nullptr_t";
   case Overload:
     return "<overloaded function type>";
+  case Recovery:
+    return "<recovery type>";
   case BoundMember:
     return "<bound member function type>";
   case PseudoObject:
@@ -3860,6 +3862,7 @@
     // Dependent types that could instantiate to a pointer type.
     case BuiltinType::Dependent:
     case BuiltinType::Overload:
+    case BuiltinType::Recovery:
     case BuiltinType::BoundMember:
     case BuiltinType::PseudoObject:
     case BuiltinType::UnknownAny:
Index: lib/AST/TextNodeDumper.cpp
===================================================================
--- lib/AST/TextNodeDumper.cpp
+++ lib/AST/TextNodeDumper.cpp
@@ -717,6 +717,10 @@
   }
 }
 
+void TextNodeDumper::VisitRecoveryExpr(const RecoveryExpr *Node) {
+  OS << " " << Stmt::getStmtClassName(Node->attemptedStmtClass());
+}
+
 void TextNodeDumper::VisitUnresolvedLookupExpr(
     const UnresolvedLookupExpr *Node) {
   OS << " (";
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1882,6 +1882,10 @@
   VisitExpr(E);
 }
 
+void StmtProfiler::VisitRecoveryExpr(const RecoveryExpr *E) {
+  VisitExpr(E);
+}
+
 void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
   VisitExpr(S);
 }
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -2372,6 +2372,20 @@
   llvm_unreachable("Cannot print TypoExpr nodes");
 }
 
+void StmtPrinter::VisitRecoveryExpr(RecoveryExpr *Node) {
+  OS << "<bad " << Stmt::getStmtClassName(Node->attemptedStmtClass()) << ">(";
+  const char *Sep = "";
+  for (Stmt *S : Node->children()) {
+    OS << Sep;
+    if (Expr *E = dyn_cast<Expr>(S))
+      PrintExpr(E);
+    else
+      PrintStmt(S);
+    Sep = ", ";
+  }
+  OS << ')';
+}
+
 void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
   OS << "__builtin_astype(";
   PrintExpr(Node->getSrcExpr());
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -71,8 +71,8 @@
   return ::operator new(bytes, C, alignment);
 }
 
-const char *Stmt::getStmtClassName() const {
-  return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
+const char *Stmt::getStmtClassName(StmtClass C) {
+  return getStmtInfoTableEntry(C).Name;
 }
 
 // Check that no statement / expression class is polymorphic. LLVM style RTTI
Index: lib/AST/NSAPI.cpp
===================================================================
--- lib/AST/NSAPI.cpp
+++ lib/AST/NSAPI.cpp
@@ -485,6 +485,7 @@
   case BuiltinType::BoundMember:
   case BuiltinType::Dependent:
   case BuiltinType::Overload:
+  case BuiltinType::Recovery:
   case BuiltinType::UnknownAny:
   case BuiltinType::ARCUnbridgedCast:
   case BuiltinType::Half:
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -2013,6 +2013,7 @@
   case BuiltinType::Id:
 #include "clang/AST/BuiltinTypes.def"
   case BuiltinType::Dependent:
+  case BuiltinType::Recovery:
     llvm_unreachable("placeholder types shouldn't get to name mangling");
 
   case BuiltinType::ObjCId:
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -2626,6 +2626,7 @@
   case BuiltinType::Id:
 #include "clang/AST/BuiltinTypes.def"
   case BuiltinType::Dependent:
+  case BuiltinType::Recovery:
     if (!NullOut)
       llvm_unreachable("mangling a placeholder type");
     break;
@@ -3590,6 +3591,7 @@
   case Expr::PseudoObjectExprClass:
   case Expr::AtomicExprClass:
   case Expr::FixedPointLiteralClass:
+  case Expr::RecoveryExprClass:
   {
     if (!NullOut) {
       // As bad as this diagnostic is, it's better than crashing.
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -8081,6 +8081,7 @@
       return GCCTypeClass::None;
 
     case BuiltinType::Dependent:
+    case BuiltinType::Recovery:
       llvm_unreachable("unexpected dependent type");
     };
     llvm_unreachable("unexpected placeholder type");
@@ -11698,6 +11699,7 @@
   case Expr::CXXPseudoDestructorExprClass:
   case Expr::UnresolvedLookupExprClass:
   case Expr::TypoExprClass:
+  case Expr::RecoveryExprClass:
   case Expr::DependentScopeDeclRefExprClass:
   case Expr::CXXConstructExprClass:
   case Expr::CXXInheritedCtorInitExprClass:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -132,6 +132,7 @@
   case Expr::DependentCoawaitExprClass:
   case Expr::CXXDependentScopeMemberExprClass:
   case Expr::DependentScopeDeclRefExprClass:
+  case Expr::RecoveryExprClass:
     // ObjC instance variables are lvalues
     // FIXME: ObjC++0x might have different rules
   case Expr::ObjCIvarRefExprClass:
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -2339,6 +2339,7 @@
   // If we don't know precisely what we're looking at, let's not warn.
   case UnresolvedLookupExprClass:
   case CXXUnresolvedConstructExprClass:
+  case RecoveryExprClass:
     return false;
 
   case CXXTemporaryObjectExprClass:
@@ -3124,6 +3125,8 @@
   case TypoExprClass:
   case CXXFoldExprClass:
     llvm_unreachable("shouldn't see dependent / unresolved nodes here");
+  case RecoveryExprClass:
+    return IncludePossibleEffects;
 
   case DeclRefExprClass:
   case ObjCIvarRefExprClass:
@@ -4317,3 +4320,41 @@
   }
   return OriginalTy;
 }
+
+RecoveryExpr::RecoveryExpr(QualType T, StmtClass Attempted,
+                           SourceLocation BeginLoc, SourceLocation EndLoc,
+                           ArrayRef<Stmt *> Stmts)
+    : Expr(RecoveryExprClass, T, VK_LValue, OK_Ordinary, T->isDependentType(),
+           /*isValueDependent=*/true,
+           /*isInstantiationDependent=*/true,
+           /*containsUnexpandedParameterPack*/ false),
+      BeginLoc(BeginLoc), EndLoc(EndLoc), Attempted(Attempted),
+      NumStmts(Stmts.size()) {
+  std::copy(Stmts.begin(), Stmts.end(), getTrailingObjects<Stmt *>());
+}
+
+Optional<RecoveryExpr *> RecoveryExpr::Create(ASTContext &Ctx, QualType T,
+                                              StmtClass Attempted,
+                                              SourceLocation BeginLoc,
+                                              SourceLocation EndLoc,
+                                              ArrayRef<Stmt *> Stmts) {
+  // FIXME: In some contexts recovery is not desired (e.g. synthesized member
+  // accesses for coroutines). Currently the caller checks for RecoveryExpr and
+  // discards it, it would be cleaner/safer to have a flag on Sema and never
+  // call Create(). The current cases where we return None could be moved there.
+
+  if (T.isNull()) {
+    if (!Ctx.getLangOpts().CPlusPlus)
+      return None; // We have no type, and can't use a dependent type.
+    T = Ctx.RecoveryTy;
+  }
+  void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(Stmts.size()),
+                           alignof(CallExpr));
+  return new (Mem) RecoveryExpr(T, Attempted, BeginLoc, EndLoc, Stmts);
+}
+
+RecoveryExpr *RecoveryExpr::CreateEmpty(ASTContext &Ctx, unsigned NumStmts) {
+  void *Mem =
+      Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumStmts), alignof(CallExpr));
+  return new (Mem) RecoveryExpr(EmptyShell());
+}
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -1247,6 +1247,9 @@
   // expressions.
   InitBuiltinType(DependentTy,         BuiltinType::Dependent);
 
+  // Placeholder type for broken/invalid expressions of unknown type.
+  InitBuiltinType(RecoveryTy,          BuiltinType::Recovery);
+
   // Placeholder type for functions.
   InitBuiltinType(OverloadTy,          BuiltinType::Overload);
 
@@ -6610,6 +6613,7 @@
     case BuiltinType::OCLReserveID:
     case BuiltinType::OCLSampler:
     case BuiltinType::Dependent:
+    case BuiltinType::Recovery:
 #define BUILTIN_TYPE(KIND, ID)
 #define PLACEHOLDER_TYPE(KIND, ID) \
     case BuiltinType::KIND:
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1010,6 +1010,9 @@
       /// \brief The '_Sat unsigned long _Fract' type
       PREDEF_TYPE_SAT_ULONG_FRACT_ID = 69,
 
+      /// The type for broken/invalid expressions of unknown type.
+      PREDEF_TYPE_RECOVERY_ID = 70,
+
       /// OpenCL image types with auto numeration
 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
       PREDEF_TYPE_##Id##_ID,
@@ -1750,6 +1753,9 @@
       /// An AtomicExpr record.
       EXPR_ATOMIC,
 
+      /// A RecoveryExpr record.
+      EXPR_RECOVERY,
+
       // Objective-C
 
       /// An ObjCStringLiteral record.
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -191,6 +191,7 @@
 def BlockExpr : DStmt<Expr>;
 def OpaqueValueExpr : DStmt<Expr>;
 def TypoExpr : DStmt<Expr>;
+def RecoveryExpr : DStmt<Expr>;
 
 // Microsoft Extensions.
 def MSPropertyRefExpr : DStmt<Expr>;
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -2419,8 +2419,9 @@
   friend class ASTContext; // ASTContext creates these.
 
   BuiltinType(Kind K)
-      : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
-             /*InstantiationDependent=*/(K == Dependent),
+      : Type(Builtin, QualType(),
+             /*Dependent=*/(K == Dependent || K == Recovery),
+             /*InstantiationDependent=*/(K == Dependent || K == Recovery),
              /*VariablyModified=*/false,
              /*Unexpanded parameter pack=*/false) {
     BuiltinTypeBits.Kind = K;
Index: include/clang/AST/TextNodeDumper.h
===================================================================
--- include/clang/AST/TextNodeDumper.h
+++ include/clang/AST/TextNodeDumper.h
@@ -259,6 +259,7 @@
   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
   void VisitExprWithCleanups(const ExprWithCleanups *Node);
   void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
+  void VisitRecoveryExpr(const RecoveryExpr *Node);
   void VisitSizeOfPackExpr(const SizeOfPackExpr *Node);
   void
   VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node);
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -1047,7 +1047,10 @@
   Stmt &operator=(const Stmt &) = delete;
   Stmt &operator=(Stmt &&) = delete;
 
-  const char *getStmtClassName() const;
+  static const char *getStmtClassName(StmtClass);
+  const char *getStmtClassName() const {
+    return getStmtClassName(getStmtClass());
+  }
 
   bool isOMPStructuredBlock() const { return StmtBits.IsOMPStructuredBlock; }
   void setIsOMPStructuredBlock(bool IsOMPStructuredBlock) {
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2575,6 +2575,7 @@
 DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
 DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
 DEF_TRAVERSE_STMT(TypoExpr, {})
+DEF_TRAVERSE_STMT(RecoveryExpr, {})
 DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})
 
 // These operators (all of them) do not need any action except
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -5797,6 +5797,64 @@
   }
 
 };
+
+/// RecoveryExpr - a broken expression that we couldn't construct an AST for,
+/// e.g. because overload resolution failed.
+/// We capture:
+///  - the kind of expression that would have been produced
+///  - the valid subexpressions
+///  - the type, if known. If unknown, it is the built-in RecoveryTy, which
+///    is dependent (and so generally suppresses further diagnostics etc).
+class RecoveryExpr final : public Expr,
+                           private llvm::TrailingObjects<RecoveryExpr, Stmt *> {
+public:
+  // T may be null, in which case RecoveryTy is used.
+  // Returns None if recovery is not valid here, e.g. because dependent types
+  // are required but not supported.
+  static Optional<RecoveryExpr *> Create(ASTContext &Ctx, QualType T,
+                                         StmtClass Attempted,
+                                         SourceLocation BeginLoc,
+                                         SourceLocation EndLoc,
+                                         ArrayRef<Stmt *> Stmts);
+  static RecoveryExpr *CreateEmpty(ASTContext &Ctx, unsigned NumStmts);
+
+  /// The expression type that would have been produced, if not for errors
+  /// in the code.
+  StmtClass attemptedStmtClass() const { return Attempted; }
+
+  child_range children() {
+    const_child_range CCR = const_cast<const RecoveryExpr *>(this)->children();
+    return child_range(cast_away_const(CCR.begin()),
+                       cast_away_const(CCR.end()));
+  }
+  const_child_range children() const {
+    Stmt *const *cs = const_cast<Stmt *const *>(
+        reinterpret_cast<const Stmt *const *>(getTrailingObjects<Stmt *>()));
+    return const_child_range(cs, cs + NumStmts);
+  }
+
+  SourceLocation getBeginLoc() const { return BeginLoc; }
+  SourceLocation getEndLoc() const { return EndLoc; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == RecoveryExprClass;
+  }
+
+private:
+  RecoveryExpr(QualType T, StmtClass Attempted, SourceLocation BeginLoc,
+               SourceLocation EndLoc, ArrayRef<Stmt *> Stmts);
+  RecoveryExpr(EmptyShell Empty) : Expr(RecoveryExprClass, Empty) {}
+
+  size_t numTrailingObjects(OverloadToken<Stmt *>) const { return NumStmts; }
+
+  SourceLocation BeginLoc, EndLoc;
+  StmtClass Attempted;
+  unsigned NumStmts;
+  friend TrailingObjects;
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+};
+
 } // end namespace clang
 
 #endif // LLVM_CLANG_AST_EXPR_H
Index: include/clang/AST/BuiltinTypes.def
===================================================================
--- include/clang/AST/BuiltinTypes.def
+++ include/clang/AST/BuiltinTypes.def
@@ -257,6 +257,13 @@
 // theoretically deducible.
 BUILTIN_TYPE(Dependent, DependentTy)
 
+// The type of a broken expression whose type isn't clear. e.g. 'foo()', where
+// foo's overloads require arguments and have different return types.
+// This type is considered dependent, even though it will never be deduced: the
+// concrete type is determined by correcting the source code, not instantiating
+// a template.
+BUILTIN_TYPE(Recovery, RecoveryTy)
+
 // The type of an unresolved overload set.  A placeholder type.
 // Expressions with this type have one of the following basic
 // forms, with parentheses generally permitted:
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -1031,7 +1031,7 @@
   CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
   CanQualType Float128ComplexTy;
   CanQualType VoidPtrTy, NullPtrTy;
-  CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
+  CanQualType DependentTy, RecoveryTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
   CanQualType BuiltinFnTy;
   CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
   CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to