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("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
|
||||
* 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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue