1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-13 11:15:38 +02:00

Bug 316704: Exponential complexity resolving template argument ambiguity.

This commit is contained in:
Markus Schorn 2010-06-18 14:38:24 +00:00
parent 2f75332ece
commit 19768142fd
4 changed files with 81 additions and 26 deletions

View file

@ -4994,4 +4994,18 @@ public class AST2TemplateTests extends AST2BaseTest {
assertEquals(1, names.length); assertEquals(1, names.length);
assertEquals("CT<char, char>", names[0].toString()); assertEquals("CT<char, char>", names[0].toString());
} }
public void testBug316704() throws Exception {
StringBuilder code= new StringBuilder("typedef if_< bool,");
for (int i = 0; i < 50; i++) {
code.append('\n').append("if_<bool,");
}
code.append("int_<0>,");
for (int i = 0; i < 50; i++) {
code.append('\n').append("int_<0> >::type,");
}
code.append("int_<0> >::type tdef;");
IASTTranslationUnit tu= parse(code.toString(), ParserLanguage.CPP, true, true);
assertEquals(1, tu.getDeclarations().length);
}
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2004, 2009 IBM Corporation and others. * Copyright (c) 2004, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -65,6 +65,9 @@ public abstract class ASTAmbiguousNode extends ASTNode {
protected void beforeResolution() { protected void beforeResolution() {
} }
protected void beforeAlternative(IASTNode alternative) {
}
protected void afterResolution(ASTVisitor resolver, IASTNode best) { protected void afterResolution(ASTVisitor resolver, IASTNode best) {
} }
@ -78,6 +81,8 @@ public abstract class ASTAmbiguousNode extends ASTNode {
int minIssues = Integer.MAX_VALUE; int minIssues = Integer.MAX_VALUE;
for (IASTNode alternative : alternatives) { for (IASTNode alternative : alternatives) {
beforeAlternative(alternative);
// setup the ast to use the alternative // setup the ast to use the alternative
owner.replace(nodeToReplace, alternative); owner.replace(nodeToReplace, alternative);
nodeToReplace= alternative; nodeToReplace= alternative;
@ -134,7 +139,7 @@ public abstract class ASTAmbiguousNode extends ASTNode {
return bestAlternative; return bestAlternative;
} }
public boolean isLValue() { public boolean isLValue() {
return false; return false;
} }
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008, 2009 Symbian Software Systems and others. * Copyright (c) 2008, 2010 Symbian Software Systems and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
@ -15,8 +15,12 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument;
@ -53,6 +57,33 @@ public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements
} }
} }
@Override
protected void beforeAlternative(IASTNode node) {
// The name may be shared between the alternatives make sure it's parent is set correctly
if (node instanceof IASTTypeId) {
IASTDeclSpecifier declSpec = ((IASTTypeId) node).getDeclSpecifier();
if (declSpec instanceof IASTNamedTypeSpecifier) {
IASTNamedTypeSpecifier namedTypeSpec= (IASTNamedTypeSpecifier) declSpec;
final IASTName name = namedTypeSpec.getName();
name.setBinding(null);
namedTypeSpec.setName(name);
}
} else if (node instanceof IASTIdExpression) {
IASTIdExpression id= (IASTIdExpression) node;
final IASTName name = id.getName();
name.setBinding(null);
id.setName(name);
}
}
@Override
protected void afterResolution(ASTVisitor resolver, IASTNode best) {
beforeAlternative(best);
}
public IASTNode copy() { public IASTNode copy() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View file

@ -559,34 +559,37 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// This is potentially a type-id, now check ambiguity with id-expression // This is potentially a type-id, now check ambiguity with id-expression
IASTDeclSpecifier declspec= typeId.getDeclSpecifier(); IASTDeclSpecifier declspec= typeId.getDeclSpecifier();
if (declspec instanceof IASTNamedTypeSpecifier) { if (declspec instanceof IASTNamedTypeSpecifier) {
IASTName name= ((IASTNamedTypeSpecifier) declspec).getName(); final IASTNamedTypeSpecifier namedDeclspec = (IASTNamedTypeSpecifier) declspec;
IASTName name= namedDeclspec.getName();
if (name.contains(typeId)) { if (name.contains(typeId)) {
// A template-id cannot be used in an id-expression as a template argument // A template-id cannot be used in an id-expression as a template argument
// 5.1-11 A template-id shall be used as an unqualified-id only as specified in // 5.1-11 A template-id shall be used as an unqualified-id only as specified in
// 14.7.2, 14.7, and 14.5.4. // 14.7.2, 14.7, and 14.5.4.
name= name.getLastName(); if (!(name.getLastName() instanceof ICPPASTTemplateId)) {
if (!(name instanceof ICPPASTTemplateId)) {
IToken typeIdEnd= mark(); IToken typeIdEnd= mark();
backup(argStart); IASTIdExpression idExpr= setRange(nodeFactory.newIdExpression(name), name);
try { try {
IASTExpression expression = expression(ExprKind.eAssignment, exprCtx); IASTExpression expression = expression(ExprKind.eAssignment, exprCtx, idExpr);
if (expression instanceof IASTIdExpression) { boolean isAmbiguous= (expression == idExpr);
if (mark() == typeIdEnd) { if (LT(1) == IToken.tELLIPSIS) {
if (LT(1) == IToken.tELLIPSIS) { IToken ellipsis= consume();
IToken ellipsis= consume(); if (isAmbiguous) {
addPackExpansion(typeId, ellipsis); addPackExpansion(typeId, ellipsis);
expression= addPackExpansion(expression, ellipsis);
}
ICPPASTAmbiguousTemplateArgument ambiguity= createAmbiguousTemplateArgument();
ambiguity.addTypeId(typeId);
ambiguity.addIdExpression(expression);
return ambiguity;
} }
expression= addPackExpansion(expression, ellipsis);
} }
if (isAmbiguous) {
ICPPASTAmbiguousTemplateArgument ambiguity= createAmbiguousTemplateArgument();
ambiguity.addTypeId(typeId);
ambiguity.addIdExpression(expression);
return ambiguity;
}
return expression;
} catch (BacktrackException e) { } catch (BacktrackException e) {
// Use the typeId // Use the typeId
} }
backup(typeIdEnd); backup(typeIdEnd);
namedDeclspec.setName(name);
} }
} }
} }
@ -599,7 +602,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// Not a type-id, parse as expression // Not a type-id, parse as expression
backup(argStart); backup(argStart);
IASTExpression expr= expression(ExprKind.eAssignment, exprCtx); IASTExpression expr= expression(ExprKind.eAssignment, exprCtx, null);
if (LT(1) == IToken.tELLIPSIS) { if (LT(1) == IToken.tELLIPSIS) {
expr= addPackExpansion(expr, consume()); expr= addPackExpansion(expr, consume());
} }
@ -683,15 +686,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
@Override @Override
protected IASTExpression expression() throws BacktrackException, EndOfFileException { protected IASTExpression expression() throws BacktrackException, EndOfFileException {
return expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID); return expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID, null);
} }
@Override @Override
protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException { protected IASTExpression constantExpression() throws BacktrackException, EndOfFileException {
return expression(ExprKind.eConstant, BinaryExprCtx.eNoTmplID); return expression(ExprKind.eConstant, BinaryExprCtx.eNoTmplID, null);
} }
private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx) throws EndOfFileException, BacktrackException { private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr) throws EndOfFileException, BacktrackException {
final boolean allowComma= kind==ExprKind.eExpression; final boolean allowComma= kind==ExprKind.eExpression;
boolean allowAssignment= kind !=ExprKind.eConstant; boolean allowAssignment= kind !=ExprKind.eConstant;
final CastExprCtx castCtx= ctx == BinaryExprCtx.eNoTmplID ? CastExprCtx.eBExpr : CastExprCtx.eBExprInTmplID; final CastExprCtx castCtx= ctx == BinaryExprCtx.eNoTmplID ? CastExprCtx.eBExpr : CastExprCtx.eBExprInTmplID;
@ -703,7 +706,9 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
int lt1; int lt1;
int conditionCount= 0; int conditionCount= 0;
BinaryOperator lastOperator= null; BinaryOperator lastOperator= null;
IASTInitializerClause expr= castExpression(castCtx); if (expr == null) {
expr= castExpression(castCtx);
}
loop: while(true) { loop: while(true) {
// Typically after a binary operator there cannot be a throw expression // Typically after a binary operator there cannot be a throw expression
@ -1376,7 +1381,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
} }
t = consume(); t = consume();
int finalOffset= 0; int finalOffset= 0;
IASTExpression lhs= expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID); // instead of expression(), to keep the stack smaller IASTExpression lhs= expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID, null); // instead of expression(), to keep the stack smaller
switch (LT(1)) { switch (LT(1)) {
case IToken.tRPAREN: case IToken.tRPAREN:
case IToken.tEOC: case IToken.tEOC:
@ -2947,7 +2952,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// assignment expression // assignment expression
final BinaryExprCtx ctx = fInTemplateParameterList ? BinaryExprCtx.eTmplID : BinaryExprCtx.eNoTmplID; final BinaryExprCtx ctx = fInTemplateParameterList ? BinaryExprCtx.eTmplID : BinaryExprCtx.eNoTmplID;
IASTExpression assignmentExpression = expression(ExprKind.eAssignment, ctx); IASTExpression assignmentExpression = expression(ExprKind.eAssignment, ctx, null);
if (allowSkipping && skipTrivialExpressionsInAggregateInitializers) { if (allowSkipping && skipTrivialExpressionsInAggregateInitializers) {
if (!ASTQueries.canContainName(assignmentExpression)) if (!ASTQueries.canContainName(assignmentExpression))
return null; return null;