From e49ff3ef3459e97fa76502bd9eae4ed9170fd048 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 25 Sep 2012 04:46:05 +0000 Subject: [PATCH] Fix crash when a decltype expression in a trailing return type refers to the function being instantiated. An error recovery codepath was recursively performing name lookup (and triggering an unbounded stack of template instantiations which blew out the stack before hitting the depth limit). Patch by Wei Pan! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164586 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 6 ++++++ lib/Sema/Sema.cpp | 1 + lib/Sema/SemaOverload.cpp | 23 +++++++++++++++++++++++ test/SemaCXX/trailing-return-0x.cpp | 16 ++++++++++++++++ 4 files changed, 46 insertions(+) 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 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 auto foo(T t) -> decltype(foo(t)) {} + // template 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 xx; only p2 = xx.f(0L); only p3 = xx.g(0L, 1.0); only p4 = xx.get_nested().h(0L, 1.0, 3.14f); + +namespace PR12053 { + template + 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 + 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'}} + } +} -- 2.40.0