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