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:
parent
2f75332ece
commit
19768142fd
4 changed files with 81 additions and 26 deletions
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue