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:
parent
9e3bca14b5
commit
c1b801b036
4 changed files with 100 additions and 49 deletions
|
@ -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 {
|
||||
|
|
|
@ -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)}.
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue