diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 6 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 23 | ||||
-rw-r--r-- | test/SemaCXX/trailing-return-0x.cpp | 16 |
4 files changed, 46 insertions, 0 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 74114a8d32..676f52953f 100644 --- a/include/clang/Sema/Sema.h +++ b/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 a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index bd7c8515f6..08ccfa4259 100644 --- a/lib/Sema/Sema.cpp +++ b/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 a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index fe4cac8630..e9c2c6c5f6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -9655,6 +9655,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. @@ -9667,6 +9681,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 a/test/SemaCXX/trailing-return-0x.cpp b/test/SemaCXX/trailing-return-0x.cpp index c219b77d9e..462b4fa3da 100644 --- a/test/SemaCXX/trailing-return-0x.cpp +++ b/test/SemaCXX/trailing-return-0x.cpp @@ -69,3 +69,19 @@ X<int> xx; only<int> p2 = xx.f(0L); only<double> p3 = xx.g(0L, 1.0); only<double> p4 = xx.get_nested<double>().h(0L, 1.0, 3.14f); + +namespace PR12053 { + 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'}} + } +} |