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:
parent
1f4650fb61
commit
93285e7f68
5 changed files with 138 additions and 49 deletions
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue