mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-04 07:35:24 +02:00
Bug 364225: NPE in template ambiguity handling in delete expression.
This commit is contained in:
parent
c253ee2f96
commit
bc6ff322dc
4 changed files with 56 additions and 42 deletions
|
@ -5494,4 +5494,26 @@ public class AST2TemplateTests extends AST2BaseTest {
|
|||
final String code= getAboveComment();
|
||||
parseAndCheckBindings(code);
|
||||
}
|
||||
|
||||
// template<class T> struct A {
|
||||
// bool b;
|
||||
// };
|
||||
// class B {
|
||||
// };
|
||||
// template<class T> T * func();
|
||||
// void test1() {
|
||||
// delete func<A<B>>(); // This line causes the NPE
|
||||
// }
|
||||
//
|
||||
// template<bool> struct C {
|
||||
// int* ptr;
|
||||
// };
|
||||
// void test2() {
|
||||
// int a = 0, b = 1;
|
||||
// delete C< a<b >::ptr;
|
||||
// delete C< A<B>::b >::ptr;
|
||||
// }
|
||||
public void testTemplateAmbiguityInDeleteExpression_364225() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver;
|
|||
*/
|
||||
public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||
public interface ITemplateIdStrategy {
|
||||
boolean shallParseAsTemplateID(IASTName name);
|
||||
}
|
||||
|
||||
protected static class FoundAggregateInitializer extends Exception {
|
||||
|
|
|
@ -209,11 +209,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
}
|
||||
|
||||
private IASTName qualifiedName() throws BacktrackException, EndOfFileException {
|
||||
return ambiguousQualifiedName(CastExprCtx.eNotInBExpr);
|
||||
}
|
||||
|
||||
private IASTName ambiguousQualifiedName(CastExprCtx ctx) throws BacktrackException, EndOfFileException {
|
||||
TemplateIdStrategy strat= new TemplateIdStrategy();
|
||||
IToken m= mark();
|
||||
for(;;) {
|
||||
try {
|
||||
return qualifiedName(strat, CastExprCtx.eNotInBExpr);
|
||||
return qualifiedName(ctx, strat);
|
||||
} catch (BacktrackException e) {
|
||||
if (strat.setNextAlternative()) {
|
||||
backup(m);
|
||||
|
@ -227,8 +231,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
/**
|
||||
* Parses a qualified name.
|
||||
*/
|
||||
private IASTName qualifiedName(ITemplateIdStrategy s, CastExprCtx ctx) throws BacktrackException, EndOfFileException {
|
||||
final TemplateIdStrategy strat= (TemplateIdStrategy) s;
|
||||
private IASTName qualifiedName(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
|
||||
if (strat == null)
|
||||
return ambiguousQualifiedName(ctx);
|
||||
|
||||
ICPPASTQualifiedName qname= null;
|
||||
IASTName name= null;
|
||||
final int offset= LA(1).getOffset();
|
||||
|
@ -288,11 +294,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
if (haveArgs == -1) {
|
||||
templateID= false;
|
||||
} else if (haveArgs == 0) {
|
||||
if (strat.ignoreTemplateID()) {
|
||||
templateID= false;
|
||||
} else {
|
||||
strat.addTemplateName(name);
|
||||
}
|
||||
templateID= strat.shallParseAsTemplateID(name);
|
||||
}
|
||||
}
|
||||
if (templateID) {
|
||||
|
@ -350,7 +352,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return name;
|
||||
}
|
||||
|
||||
private IASTName addTemplateArguments(IASTName templateName, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private IASTName addTemplateArguments(IASTName templateName, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
// Parse for template arguments
|
||||
consume(IToken.tLT);
|
||||
List<IASTNode> list = templateArgumentList(strat);
|
||||
|
@ -566,7 +568,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
}
|
||||
}
|
||||
|
||||
private List<IASTNode> templateArgumentList(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private List<IASTNode> templateArgumentList(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
int startingOffset = LA(1).getOffset();
|
||||
int endOffset = 0;
|
||||
List<IASTNode> list= null;
|
||||
|
@ -596,7 +598,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return list;
|
||||
}
|
||||
|
||||
private IASTNode templateArgument(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
IToken argStart = mark();
|
||||
ICPPASTTypeId typeId= null;
|
||||
int lt1= 0;
|
||||
|
@ -742,7 +744,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return expression(ExprKind.eConstant, BinaryExprCtx.eNotInTemplateID, null, null);
|
||||
}
|
||||
|
||||
private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
private IASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||
final boolean allowComma= kind==ExprKind.eExpression;
|
||||
boolean allowAssignment= kind !=ExprKind.eConstant;
|
||||
|
||||
|
@ -750,12 +752,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return throwExpression();
|
||||
}
|
||||
|
||||
final boolean handleVariants= strat == null;
|
||||
if (handleVariants) {
|
||||
strat= new TemplateIdStrategy();
|
||||
}
|
||||
|
||||
|
||||
final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset();
|
||||
int lt1;
|
||||
int conditionCount= 0;
|
||||
|
@ -763,7 +759,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
NameOrTemplateIDVariants variants= null;
|
||||
|
||||
if (expr == null) {
|
||||
Object e = castExpressionForBinaryExpression(handleVariants, strat);
|
||||
Object e = castExpressionForBinaryExpression(strat);
|
||||
if (e instanceof IASTExpression) {
|
||||
expr= (IASTExpression) e;
|
||||
} else {
|
||||
|
@ -934,7 +930,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
// Cast expression
|
||||
IToken m= mark();
|
||||
try {
|
||||
Object e = castExpressionForBinaryExpression(handleVariants, strat);
|
||||
Object e = castExpressionForBinaryExpression(strat);
|
||||
if (e instanceof IASTExpression) {
|
||||
expr= (IASTExpression) e;
|
||||
} else {
|
||||
|
@ -999,18 +995,19 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return buildExpression(lastOperator, expr);
|
||||
}
|
||||
|
||||
public Object castExpressionForBinaryExpression(boolean handleVariants, final TemplateIdStrategy strat)
|
||||
public Object castExpressionForBinaryExpression(ITemplateIdStrategy s)
|
||||
throws EndOfFileException, BacktrackException {
|
||||
if (!handleVariants)
|
||||
return castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
||||
if (s != null) {
|
||||
return castExpression(CastExprCtx.eDirectlyInBExpr, s);
|
||||
}
|
||||
|
||||
TemplateIdStrategy strat= new TemplateIdStrategy();
|
||||
Variant variants= null;
|
||||
IASTExpression singleExpression= null;
|
||||
IASTName[] firstNames= null;
|
||||
|
||||
final IToken mark= mark();
|
||||
IToken lastToken= null;
|
||||
strat.reset();
|
||||
for(;;) {
|
||||
try {
|
||||
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
||||
|
@ -1554,7 +1551,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
isTemplate = true;
|
||||
}
|
||||
|
||||
IASTName name = qualifiedName(strat, ctx);
|
||||
IASTName name = qualifiedName(ctx, strat);
|
||||
|
||||
if (name == null)
|
||||
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
||||
|
@ -1577,7 +1574,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
isTemplate = true;
|
||||
}
|
||||
|
||||
name = qualifiedName(strat, ctx);
|
||||
name = qualifiedName(ctx, strat);
|
||||
|
||||
if (name == null)
|
||||
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
||||
|
@ -1690,7 +1687,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
case IToken.t_operator:
|
||||
case IToken.tCOMPLETION:
|
||||
case IToken.tBITCOMPLEMENT: {
|
||||
IASTName name = qualifiedName(strat, ctx);
|
||||
IASTName name = qualifiedName(ctx, strat);
|
||||
IASTIdExpression idExpression = nodeFactory.newIdExpression(name);
|
||||
((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset()
|
||||
+ ((ASTNode) name).getLength() - ((ASTNode) name).getOffset());
|
||||
|
|
|
@ -27,24 +27,18 @@ final class TemplateIdStrategy implements ITemplateIdStrategy {
|
|||
private IASTName[] fTemplateNames;
|
||||
|
||||
public TemplateIdStrategy() {
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
fCurrentBranchPoint= -1;
|
||||
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
|
||||
if (fSimpleIDs != null) {
|
||||
fSimpleIDs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ignoreTemplateID() {
|
||||
public boolean shallParseAsTemplateID(IASTName name) {
|
||||
fCurrentBranchPoint++;
|
||||
return fSimpleIDs == null ? false : fSimpleIDs.get(fCurrentBranchPoint);
|
||||
}
|
||||
|
||||
public void addTemplateName(IASTName name) {
|
||||
fTemplateNames= ArrayUtil.append(fTemplateNames, name);
|
||||
boolean templateID= fSimpleIDs == null || !fSimpleIDs.get(fCurrentBranchPoint);
|
||||
if (templateID) {
|
||||
fTemplateNames= ArrayUtil.append(fTemplateNames, name);
|
||||
}
|
||||
return templateID;
|
||||
}
|
||||
|
||||
public boolean setNextAlternative() {
|
||||
|
|
Loading…
Add table
Reference in a new issue