C++: Fix crash for invalid code

...due to indirect recursion:

  ...
  CPlusPlus::ClassOrNamespace::lookupType        LookupContext.cpp 833  0x7fffd6c954cc
  CPlusPlus::ClassOrNamespace::nestedType        LookupContext.cpp 1364 0x7fffd6c94bc6
  CPlusPlus::ClassOrNamespace::lookupType_helper LookupContext.cpp 955  0x7fffd6c9517f
  CPlusPlus::ClassOrNamespace::lookupType_helper LookupContext.cpp 983  0x7fffd6c952ad
  CPlusPlus::ClassOrNamespace::lookupType        LookupContext.cpp 833  0x7fffd6c954cc
  CPlusPlus::ClassOrNamespace::nestedType        LookupContext.cpp 1364 0x7fffd6c94bc6
  CPlusPlus::ClassOrNamespace::lookupType_helper LookupContext.cpp 955  0x7fffd6c9517f
  CPlusPlus::ClassOrNamespace::lookupType_helper LookupContext.cpp 983  0x7fffd6c952ad
  CPlusPlus::ClassOrNamespace::lookupType        LookupContext.cpp 833  0x7fffd6c954cc
  ...

ClassOrNamespace::lookupType(const Name *) already guards with a list of
entries already processed, but some calls deeper the list is not passed
on and lookupType() starts again with an empty list. Handle that case,
too.

Task-number: QTCREATORBUG-18499
Change-Id: Iab8978f6ac1d0aea16f49b3547415f43de887b07
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Nikolai Kosjar
2017-07-05 12:10:17 +02:00
parent cfb5f610a1
commit f51d7a2314
2 changed files with 14 additions and 9 deletions

View File

@@ -952,7 +952,7 @@ ClassOrNamespace *ClassOrNamespace::lookupType_helper(const Name *name,
return this; return this;
} }
if (ClassOrNamespace *e = nestedType(name, origin)) if (ClassOrNamespace *e = nestedType(name, processed, origin))
return e; return e;
if (_templateId) { if (_templateId) {
@@ -1074,7 +1074,9 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateNestedAnonymousType(
} }
} }
ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespace *origin) ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name,
QSet<ClassOrNamespace *> *processed,
ClassOrNamespace *origin)
{ {
Q_ASSERT(name != 0); Q_ASSERT(name != 0);
Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()); Q_ASSERT(name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId());
@@ -1184,11 +1186,11 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
instantiation->_name = templId; instantiation->_name = templId;
instantiation->_templateId = templId; instantiation->_templateId = templId;
QSet<ClassOrNamespace *> processed; QSet<ClassOrNamespace *> otherProcessed;
while (!origin->_symbols.isEmpty() && origin->_symbols[0]->isBlock()) { while (!origin->_symbols.isEmpty() && origin->_symbols[0]->isBlock()) {
if (processed.contains(origin)) if (otherProcessed.contains(origin))
break; break;
processed.insert(origin); otherProcessed.insert(origin);
origin = origin->parent(); origin = origin->parent();
} }
@@ -1310,7 +1312,7 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
// Another template that uses the dependent name. // Another template that uses the dependent name.
// Ex.: template <class T> class A : public B<T> {}; // Ex.: template <class T> class A : public B<T> {};
if (baseTemplId->identifier() != templId->identifier()) if (baseTemplId->identifier() != templId->identifier())
baseBinding = nestedType(baseName, origin); baseBinding = nestedType(baseName, processed, origin);
} else if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) { } else if (const QualifiedNameId *qBaseName = baseName->asQualifiedNameId()) {
// Qualified names in general. // Qualified names in general.
// Ex.: template <class T> class A : public B<T>::Type {}; // Ex.: template <class T> class A : public B<T>::Type {};
@@ -1361,7 +1363,8 @@ ClassOrNamespace *ClassOrNamespace::nestedType(const Name *name, ClassOrNamespac
} }
if (binding) { if (binding) {
ClassOrNamespace * baseBinding = binding->lookupType(baseName); ClassOrNamespace * baseBinding
= binding->lookupType_helper(baseName, processed, true, this);
if (baseBinding && !knownUsings.contains(baseBinding)) if (baseBinding && !knownUsings.contains(baseBinding))
reference->addUsing(baseBinding); reference->addUsing(baseBinding);
} }
@@ -1518,7 +1521,8 @@ ClassOrNamespace *ClassOrNamespace::findOrCreateType(const Name *name, ClassOrNa
return findOrCreateType(q->base(), origin)->findOrCreateType(q->name(), origin, clazz); return findOrCreateType(q->base(), origin)->findOrCreateType(q->name(), origin, clazz);
} else if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) { } else if (name->isNameId() || name->isTemplateNameId() || name->isAnonymousNameId()) {
ClassOrNamespace *e = nestedType(name, origin); QSet<ClassOrNamespace *> processed;
ClassOrNamespace *e = nestedType(name, &processed, origin);
if (! e) { if (! e) {
e = _factory->allocClassOrNamespace(this); e = _factory->allocClassOrNamespace(this);

View File

@@ -121,7 +121,8 @@ private:
ClassOrNamespace *findBlock_helper(Block *block, QSet<ClassOrNamespace *> *processed, ClassOrNamespace *findBlock_helper(Block *block, QSet<ClassOrNamespace *> *processed,
bool searchInEnclosingScope); bool searchInEnclosingScope);
ClassOrNamespace *nestedType(const Name *name, ClassOrNamespace *origin); ClassOrNamespace *nestedType(const Name *name, QSet<ClassOrNamespace *> *processed,
ClassOrNamespace *origin);
void instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass, void instantiateNestedClasses(ClassOrNamespace *enclosingTemplateClass,
Clone &cloner, Clone &cloner,