aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-09-25 04:46:05 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-09-25 04:46:05 +0000
commite49ff3ef3459e97fa76502bd9eae4ed9170fd048 (patch)
tree4a404becefcdea1230ee2a171be4f4e6f31b4f95
parent511e3ae61bc2ff3803195587fe9774cb815726fc (diff)
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
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/Sema/Sema.cpp1
-rw-r--r--lib/Sema/SemaOverload.cpp23
-rw-r--r--test/SemaCXX/trailing-return-0x.cpp16
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'}}
+ }
+}