Commit 0bcddcd0 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh
Browse files

C++: Limit template instantiation depth



A recursive template generates infinite expansions.

Consider the following example:

template <class R1>
struct Base
{
};

template<typename R>
struct Derived :
  Base<
    typename Derived<typename Base<R>::type>::type,
    typename Derived<typename Base<R>::type>::type
  >::type
{};

R is instantiated as Base<R>::type, which causes another
instantiation of R into Base<Base<R>> etc...

This is not a solution, but a workaround.

Task-number: QTCREATORBUG-15141
Change-Id: Ib04f70275e07919e2cb6c7fb61a2045bd52f4a7d
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@theqtcompany.com>
parent a27cd125
...@@ -1549,6 +1549,7 @@ CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snaps ...@@ -1549,6 +1549,7 @@ CreateBindings::CreateBindings(Document::Ptr thisDocument, const Snapshot &snaps
: _snapshot(snapshot) : _snapshot(snapshot)
, _control(QSharedPointer<Control>(new Control)) , _control(QSharedPointer<Control>(new Control))
, _expandTemplates(false) , _expandTemplates(false)
, _depth(0)
{ {
_globalNamespace = allocLookupScope(/*parent = */ 0, /*name = */ 0); _globalNamespace = allocLookupScope(/*parent = */ 0, /*name = */ 0);
_currentLookupScope = _globalNamespace; _currentLookupScope = _globalNamespace;
...@@ -1978,8 +1979,13 @@ void CreateBindings::initializeSubst(Clone &cloner, ...@@ -1978,8 +1979,13 @@ void CreateBindings::initializeSubst(Clone &cloner,
{ {
const unsigned argumentCountOfSpecialization = specialization->templateParameterCount(); const unsigned argumentCountOfSpecialization = specialization->templateParameterCount();
if (_depth > 15)
return;
++_depth;
for (unsigned i = 0; i < argumentCountOfSpecialization; ++i) for (unsigned i = 0; i < argumentCountOfSpecialization; ++i)
resolveTemplateArgument(cloner, subst, origin, specialization, instantiation, i); resolveTemplateArgument(cloner, subst, origin, specialization, instantiation, i);
--_depth;
} }
} // namespace CPlusPlus } // namespace CPlusPlus
...@@ -209,6 +209,7 @@ private: ...@@ -209,6 +209,7 @@ private:
LookupScope *_globalNamespace; LookupScope *_globalNamespace;
LookupScope *_currentLookupScope; LookupScope *_currentLookupScope;
bool _expandTemplates; bool _expandTemplates;
int _depth;
}; };
class CPLUSPLUS_EXPORT LookupContext class CPLUSPLUS_EXPORT LookupContext
......
...@@ -225,6 +225,8 @@ private slots: ...@@ -225,6 +225,8 @@ private slots:
void test_checksymbols_infiniteLoop_data(); void test_checksymbols_infiniteLoop_data();
void test_checksymbols_infiniteLoop(); void test_checksymbols_infiniteLoop();
void test_checksymbols_infiniteLoop_BUG15141();
void test_parentOfBlock(); void test_parentOfBlock();
void findField(); void findField();
...@@ -1122,6 +1124,25 @@ void tst_CheckSymbols::test_checksymbols_infiniteLoop() ...@@ -1122,6 +1124,25 @@ void tst_CheckSymbols::test_checksymbols_infiniteLoop()
TestCase::runCheckSymbols(document1, snapshot); TestCase::runCheckSymbols(document1, snapshot);
} }
void tst_CheckSymbols::test_checksymbols_infiniteLoop_BUG15141()
{
QByteArray source =
"template <class R1>\n"
"struct Base\n"
"{\n"
"};\n"
"\n"
"template<typename R>\n"
"struct Derived :\n"
" Base<\n"
" typename Derived<typename Base<R>::type>::type,\n"
" typename Derived<typename Base<R>::type>::type\n"
" >::type\n"
"{};\n";
BaseTestCase tc(source);
}
void tst_CheckSymbols::test_parentOfBlock() void tst_CheckSymbols::test_parentOfBlock()
{ {
const QByteArray source = "void C::f()\n" const QByteArray source = "void C::f()\n"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment