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("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
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -65,6 +65,9 @@ public abstract class ASTAmbiguousNode extends ASTNode {
protected void beforeResolution() {
}
protected void beforeAlternative(IASTNode alternative) {
}
protected void afterResolution(ASTVisitor resolver, IASTNode best) {
}
@ -78,6 +81,8 @@ public abstract class ASTAmbiguousNode extends ASTNode {
int minIssues = Integer.MAX_VALUE;
for (IASTNode alternative : alternatives) {
beforeAlternative(alternative);
// setup the ast to use the alternative
owner.replace(nodeToReplace, alternative);
nodeToReplace= alternative;

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
* are made available under the terms of the Eclipse Public License v1.0
* 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.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.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.IASTTypeId;
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() {
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
IASTDeclSpecifier declspec= typeId.getDeclSpecifier();
if (declspec instanceof IASTNamedTypeSpecifier) {
IASTName name= ((IASTNamedTypeSpecifier) declspec).getName();
final IASTNamedTypeSpecifier namedDeclspec = (IASTNamedTypeSpecifier) declspec;
IASTName name= namedDeclspec.getName();
if (name.contains(typeId)) {
// 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
// 14.7.2, 14.7, and 14.5.4.
name= name.getLastName();
if (!(name instanceof ICPPASTTemplateId)) {
if (!(name.getLastName() instanceof ICPPASTTemplateId)) {
IToken typeIdEnd= mark();
backup(argStart);
IASTIdExpression idExpr= setRange(nodeFactory.newIdExpression(name), name);
try {
IASTExpression expression = expression(ExprKind.eAssignment, exprCtx);
if (expression instanceof IASTIdExpression) {
if (mark() == typeIdEnd) {
IASTExpression expression = expression(ExprKind.eAssignment, exprCtx, idExpr);
boolean isAmbiguous= (expression == idExpr);
if (LT(1) == IToken.tELLIPSIS) {
IToken ellipsis= consume();
if (isAmbiguous) {
addPackExpansion(typeId, ellipsis);
}
expression= addPackExpansion(expression, ellipsis);
}
if (isAmbiguous) {
ICPPASTAmbiguousTemplateArgument ambiguity= createAmbiguousTemplateArgument();
ambiguity.addTypeId(typeId);
ambiguity.addIdExpression(expression);
return ambiguity;
}
}
return expression;
} catch (BacktrackException e) {
// Use the typeId
}
backup(typeIdEnd);
namedDeclspec.setName(name);
}
}
}
@ -599,7 +602,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// Not a type-id, parse as expression
backup(argStart);
IASTExpression expr= expression(ExprKind.eAssignment, exprCtx);
IASTExpression expr= expression(ExprKind.eAssignment, exprCtx, null);
if (LT(1) == IToken.tELLIPSIS) {
expr= addPackExpansion(expr, consume());
}
@ -683,15 +686,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
@Override
protected IASTExpression expression() throws BacktrackException, EndOfFileException {
return expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID);
return expression(ExprKind.eExpression, BinaryExprCtx.eNoTmplID, null);
}
@Override
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;
boolean allowAssignment= kind !=ExprKind.eConstant;
final CastExprCtx castCtx= ctx == BinaryExprCtx.eNoTmplID ? CastExprCtx.eBExpr : CastExprCtx.eBExprInTmplID;
@ -703,7 +706,9 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
int lt1;
int conditionCount= 0;
BinaryOperator lastOperator= null;
IASTInitializerClause expr= castExpression(castCtx);
if (expr == null) {
expr= castExpression(castCtx);
}
loop: while(true) {
// Typically after a binary operator there cannot be a throw expression
@ -1376,7 +1381,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
}
t = consume();
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)) {
case IToken.tRPAREN:
case IToken.tEOC:
@ -2947,7 +2952,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// assignment expression
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 (!ASTQueries.canContainName(assignmentExpression))
return null;