1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-29 03:45:35 +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())); assertEquals("bool", ASTTypeUtil.getType(td.getType()));
ah.assertProblem("B<int*>::type", "type"); 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> // template <typename From>
// struct is_convertible { // 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 * Add an partial parse tree that could be a suitable subtree representing
* the template argument * the template argument
* @param idExpression a non-null id-expression or a pack expansion of an id-expression * @param expression a non-null expression
* @since 5.2 * @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 * Add an partial parse tree that could be a suitable subtree representing
* the template argument * the template argument
@ -38,6 +38,12 @@ public interface ICPPASTAmbiguousTemplateArgument extends IASTNode {
*/ */
public void addTypeId(IASTTypeId typeId); public void addTypeId(IASTTypeId typeId);
/**
* @deprecated Replaced by {@link #addExpression(IASTExpression)}.
*/
@Deprecated
public void addIdExpression(IASTExpression idExpression);
/** /**
* @deprecated Replaced by {@link #addIdExpression(IASTExpression)}. * @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; 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 { public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements ICPPASTAmbiguousTemplateArgument {
private List<IASTNode> fNodes; private List<IASTNode> fNodes;
@ -43,15 +43,8 @@ public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements
public CPPASTAmbiguousTemplateArgument(IASTNode... nodes) { public CPPASTAmbiguousTemplateArgument(IASTNode... nodes) {
fNodes= new ArrayList<IASTNode>(2); fNodes= new ArrayList<IASTNode>(2);
for (IASTNode node : nodes) { for (IASTNode node : nodes) {
if (node instanceof IASTTypeId || node instanceof IASTIdExpression) { if (node instanceof IASTTypeId || node instanceof IASTExpression) {
fNodes.add(node); 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 { } else {
Assert.isLegal(false, node == null ? "null" : node.getClass().getName()); //$NON-NLS-1$ Assert.isLegal(false, node == null ? "null" : node.getClass().getName()); //$NON-NLS-1$
} }
@ -60,7 +53,9 @@ public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements
@Override @Override
protected void beforeAlternative(IASTNode node) { 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) { if (node instanceof IASTTypeId) {
IASTDeclSpecifier declSpec = ((IASTTypeId) node).getDeclSpecifier(); IASTDeclSpecifier declSpec = ((IASTTypeId) node).getDeclSpecifier();
if (declSpec instanceof IASTNamedTypeSpecifier) { if (declSpec instanceof IASTNamedTypeSpecifier) {
@ -122,16 +117,20 @@ public class CPPASTAmbiguousTemplateArgument extends ASTAmbiguousNode implements
addNode(typeId); addNode(typeId);
} }
@Override
public void addExpression(IASTExpression expression) {
assertNotFrozen();
addNode(expression);
}
@Override @Override
public void addIdExpression(IASTIdExpression idExpression) { public void addIdExpression(IASTIdExpression idExpression) {
assertNotFrozen(); addExpression(idExpression);
addNode(idExpression);
} }
@Override @Override
public void addIdExpression(IASTExpression idExpression) { public void addIdExpression(IASTExpression idExpression) {
assertNotFrozen(); addExpression(idExpression);
addNode(idExpression);
} }
private void addNode(IASTNode node) { private void addNode(IASTNode node) {

View file

@ -658,46 +658,78 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (typeId != null if (typeId != null
&& (lt1 == IToken.tCOMMA || lt1 == IToken.tGT || lt1 == IToken.tGT_in_SHIFTR && (lt1 == IToken.tCOMMA || lt1 == IToken.tGT || lt1 == IToken.tGT_in_SHIFTR
|| lt1 == IToken.tEOC || lt1 == IToken.tELLIPSIS)) { || lt1 == IToken.tEOC || lt1 == IToken.tELLIPSIS)) {
// This is potentially a type-id, now check ambiguity with id-expression // This is potentially a type-id, now check ambiguity with expression.
IASTDeclSpecifier declspec= typeId.getDeclSpecifier(); IToken typeIdEnd= mark();
if (declspec instanceof IASTNamedTypeSpecifier) { IASTNamedTypeSpecifier namedTypeSpec = null;
final IASTNamedTypeSpecifier namedDeclspec = (IASTNamedTypeSpecifier) declspec; IASTName name = null;
IASTName name= namedDeclspec.getName(); try {
if (name.contains(typeId)) { // If the type-id consists of a name, that name could be or contain
IToken typeIdEnd= mark(); // a template-id, with template arguments of its own, which can
IASTIdExpression idExpr= setRange(nodeFactory.newIdExpression(name), name); // themselves be ambiguous. If we parse the name anew as an
try { // id-expression, our complexity becomes exponential in the nesting
IASTExpression expression = expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, idExpr, strat); // depth of template-ids (bug 316704). To avoid this, we do not
boolean isAmbiguous= (expression == idExpr); // re-parse the name, but instead synthesize an id-expression from
if (LT(1) == IToken.tELLIPSIS) { // it, and then continue parsing an expression from the id-expression
IToken ellipsis= consume(); // onwards (as the id-expression could be the beginning of a larger
if (isAmbiguous) { // expression).
addPackExpansion(typeId, ellipsis); IASTIdExpression idExpression = null;
} IASTDeclSpecifier declSpec = typeId.getDeclSpecifier();
expression= addPackExpansion(expression, ellipsis); if (declSpec instanceof IASTNamedTypeSpecifier) {
} namedTypeSpec = (IASTNamedTypeSpecifier) declSpec;
if (isAmbiguous) { name = namedTypeSpec.getName();
ICPPASTAmbiguousTemplateArgument ambiguity= createAmbiguousTemplateArgument(); if (name.contains(typeId)) {
ambiguity.addTypeId(typeId); idExpression = setRange(nodeFactory.newIdExpression(name), name);
ambiguity.addIdExpression(expression);
return ambiguity;
}
return expression;
} catch (BacktrackException e) {
// Use the typeId
} }
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) { if (LT(1) == IToken.tELLIPSIS) {
addPackExpansion(typeId, consume()); addPackExpansion(typeId, consume());
} }
return typeId; return typeId;
} }
// Not a type-id, parse as expression // Not a type-id, parse as expression.
backup(argStart); backup(argStart);
IASTExpression expr= expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, null, strat); IASTExpression expr= expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, null, strat);
if (LT(1) == IToken.tELLIPSIS) { if (LT(1) == IToken.tELLIPSIS) {