1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Bug 332829 - Handle ambiguity between a type-id and an expression other

than an id-expression in a template argument

Change-Id: I1ec6157b09526a1f98850361f903fbea8b8c8a89
Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
Reviewed-on: https://git.eclipse.org/r/20140
Reviewed-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
IP-Clean: Sergey Prigogin <eclipse.sprigogin@gmail.com>
Tested-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
This commit is contained in:
Nathan Ridge 2013-12-20 03:12:13 -05:00 committed by Sergey Prigogin
parent 9e3bca14b5
commit c1b801b036
4 changed files with 100 additions and 49 deletions

View file

@ -7265,6 +7265,20 @@ public class AST2TemplateTests extends AST2TestBase {
assertEquals("bool", ASTTypeUtil.getType(td.getType()));
ah.assertProblem("B<int*>::type", "type");
}
// constexpr int f() { return 1; }
//
// template <int>
// struct A {
// static void g() {}
// };
//
// void bar() {
// A<f()>::g();
// }
public void testConstexprFunctionCallInTemplateArgument_332829() throws Exception {
parseAndCheckBindings();
}
// template <typename From>
// struct is_convertible {

View file

@ -26,11 +26,11 @@ public interface ICPPASTAmbiguousTemplateArgument extends IASTNode {
/**
* Add an partial parse tree that could be a suitable subtree representing
* the template argument
* @param idExpression a non-null id-expression or a pack expansion of an id-expression
* @since 5.2
* @param expression a non-null expression
* @since 5.6
*/
public void addIdExpression(IASTExpression idExpression);
public void addExpression(IASTExpression expression);
/**
* Add an partial parse tree that could be a suitable subtree representing
* the template argument
@ -38,6 +38,12 @@ public interface ICPPASTAmbiguousTemplateArgument extends IASTNode {
*/
public void addTypeId(IASTTypeId typeId);
/**
* @deprecated Replaced by {@link #addExpression(IASTExpression)}.
*/
@Deprecated
public void addIdExpression(IASTExpression idExpression);
/**
* @deprecated Replaced by {@link #addIdExpression(IASTExpression)}.
*/

View file

@ -31,7 +31,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.core.runtime.Assert;
/**
* Ambiguity node for deciding between type-id and id-expression in a template argument.
* Ambiguity node for deciding between type-id and expression in a template argument.
*/
public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements ICPPASTAmbiguousTemplateArgument {
private List<IASTNode> fNodes;
@ -43,15 +43,8 @@ public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements
public CPPASTAmbiguousTemplateArgument(IASTNode... nodes) {
fNodes= new ArrayList<IASTNode>(2);
for (IASTNode node : nodes) {
if (node instanceof IASTTypeId || node instanceof IASTIdExpression) {
if (node instanceof IASTTypeId || node instanceof IASTExpression) {
fNodes.add(node);
} else if (node instanceof ICPPASTPackExpansionExpression) {
final IASTExpression pattern = ((ICPPASTPackExpansionExpression) node).getPattern();
if (pattern instanceof IASTIdExpression) {
fNodes.add(node);
} else {
Assert.isLegal(false, pattern == null ? "null" : pattern.getClass().getName()); //$NON-NLS-1$
}
} else {
Assert.isLegal(false, node == null ? "null" : node.getClass().getName()); //$NON-NLS-1$
}
@ -60,7 +53,9 @@ 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 the expression is an id-expression, the name may be shared
// between the alternatives (see bug 316704), so make sure its parent
// is set correctly.
if (node instanceof IASTTypeId) {
IASTDeclSpecifier declSpec = ((IASTTypeId) node).getDeclSpecifier();
if (declSpec instanceof IASTNamedTypeSpecifier) {
@ -122,16 +117,20 @@ public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements
addNode(typeId);
}
@Override
public void addExpression(IASTExpression expression) {
assertNotFrozen();
addNode(expression);
}
@Override
public void addIdExpression(IASTIdExpression idExpression) {
assertNotFrozen();
addNode(idExpression);
addExpression(idExpression);
}
@Override
public void addIdExpression(IASTExpression idExpression) {
assertNotFrozen();
addNode(idExpression);
addExpression(idExpression);
}
private void addNode(IASTNode node) {

View file

@ -658,46 +658,78 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (typeId != null
&& (lt1 == IToken.tCOMMA || lt1 == IToken.tGT || lt1 == IToken.tGT_in_SHIFTR
|| lt1 == IToken.tEOC || lt1 == IToken.tELLIPSIS)) {
// This is potentially a type-id, now check ambiguity with id-expression
IASTDeclSpecifier declspec= typeId.getDeclSpecifier();
if (declspec instanceof IASTNamedTypeSpecifier) {
final IASTNamedTypeSpecifier namedDeclspec = (IASTNamedTypeSpecifier) declspec;
IASTName name= namedDeclspec.getName();
if (name.contains(typeId)) {
IToken typeIdEnd= mark();
IASTIdExpression idExpr= setRange(nodeFactory.newIdExpression(name), name);
try {
IASTExpression expression = expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, idExpr, strat);
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
// This is potentially a type-id, now check ambiguity with expression.
IToken typeIdEnd= mark();
IASTNamedTypeSpecifier namedTypeSpec = null;
IASTName name = null;
try {
// If the type-id consists of a name, that name could be or contain
// a template-id, with template arguments of its own, which can
// themselves be ambiguous. If we parse the name anew as an
// id-expression, our complexity becomes exponential in the nesting
// depth of template-ids (bug 316704). To avoid this, we do not
// re-parse the name, but instead synthesize an id-expression from
// it, and then continue parsing an expression from the id-expression
// onwards (as the id-expression could be the beginning of a larger
// expression).
IASTIdExpression idExpression = null;
IASTDeclSpecifier declSpec = typeId.getDeclSpecifier();
if (declSpec instanceof IASTNamedTypeSpecifier) {
namedTypeSpec = (IASTNamedTypeSpecifier) declSpec;
name = namedTypeSpec.getName();
if (name.contains(typeId)) {
idExpression = setRange(nodeFactory.newIdExpression(name), name);
}
backup(typeIdEnd);
namedDeclspec.setName(name);
}
// Parse an expression, starting with the id-expression synthesized
// above if there is one, otherwise starting from the beginning of
// the argument.
if (idExpression == null)
backup(argStart);
IASTExpression expression = expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, idExpression, strat);
// At this point we have a valid type-id and a valid expression.
// We prefer the longer one.
if (!typeId.contains(expression)) {
// The expression is longer.
if (LT(1) == IToken.tELLIPSIS) {
expression = addPackExpansion(expression, consume());
}
return expression;
} else if (expression.contains(typeId)) {
// The two are of the same length - ambiguous.
if (LT(1) == IToken.tELLIPSIS) {
IToken ellipsis = consume();
addPackExpansion(typeId, ellipsis);
expression = addPackExpansion(expression, ellipsis);
}
ICPPASTAmbiguousTemplateArgument ambiguity = createAmbiguousTemplateArgument();
ambiguity.addTypeId(typeId);
ambiguity.addExpression(expression);
return ambiguity;
}
// The type-id is longer, use it.
} catch (BacktrackException e) {
// Failed to parse an expression, use the type id.
}
// There is no ambiguity, use the type-id
// Clean up after our failed attempt to parse an expression.
backup(typeIdEnd);
if (name != null && namedTypeSpec != null) {
// When we synthesized the id-expression, it took ownership
// of the name. Give ownership back to the type-id.
namedTypeSpec.setName(name);
}
// Use the type-id.
if (LT(1) == IToken.tELLIPSIS) {
addPackExpansion(typeId, consume());
}
return typeId;
}
// Not a type-id, parse as expression
// Not a type-id, parse as expression.
backup(argStart);
IASTExpression expr= expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, null, strat);
if (LT(1) == IToken.tELLIPSIS) {