diff --git include/clang/Sema/Sema.h include/clang/Sema/Sema.h
index 2cd4688..c023404 100644
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -234,6 +234,12 @@ public:
   /// VisContext - Manages the stack for \#pragma GCC visibility.
   void *VisContext; // Really a "PragmaVisStack*"
 
+  /// \brief Flag indicating if Sema is building a recovery call expression.
+  ///
+  /// This flag is used to avoid building recovery call expressions
+  /// if Sema is already doing so, which would cause infinite recursions.
+  bool IsBuildingRecoveryCallExpr;
+
   /// ExprNeedsCleanups - True if the current evaluation context
   /// requires cleanups to be run at its conclusion.
   bool ExprNeedsCleanups;
diff --git lib/Sema/Sema.cpp lib/Sema/Sema.cpp
index bd7c851..08ccfa4 100644
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -90,6 +90,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
     CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
     CurContext(0), OriginalLexicalContext(0),
     PackContext(0), MSStructPragmaOn(false), VisContext(0),
+    IsBuildingRecoveryCallExpr(false),
     ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
     IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
     NSNumberDecl(0),
diff --git lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.cpp
index 14f8db6..42fbb9a 100644
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -9653,6 +9653,20 @@ class NoTypoCorrectionCCC : public CorrectionCandidateCallback {
     return false;
   }
 };
+
+class BuildRecoveryCallExprRAII {
+  Sema &SemaRef;
+public:
+  BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S) {
+    assert(SemaRef.IsBuildingRecoveryCallExpr == false);
+    SemaRef.IsBuildingRecoveryCallExpr = true;
+  }
+
+  ~BuildRecoveryCallExprRAII() {
+    SemaRef.IsBuildingRecoveryCallExpr = false;
+  }
+};
+
 }
 
 /// Attempts to recover from a call where no functions were found.
@@ -9665,6 +9679,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
                       llvm::MutableArrayRef<Expr *> Args,
                       SourceLocation RParenLoc,
                       bool EmptyLookup, bool AllowTypoCorrection) {
+  // Do not try to recover if it is already building a recovery call.
+  // This stops infinite loops for template instantiations like
+  //
+  // template <typename T> auto foo(T t) -> decltype(foo(t)) {}
+  // template <typename T> auto foo(T t) -> decltype(foo(&t)) {}
+  //
+  if (SemaRef.IsBuildingRecoveryCallExpr)
+    return ExprError();
+  BuildRecoveryCallExprRAII RCE(SemaRef);
 
   CXXScopeSpec SS;
   SS.Adopt(ULE->getQualifierLoc());
diff --git test/SemaCXX/PR12053.cpp test/SemaCXX/PR12053.cpp
new file mode 100644
index 0000000..d643e2b
--- /dev/null
+++ test/SemaCXX/PR12053.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+template <typename T>
+auto f1(T t) -> decltype(f1(t)) {} // expected-note{{candidate template ignored}}
+
+void test_f1() {
+  f1(0); // expected-error{{no matching function for call to 'f1'}}
+}
+
+template <typename T>
+auto f2(T t) -> decltype(f2(&t)) {} // expected-note{{candidate template ignored}}
+
+void test_f2() {
+  f2(0); // expected-error{{no matching function for call to 'f2'}}
+}
diff --git test/SemaTemplate/instantiation-depth-subst.cpp test/SemaTemplate/instantiation-depth-subst.cpp
index 58e6374..7a1235b 100644
--- test/SemaTemplate/instantiation-depth-subst.cpp
+++ test/SemaTemplate/instantiation-depth-subst.cpp
@@ -2,8 +2,9 @@
 
 // PR9793
 template<typename T> auto f(T t) -> decltype(f(t)); // \
-// expected-error {{recursive template instantiation exceeded maximum depth of 2}} \
-// expected-note 3 {{while substituting}} \
+// expected-error 4 {{recursive template instantiation exceeded maximum depth of 2}} \
+// expected-note 6 {{while substituting}} \
 // expected-note {{candidate}}
 
-int k = f(0); // expected-error {{no matching function for call to 'f'}}
+struct S {};
+int k = f(S()); // expected-error {{no matching function for call to 'f'}}
