1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 363609: Performance issue with nested template ambiguities.

This commit is contained in:
Markus Schorn 2011-11-28 07:54:30 +01:00
parent 1f4650fb61
commit 93285e7f68
5 changed files with 138 additions and 49 deletions

View file

@ -5583,4 +5583,26 @@ public class AST2TemplateTests extends AST2BaseTest {
public void testDirectlyNestedAmbiguity_362976() throws Exception { public void testDirectlyNestedAmbiguity_362976() throws Exception {
parseAndCheckBindings(); parseAndCheckBindings();
} }
// template<typename T, T p1, T p2, T p3=T(), T p4=T(), T p5=T(),
// T p6=T(), T p7=T(), T p8=T(), T p9=T(), T p10=T(),
// T p11=T(), T p12=T(), T p13=T(), T p14=T(), T p15=T(),
// T p16=T(), T p17=T(), T p18=T(), T p19=T(), T p20=T()
// >
// struct MaxOfN {
// template<typename X, X x1, X x2> struct Max2 {
// static const X result = (x1>x2)?x1:x2;
// };
// static const T result = Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,
// (Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,(Max2<T,p1,p2>::result),
// p3>::result),p4>::result),p5>::result),p6>::result),p7>::result),p8>::result),
// p9>::result),p10>::result),p11>::result),p12>::result),p13>::result),p14>::result),
// p15>::result),p16>::result),p17>::result),p18>::result),p19>::result),p20>::result;
// };
// int main(){
// return MaxOfN<int,1,2>::result;
// }
public void testNestedTemplateAmbiguity_363609() throws Exception {
parseAndCheckBindings();
}
} }

View file

@ -243,7 +243,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
throw backtrack; throw backtrack;
} }
public IASTCompletionNode getCompletionNode() { @Override
public IASTCompletionNode getCompletionNode() {
return completionNode; return completionNode;
} }
@ -555,7 +556,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
parsePassed = false; parsePassed = false;
} }
public synchronized void cancel() { @Override
public synchronized void cancel() {
isCancelled = true; isCancelled = true;
} }
@ -642,7 +644,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
throwBacktrack(n.getOffset(), n.getLength()); throwBacktrack(n.getOffset(), n.getLength());
} }
public IASTTranslationUnit parse() { @Override
public IASTTranslationUnit parse() {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
translationUnit(); translationUnit();
log.traceLog("Parse " //$NON-NLS-1$ log.traceLog("Parse " //$NON-NLS-1$
@ -1173,22 +1176,27 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return fUnaryOperatorOffset; return fUnaryOperatorOffset;
} }
@Override
public IASTExpression copy() { public IASTExpression copy() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public IASTExpression copy(CopyStyle style) { public IASTExpression copy(CopyStyle style) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public IType getExpressionType() { public IType getExpressionType() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean isLValue() { public boolean isLValue() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public ValueCategory getValueCategory() { public ValueCategory getValueCategory() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -1198,11 +1206,14 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (LT(1) == IToken.tLPAREN) { if (LT(1) == IToken.tLPAREN) {
final IToken mark= mark(); final IToken mark= mark();
final int startingOffset= mark.getOffset(); final int startingOffset= mark.getOffset();
final boolean canBeCast= canBeCastExpression();
consume(); consume();
IASTTypeId typeId= null; IASTTypeId typeId= null;
try { if (canBeCast) {
typeId= typeId(DeclarationOptions.TYPEID); try {
} catch (BacktrackException e) { typeId= typeId(DeclarationOptions.TYPEID);
} catch (BacktrackException e) {
}
} }
if (typeId != null && LT(1) == IToken.tRPAREN) { if (typeId != null && LT(1) == IToken.tRPAREN) {
consume(); consume();
@ -1562,7 +1573,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
return skipProblemConditionInParenthesis(mark.getOffset()); return skipProblemConditionInParenthesis(mark.getOffset());
} }
public boolean encounteredError() { @Override
public boolean encounteredError() {
return !parsePassed; return !parsePassed;
} }
@ -2399,7 +2411,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
if (token.getType() == IGCCToken.t__declspec) { if (token.getType() == IGCCToken.t__declspec) {
consume(); consume();
if (LT(1) == IToken.tLPAREN) { if (LT(1) == IToken.tLPAREN) {
skipBrackets(IToken.tLPAREN, IToken.tRPAREN); skipBrackets(IToken.tLPAREN, IToken.tRPAREN, 0);
} }
} }
} }
@ -2433,24 +2445,68 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
} }
} }
/** protected boolean canBeCompoundLiteral() throws EndOfFileException {
* In case a cast expression is followed by +/- or & we should avoid it: IToken m= mark();
* (a)+1 vs. (int)+1; try {
* @since 4.0 // The parenthesis cannot be followed by a binary operator
*/ skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI);
protected boolean avoidCastExpressionByHeuristics() throws EndOfFileException { return LTcatchEOF(1) == IToken.tLBRACE;
if (LT(1) == IToken.tIDENTIFIER) { } catch (BacktrackException bt) {
if (LT(2) == IToken.tRPAREN) { return false;
switch (LT(3)) { } finally {
case IToken.tPLUS: backup(m);
case IToken.tMINUS: }
case IToken.tAMPER: }
case IToken.tSTAR:
return true; protected boolean canBeCastExpression() throws EndOfFileException {
} IToken m= mark();
} try {
// The parenthesis cannot be followed by a binary operator
skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI);
switch (LTcatchEOF(1)) {
case IToken.tAMPERASSIGN:
case IToken.tAND:
case IToken.tARROW:
case IToken.tARROWSTAR:
case IToken.tASSIGN:
case IToken.tBITOR:
case IToken.tBITORASSIGN:
case IToken.tCOLON:
case IToken.tCOMMA:
case IToken.tDIV:
case IToken.tDIVASSIGN:
case IToken.tDOT:
case IToken.tDOTSTAR:
case IToken.tEQUAL:
case IToken.tGT:
case IToken.tGT_in_SHIFTR:
case IToken.tGTEQUAL:
case IToken.tLBRACKET:
case IToken.tLTEQUAL:
case IToken.tMINUSASSIGN:
case IToken.tMOD:
case IToken.tMODASSIGN:
case IToken.tNOTEQUAL:
case IToken.tOR:
case IToken.tPLUSASSIGN:
case IToken.tQUESTION:
case IToken.tRBRACE:
case IToken.tRBRACKET:
case IToken.tRPAREN:
case IToken.tSEMI:
case IToken.tSHIFTL:
case IToken.tSHIFTLASSIGN:
case IToken.tSHIFTR:
case IToken.tSHIFTRASSIGN:
case IToken.tSTARASSIGN:
return false;
}
return true;
} catch (BacktrackException bt) {
return false;
} finally {
backup(m);
} }
return false;
} }
protected boolean canBeTypeSpecifier() throws EndOfFileException { protected boolean canBeTypeSpecifier() throws EndOfFileException {
@ -2511,12 +2567,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
} }
} }
protected void skipBrackets(int left, int right) throws EndOfFileException, BacktrackException { protected void skipBrackets(int left, int right, int terminator) throws EndOfFileException, BacktrackException {
consume(left); consume(left);
int nesting= 0; int nesting= 0;
while(true) { while(true) {
final int lt1= LT(1); final int lt1= LT(1);
if (lt1 == IToken.tEOC) if (lt1 == IToken.tEOC || lt1 == terminator)
throwBacktrack(LA(1)); throwBacktrack(LA(1));
consume(); consume();

View file

@ -1754,7 +1754,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
final IToken current = LA(1); final IToken current = LA(1);
int startingOffset = current.getOffset(); int startingOffset = current.getOffset();
if (current.getType() == IToken.tLBRACKET && supportParameterInfoBlock) { if (current.getType() == IToken.tLBRACKET && supportParameterInfoBlock) {
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET); skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0);
} }
IASTDeclSpecifier declSpec = null; IASTDeclSpecifier declSpec = null;

View file

@ -1454,14 +1454,16 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// ( type-name ) { initializer-list , } // ( type-name ) { initializer-list , }
IToken m = mark(); IToken m = mark();
try { try {
int offset = consume().getOffset(); if (canBeCompoundLiteral()) {
IASTTypeId t= typeId(DeclarationOptions.TYPEID); int offset = consume().getOffset();
consume(IToken.tRPAREN); IASTTypeId t= typeId(DeclarationOptions.TYPEID);
if (LT(1) == IToken.tLBRACE) { consume(IToken.tRPAREN);
IASTInitializer i = bracedInitList(false); if (LT(1) == IToken.tLBRACE) {
firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); IASTInitializer i = bracedInitList(false);
setRange(firstExpression, offset, calculateEndOffset(i)); firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i);
break; setRange(firstExpression, offset, calculateEndOffset(i));
break;
}
} }
} catch (BacktrackException bt) { } catch (BacktrackException bt) {
} }
@ -2568,7 +2570,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
final int startOffset= LA(1).getOffset(); final int startOffset= LA(1).getOffset();
if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) { if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) {
skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET); skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0);
} }
IASTDeclSpecifier declSpec= null; IASTDeclSpecifier declSpec= null;

View file

@ -14,6 +14,8 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.BitSet; import java.util.BitSet;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITemplateIdStrategy; import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITemplateIdStrategy;
@ -48,29 +50,36 @@ final class TemplateIdStrategy implements ITemplateIdStrategy {
} }
public boolean setNextAlternative() { public boolean setNextAlternative() {
final int bp = fCurrentBranchPoint; int bp = fCurrentBranchPoint;
if (bp < 0) if (bp < 0)
return false; return false;
fCurrentBranchPoint= -1; fCurrentBranchPoint= -1;
IASTName[] names = getTemplateNames();
int nameLen= names.length;
fTemplateNames= IASTName.EMPTY_NAME_ARRAY; fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
if (fSimpleIDs == null) { if (fSimpleIDs == null) {
fSimpleIDs= new BitSet(); fSimpleIDs= new BitSet();
} }
// Set a new branch as far right as possible. // Set a new branch as far right as possible.
final int len = fSimpleIDs.length(); while (bp >= 0) {
if (len <= bp) { if (!fSimpleIDs.get(bp)) {
fSimpleIDs.set(bp); if (nameLen == 0 || !hasMultipleArgs(names[--nameLen])) {
return true; fSimpleIDs.clear(bp+1, Integer.MAX_VALUE);
} fSimpleIDs.set(bp);
return true;
for (int branch= Math.min(bp, len-2); branch>=0; branch--) { }
if (!fSimpleIDs.get(branch)) {
fSimpleIDs.clear(branch+1, len);
fSimpleIDs.set(branch);
return true;
} }
bp--;
}
return false;
}
private boolean hasMultipleArgs(IASTName templateName) {
IASTNode parent= templateName.getParent();
if (parent instanceof ICPPASTTemplateId) {
return ((ICPPASTTemplateId) parent).getTemplateArguments().length > 1;
} }
return false; return false;
} }