mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 529696 - Propagate the template-id strategy into names contained within a type template argument
This avoids expontential complexity when type template arguments inside an ambiguous name specifier themselves contain ambiguous name specifiers. The patch also enhances TemplateIdStrategy to allow marking and backing up to a branch point, and uses this ability in templateArgument(). Change-Id: Ia03e9cd0bc026b02b85edc05ed327cce883d6a59
This commit is contained in:
parent
88da6c08bb
commit
a4599f7c36
5 changed files with 66 additions and 13 deletions
|
@ -10537,4 +10537,18 @@ public class AST2TemplateTests extends AST2CPPTestBase {
|
|||
IType waldo = helper.assertNonProblem("Waldo");
|
||||
assertSameType(CommonCPPTypes.void_, waldo);
|
||||
}
|
||||
|
||||
// template <int, int, int, int, int, int, int, int> int constant8f();
|
||||
//
|
||||
// template <int i0, int i1, int i2, int i3>
|
||||
// void foo() {
|
||||
// constant8f<
|
||||
// i0 < 0, i0 < 0,
|
||||
// i1 < 0, i1 < 0,
|
||||
// i2 < 0, i2 < 0,
|
||||
// i3 < 0, i3 < 0>();
|
||||
// }
|
||||
public void testTemplateIdAmbiguity_529696() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1631,19 +1631,32 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
|
||||
protected abstract IASTDeclaration declaration(DeclarationOptions option) throws BacktrackException, EndOfFileException;
|
||||
|
||||
protected Decl declSpecifierSeq(DeclarationOptions option) throws BacktrackException, EndOfFileException {
|
||||
return declSpecifierSeq(option, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses for two alternatives of a declspec sequence. If there is a second alternative the token after the second alternative
|
||||
* is returned, such that the parser can continue after both variants.
|
||||
*/
|
||||
protected abstract Decl declSpecifierSeq(DeclarationOptions option) throws BacktrackException, EndOfFileException;
|
||||
protected abstract Decl declSpecifierSeq(DeclarationOptions option, ITemplateIdStrategy strat)
|
||||
throws BacktrackException, EndOfFileException;
|
||||
|
||||
protected Decl declSpecifierSequence_initDeclarator(final DeclarationOptions option,
|
||||
boolean acceptCompoundWithoutDtor)
|
||||
throws EndOfFileException, FoundAggregateInitializer, BacktrackException {
|
||||
return declSpecifierSequence_initDeclarator(option, acceptCompoundWithoutDtor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses for two alternatives of a declspec sequence followed by a initDeclarator.
|
||||
* A second alternative is accepted only, if it ends at the same point of the first alternative. Otherwise the
|
||||
* longer alternative is selected.
|
||||
*/
|
||||
protected Decl declSpecifierSequence_initDeclarator(final DeclarationOptions option, boolean acceptCompoundWithoutDtor) throws EndOfFileException, FoundAggregateInitializer, BacktrackException {
|
||||
Decl result= declSpecifierSeq(option);
|
||||
protected Decl declSpecifierSequence_initDeclarator(final DeclarationOptions option,
|
||||
boolean acceptCompoundWithoutDtor, ITemplateIdStrategy strat)
|
||||
throws EndOfFileException, FoundAggregateInitializer, BacktrackException {
|
||||
Decl result= declSpecifierSeq(option, strat);
|
||||
|
||||
final int lt1 = LTcatchEOF(1);
|
||||
if (lt1 == IToken.tEOC)
|
||||
|
|
|
@ -911,7 +911,8 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
|
|||
SHORT=0x10, UNSIGNED= 0x20, SIGNED=0x40, COMPLEX=0x80, IMAGINARY=0x100;
|
||||
|
||||
@Override
|
||||
protected Decl declSpecifierSeq(final DeclarationOptions declOption) throws BacktrackException, EndOfFileException {
|
||||
protected Decl declSpecifierSeq(final DeclarationOptions declOption, ITemplateIdStrategy strat)
|
||||
throws BacktrackException, EndOfFileException {
|
||||
int storageClass= IASTDeclSpecifier.sc_unspecified;
|
||||
int simpleType= IASTSimpleDeclSpecifier.t_unspecified;
|
||||
int options= 0;
|
||||
|
|
|
@ -751,10 +751,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
IToken argStart = mark();
|
||||
int markBranchPoint = ((TemplateIdStrategy) strat).getCurrentBranchPoint();
|
||||
ICPPASTTypeId typeId= null;
|
||||
int lt1= 0;
|
||||
try {
|
||||
typeId= typeId(DeclarationOptions.TYPEID);
|
||||
typeId= typeId(DeclarationOptions.TYPEID, strat);
|
||||
lt1 = LT(1);
|
||||
} catch (BacktrackException e) {
|
||||
if (e.isFatal()) {
|
||||
|
@ -849,6 +850,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
// Not a type-id, parse as expression.
|
||||
backup(argStart);
|
||||
((TemplateIdStrategy) strat).backupToBranchPoint(markBranchPoint);
|
||||
IASTExpression expr= expression(ExprKind.eAssignment, BinaryExprCtx.eInTemplateID, null, strat);
|
||||
if (LT(1) == IToken.tELLIPSIS) {
|
||||
expr= addPackExpansion(expr, consume());
|
||||
|
@ -3050,21 +3052,23 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
* {"enum"} enumSpecifier
|
||||
*/
|
||||
@Override
|
||||
protected Decl declSpecifierSeq(final DeclarationOptions option) throws BacktrackException, EndOfFileException {
|
||||
return declSpecifierSeq(option, false);
|
||||
protected Decl declSpecifierSeq(final DeclarationOptions option, ITemplateIdStrategy strat)
|
||||
throws BacktrackException, EndOfFileException {
|
||||
return declSpecifierSeq(option, false, strat);
|
||||
}
|
||||
|
||||
private ICPPASTDeclSpecifier simpleTypeSpecifier() throws BacktrackException, EndOfFileException {
|
||||
Decl d= declSpecifierSeq(null, true);
|
||||
Decl d= declSpecifierSeq(null, true, null);
|
||||
return (ICPPASTDeclSpecifier) d.fDeclSpec1;
|
||||
}
|
||||
|
||||
private ICPPASTDeclSpecifier simpleTypeSpecifierSequence() throws BacktrackException, EndOfFileException {
|
||||
Decl d= declSpecifierSeq(null, false);
|
||||
Decl d= declSpecifierSeq(null, false, null);
|
||||
return (ICPPASTDeclSpecifier) d.fDeclSpec1;
|
||||
}
|
||||
|
||||
private Decl declSpecifierSeq(final DeclarationOptions option, final boolean single) throws BacktrackException, EndOfFileException {
|
||||
private Decl declSpecifierSeq(final DeclarationOptions option, final boolean single,
|
||||
ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
|
||||
int storageClass = IASTDeclSpecifier.sc_unspecified;
|
||||
int simpleType = IASTSimpleDeclSpecifier.t_unspecified;
|
||||
int options= 0;
|
||||
|
@ -3324,7 +3328,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
}
|
||||
}
|
||||
|
||||
identifier= qualifiedName();
|
||||
identifier= qualifiedName(CastExprCtx.eNotInBExpr, strat);
|
||||
if (identifier.getLookupKey().length == 0 && LT(1) != IToken.tEOC)
|
||||
throwBacktrack(LA(1));
|
||||
|
||||
|
@ -4161,6 +4165,11 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
@Override
|
||||
protected ICPPASTTypeId typeId(DeclarationOptions option) throws EndOfFileException, BacktrackException {
|
||||
return typeId(option, null);
|
||||
}
|
||||
|
||||
protected ICPPASTTypeId typeId(DeclarationOptions option, ITemplateIdStrategy strat)
|
||||
throws EndOfFileException, BacktrackException {
|
||||
if (!canBeTypeSpecifier()) {
|
||||
throwBacktrack(LA(1));
|
||||
}
|
||||
|
@ -4169,7 +4178,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
IASTDeclarator declarator = null;
|
||||
|
||||
try {
|
||||
Decl decl= declSpecifierSequence_initDeclarator(option, false);
|
||||
Decl decl= declSpecifierSequence_initDeclarator(option, false, strat);
|
||||
declSpecifier= decl.fDeclSpec1;
|
||||
declarator= decl.fDtor1;
|
||||
} catch (FoundAggregateInitializer lie) {
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITem
|
|||
* When parsing, we potentially need to consider both possibilities for each use of '<'.
|
||||
*
|
||||
* An instance of this class is used to track alternative parses in a segment of code that includes one or
|
||||
* more uses of '<' preceded by names. An alternative consists of a choices (template-id or not) for each
|
||||
* more uses of '<' preceded by names. An alternative consists of a choice (template-id or not) for each
|
||||
* name. At a given point in time, the instance has a notion of a current alternative, and a current
|
||||
* position within that alternative.
|
||||
*
|
||||
|
@ -145,4 +145,20 @@ final class TemplateIdStrategy implements ITemplateIdStrategy {
|
|||
public IASTName[] getTemplateNames() {
|
||||
return ArrayUtil.trim(fTemplateNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes, a BacktrackException can be thrown and handled during the processing
|
||||
* of a single alternative (that is, the exception does not bubble up all the way
|
||||
* to the point where setNextAlternative() would be called). In such a case, when
|
||||
* backtracking we need to restore the branch point that was active at the point
|
||||
* we're backing up to (otherwise, the current branch point could get out of sync
|
||||
* with the parsing position). These methods facilitate marking and backing up to
|
||||
* the current branch point for such situations.
|
||||
*/
|
||||
public int getCurrentBranchPoint() {
|
||||
return fCurrentBranchPoint;
|
||||
}
|
||||
public void backupToBranchPoint(int branchPoint) {
|
||||
fCurrentBranchPoint = branchPoint;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue