2020-07-09 04:04:37 +08:00
|
|
|
// RUN: %clang_cc1 -verify %s -DTEST=1
|
|
|
|
// RUN: %clang_cc1 -verify %s -DTEST=2
|
|
|
|
// RUN: %clang_cc1 -verify %s -DTEST=3
|
Improve behavior in the case of stack exhaustion.
Summary:
Clang performs various recursive operations (such as template instantiation),
and may use non-trivial amounts of stack space in each recursive step (for
instance, due to recursive AST walks). While we try to keep the stack space
used by such steps to a minimum and we have explicit limits on the number of
such steps we perform, it's impractical to guarantee that we won't blow out the
stack on deeply recursive template instantiations on complex ASTs, even with
only a moderately high instantiation depth limit.
The user experience in these cases is generally terrible: we crash with
no hint of what went wrong. Under this patch, we attempt to do better:
* Detect when the stack is nearly exhausted, and produce a warning with a
nice template instantiation backtrace, telling the user that we might
run slowly or crash.
* For cases where we're forced to trigger recursive template
instantiation in arbitrarily-deeply-nested contexts, check whether
we're nearly out of stack space and allocate a new stack (by spawning
a new thread) after producing the warning.
Reviewers: rnk, aaron.ballman
Subscribers: mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66361
llvm-svn: 369940
2019-08-27 02:18:07 +08:00
|
|
|
// REQUIRES: thread_support
|
|
|
|
|
2019-09-04 02:00:44 +08:00
|
|
|
// FIXME: Detection of, or recovery from, stack exhaustion does not work on
|
|
|
|
// NetBSD at the moment. Since this is a best-effort mitigation for exceeding
|
|
|
|
// implementation limits, just disable the test.
|
|
|
|
// UNSUPPORTED: system-netbsd
|
|
|
|
|
2020-07-10 16:24:58 +08:00
|
|
|
// asan has own stack-overflow check.
|
|
|
|
// UNSUPPORTED: asan
|
|
|
|
|
Improve behavior in the case of stack exhaustion.
Summary:
Clang performs various recursive operations (such as template instantiation),
and may use non-trivial amounts of stack space in each recursive step (for
instance, due to recursive AST walks). While we try to keep the stack space
used by such steps to a minimum and we have explicit limits on the number of
such steps we perform, it's impractical to guarantee that we won't blow out the
stack on deeply recursive template instantiations on complex ASTs, even with
only a moderately high instantiation depth limit.
The user experience in these cases is generally terrible: we crash with
no hint of what went wrong. Under this patch, we attempt to do better:
* Detect when the stack is nearly exhausted, and produce a warning with a
nice template instantiation backtrace, telling the user that we might
run slowly or crash.
* For cases where we're forced to trigger recursive template
instantiation in arbitrarily-deeply-nested contexts, check whether
we're nearly out of stack space and allocate a new stack (by spawning
a new thread) after producing the warning.
Reviewers: rnk, aaron.ballman
Subscribers: mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66361
llvm-svn: 369940
2019-08-27 02:18:07 +08:00
|
|
|
// expected-warning@* 0-1{{stack nearly exhausted}}
|
|
|
|
// expected-note@* 0+{{}}
|
|
|
|
|
2020-07-09 04:04:37 +08:00
|
|
|
#if TEST == 1
|
|
|
|
|
Improve behavior in the case of stack exhaustion.
Summary:
Clang performs various recursive operations (such as template instantiation),
and may use non-trivial amounts of stack space in each recursive step (for
instance, due to recursive AST walks). While we try to keep the stack space
used by such steps to a minimum and we have explicit limits on the number of
such steps we perform, it's impractical to guarantee that we won't blow out the
stack on deeply recursive template instantiations on complex ASTs, even with
only a moderately high instantiation depth limit.
The user experience in these cases is generally terrible: we crash with
no hint of what went wrong. Under this patch, we attempt to do better:
* Detect when the stack is nearly exhausted, and produce a warning with a
nice template instantiation backtrace, telling the user that we might
run slowly or crash.
* For cases where we're forced to trigger recursive template
instantiation in arbitrarily-deeply-nested contexts, check whether
we're nearly out of stack space and allocate a new stack (by spawning
a new thread) after producing the warning.
Reviewers: rnk, aaron.ballman
Subscribers: mgorny, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66361
llvm-svn: 369940
2019-08-27 02:18:07 +08:00
|
|
|
template<int N> struct X : X<N-1> {};
|
|
|
|
template<> struct X<0> {};
|
|
|
|
X<1000> x;
|
|
|
|
|
|
|
|
template<typename ...T> struct tuple {};
|
|
|
|
template<typename ...T> auto f(tuple<T...> t) -> decltype(f(tuple<T...>(t))) {} // expected-error {{exceeded maximum depth}}
|
|
|
|
void g() { f(tuple<int, int>()); }
|
|
|
|
|
|
|
|
int f(X<0>);
|
|
|
|
template<int N> auto f(X<N>) -> f(X<N-1>());
|
|
|
|
|
|
|
|
int k = f(X<1000>());
|
2020-07-09 04:04:37 +08:00
|
|
|
|
|
|
|
#elif TEST == 2
|
|
|
|
|
|
|
|
namespace template_argument_recursion {
|
|
|
|
struct ostream;
|
|
|
|
template<typename T> T &&declval();
|
|
|
|
|
|
|
|
namespace mlir {
|
|
|
|
template<typename T, typename = decltype(declval<ostream&>() << declval<T&>())>
|
|
|
|
ostream &operator<<(ostream& os, const T& obj); // expected-error {{exceeded maximum depth}}
|
|
|
|
struct Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void printFunctionalType(ostream &os, mlir::Value &v) { os << v; }
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif TEST == 3
|
|
|
|
|
|
|
|
namespace template_parameter_type_recursion {
|
|
|
|
struct ostream;
|
|
|
|
template<typename T> T &&declval();
|
|
|
|
template<bool B, typename T> struct enable_if { using type = T; };
|
|
|
|
|
|
|
|
namespace mlir {
|
|
|
|
template<typename T, typename enable_if<declval<ostream&>() << declval<T&>(), void*>::type = nullptr>
|
|
|
|
ostream &operator<<(ostream& os, const T& obj); // expected-error {{exceeded maximum depth}}
|
|
|
|
struct Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void printFunctionalType(ostream &os, mlir::Value &v) { os << v; }
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#error unknown test
|
|
|
|
#endif
|