forked from qt-creator/qt-creator
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:
@@ -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);
|
||||||
|
@@ -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,
|
||||||
|
Reference in New Issue
Block a user