Index: tools/clang/include/clang/Basic/DiagnosticASTKinds.td
==================================================================
--- tools/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ tools/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -104,10 +104,11 @@
   "read of uninitialized object is not allowed in a constant expression">;
 def note_constexpr_calls_suppressed : Note<
   "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to "
   "see all)">;
 def note_constexpr_call_here : Note<"in call to '%0'">;
+def note_constexpr_circular_dependency : Note<"circular dependency detected">;
 
 // inline asm related.
 let CategoryName = "Inline Assembly Issue" in {
   def err_asm_invalid_escape : Error<
     "invalid %% escape in inline assembly string">;

Index: tools/clang/lib/AST/ExprConstant.cpp
==================================================================
--- tools/clang/lib/AST/ExprConstant.cpp
+++ tools/clang/lib/AST/ExprConstant.cpp
@@ -39,10 +39,11 @@
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/FunctionCache.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/SmallString.h"
 #include <cstring>
 #include <functional>
@@ -381,10 +382,13 @@
 
     /// CheckingPotentialConstantExpression - Are we checking whether the
     /// expression is a potential constant expression? If so, some diagnostics
     /// are suppressed.
     bool CheckingPotentialConstantExpression;
+
+    /// Local cache for constexpr function evaluations.
+    FunctionCache::CacheTable LocalCache;
 
     EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
       : Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
         CallStackDepth(0), NextCallIndex(1),
         BottomFrame(*this, SourceLocation(), 0, 0, 0),
@@ -2112,14 +2116,10 @@
     Info.Diag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
   }
   return false;
 }
 
-namespace {
-typedef SmallVector<APValue, 8> ArgVector;
-}
-
 /// EvaluateArgs - Evaluate the arguments to a function call.
 static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
                          EvalInfo &Info) {
   bool Success = true;
   for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
@@ -2142,15 +2142,39 @@
                                EvalInfo &Info, APValue &Result) {
   ArgVector ArgValues(Args.size());
   if (!EvaluateArgs(Args, ArgValues, Info))
     return false;
 
-  if (!Info.CheckCallLimit(CallLoc))
+  FunctionCache Cache;
+  if (Callee->getNumParams() == Args.size()) {
+    // FIXME: add support for This.
+    if (!This) {
+      Cache = FunctionCache::Create(Info.LocalCache, Callee, Body, ArgValues);
+      if (Cache.hasResult(Result)) {
+        if (Result.getKind() != APValue::Uninitialized)
+          return true;
+        // A returned value of "Uninitialized" means that
+        // a circular dependency has been discovered.
+        if (!Info.CheckingPotentialConstantExpression)
+          Info.Diag(CallLoc, diag::note_constexpr_circular_dependency);
+      return false;
+      }
+    }
+  }
+
+  if (!Info.CheckCallLimit(CallLoc)) {
+    Cache.discard(Info.LocalCache);
     return false;
+  }
 
   CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
-  return EvaluateStmt(Result, Info, Body) == ESR_Returned;
+  if (EvaluateStmt(Result, Info, Body) == ESR_Returned) {
+    Cache.setResultOrDiscard(Info.LocalCache, Result);
+    return true;
+  }
+  Cache.discard(Info.LocalCache);
+  return false;
 }
 
 /// Evaluate a constructor call.
 static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
                                   ArrayRef<const Expr*> Args,

