1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-14 20:45:22 +02:00

Bug 485388 - Ambiguity resolution of method bodies of nested classes

They can depend on members of enclosing classes, so their processing
needs to wait until the end of the outermost class definition.

Change-Id: Ie714d8410bb7a474bcc8dfab0bc09fcc89450598
Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
Nathan Ridge 2016-01-12 17:04:47 -05:00 committed by Gerrit Code Review @ Eclipse.org
parent 082dae21c3
commit 3d814869df
2 changed files with 55 additions and 45 deletions

View file

@ -8955,6 +8955,23 @@ public class AST2TemplateTests extends AST2TestBase {
parseAndCheckBindings();
}
// template <typename> struct S {};
// struct U {};
//
// struct outer {
// struct inner {
// S<U> foo() {
// return waldo<42>(0);
// }
// };
//
// template <int>
// static S<U> waldo(int);
// };
public void testAmbiguityResolutionInNestedClassMethodBody_485388() throws Exception {
parseAndCheckBindings();
}
// template <typename>
// struct Base {
// template <typename>

View file

@ -14,7 +14,6 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
@ -48,9 +47,18 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
*/
final class CPPASTAmbiguityResolver extends ASTVisitor {
private int fSkipInitializers= 0;
private int fDeferFunctions= 1;
/*
* The current nesting level of class definitions.
* Used to handle processing of method bodies, which are deferred
* until the end of the outermost class definition.
*/
private int fClassNestingLevel= 0;
private HashSet<IASTDeclaration> fRepopulate= new HashSet<>();
private Deque<Deque<IASTNode>> fDeferredNodes= new ArrayDeque<>();
/*
* Nodes that have been deferred for later processing.
* Currently used only for method bodies.
*/
private Deque<IASTNode> fDeferredNodes = new ArrayDeque<>();
public CPPASTAmbiguityResolver() {
super(false);
@ -98,8 +106,7 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
fDeferFunctions++;
fDeferredNodes.add(new ArrayDeque<IASTNode>());
fClassNestingLevel++;
}
return PROCESS_CONTINUE;
}
@ -107,7 +114,7 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
@Override
public int leave(IASTDeclSpecifier declSpec) {
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
fDeferFunctions--;
fClassNestingLevel--;
// Resolve class type definitions, such that the scope is available
// during ambiguity resolution.
@ -117,14 +124,20 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
if (declSpec instanceof CPPASTCompositeTypeSpecifier)
((CPPASTCompositeTypeSpecifier) declSpec).setAmbiguitiesResolved();
processDeferredNodes(fDeferredNodes.removeLast());
// If we are leaving the outermost class, process the bodies of
// methods of the class and its nested classes.
if (fClassNestingLevel == 0) {
while (!fDeferredNodes.isEmpty()) {
fDeferredNodes.removeFirst().accept(this);
}
}
}
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTDeclaration decl) {
if (fDeferFunctions > 0 && decl instanceof IASTFunctionDefinition) {
if (fClassNestingLevel > 0 && decl instanceof IASTFunctionDefinition) {
final IASTFunctionDefinition fdef= (IASTFunctionDefinition) decl;
// Visit the declarator first, it may contain ambiguous template arguments needed
@ -140,7 +153,7 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
trailingReturnType.accept(this);
}
// Defer visiting the body of the function until the class body has been visited.
fDeferredNodes.getLast().add(decl);
fDeferredNodes.add(decl);
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
@ -187,33 +200,15 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTTranslationUnit tu) {
fDeferredNodes.add(new ArrayDeque<IASTNode>());
return PROCESS_CONTINUE;
}
@Override
public int leave(IASTTranslationUnit tu) {
fDeferFunctions= 0;
while (!fDeferredNodes.isEmpty()) {
processDeferredNodes(fDeferredNodes.removeLast());
}
// As deferred method bodies are processed at the end of outermost
// class definitions, there should be none left when the end of
// the translation unit is reached.
assert fDeferredNodes.isEmpty();
return PROCESS_CONTINUE;
}
private void processDeferredNodes(Deque<IASTNode> deferredNodes) {
int deferFunctions = fDeferFunctions;
fDeferFunctions = 0;
try {
while (!deferredNodes.isEmpty()) {
deferredNodes.removeFirst().accept(this);
}
} finally {
fDeferFunctions = deferFunctions;
}
}
private void repopulateScope(IASTDeclaration declaration) {
IScope scope= CPPVisitor.getContainingNonTemplateScope(declaration);
if (scope instanceof ICPPASTInternalScope) {
@ -232,21 +227,19 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
* If 'node' has been deferred for later processing, process it now.
*/
public void resolvePendingAmbiguities(IASTNode node) {
Iterator<Deque<IASTNode>> iterator = fDeferredNodes.descendingIterator();
while (iterator.hasNext()) {
Deque<IASTNode> deferred = iterator.next();
for (IASTNode deferredNode : deferred) {
if (deferredNode == node) {
int deferFunctions = fDeferFunctions;
fDeferFunctions = 0;
try {
deferredNode.accept(this);
} finally {
fDeferFunctions = deferFunctions;
}
deferred.remove(deferredNode);
break;
for (IASTNode deferredNode : fDeferredNodes) {
if (deferredNode == node) {
// Temporarily set the class nesting level to 0,
// to prevent the node just being deferred again.
int classNestingLevel = fClassNestingLevel;
fClassNestingLevel = 0;
try {
deferredNode.accept(this);
} finally {
fClassNestingLevel = classNestingLevel;
}
fDeferredNodes.remove(deferredNode);
break;
}
}
}