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();
|
final String code= getAboveComment();
|
||||||
parseAndCheckBindings(code);
|
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 abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||||
public interface ITemplateIdStrategy {
|
public interface ITemplateIdStrategy {
|
||||||
|
boolean shallParseAsTemplateID(IASTName name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class FoundAggregateInitializer extends Exception {
|
protected static class FoundAggregateInitializer extends Exception {
|
||||||
|
|
|
@ -209,11 +209,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private IASTName qualifiedName() throws BacktrackException, EndOfFileException {
|
private IASTName qualifiedName() throws BacktrackException, EndOfFileException {
|
||||||
|
return ambiguousQualifiedName(CastExprCtx.eNotInBExpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IASTName ambiguousQualifiedName(CastExprCtx ctx) throws BacktrackException, EndOfFileException {
|
||||||
TemplateIdStrategy strat= new TemplateIdStrategy();
|
TemplateIdStrategy strat= new TemplateIdStrategy();
|
||||||
IToken m= mark();
|
IToken m= mark();
|
||||||
for(;;) {
|
for(;;) {
|
||||||
try {
|
try {
|
||||||
return qualifiedName(strat, CastExprCtx.eNotInBExpr);
|
return qualifiedName(ctx, strat);
|
||||||
} catch (BacktrackException e) {
|
} catch (BacktrackException e) {
|
||||||
if (strat.setNextAlternative()) {
|
if (strat.setNextAlternative()) {
|
||||||
backup(m);
|
backup(m);
|
||||||
|
@ -227,8 +231,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
/**
|
/**
|
||||||
* Parses a qualified name.
|
* Parses a qualified name.
|
||||||
*/
|
*/
|
||||||
private IASTName qualifiedName(ITemplateIdStrategy s, CastExprCtx ctx) throws BacktrackException, EndOfFileException {
|
private IASTName qualifiedName(CastExprCtx ctx, ITemplateIdStrategy strat) throws BacktrackException, EndOfFileException {
|
||||||
final TemplateIdStrategy strat= (TemplateIdStrategy) s;
|
if (strat == null)
|
||||||
|
return ambiguousQualifiedName(ctx);
|
||||||
|
|
||||||
ICPPASTQualifiedName qname= null;
|
ICPPASTQualifiedName qname= null;
|
||||||
IASTName name= null;
|
IASTName name= null;
|
||||||
final int offset= LA(1).getOffset();
|
final int offset= LA(1).getOffset();
|
||||||
|
@ -288,11 +294,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
if (haveArgs == -1) {
|
if (haveArgs == -1) {
|
||||||
templateID= false;
|
templateID= false;
|
||||||
} else if (haveArgs == 0) {
|
} else if (haveArgs == 0) {
|
||||||
if (strat.ignoreTemplateID()) {
|
templateID= strat.shallParseAsTemplateID(name);
|
||||||
templateID= false;
|
|
||||||
} else {
|
|
||||||
strat.addTemplateName(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (templateID) {
|
if (templateID) {
|
||||||
|
@ -350,7 +352,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
return name;
|
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
|
// Parse for template arguments
|
||||||
consume(IToken.tLT);
|
consume(IToken.tLT);
|
||||||
List<IASTNode> list = templateArgumentList(strat);
|
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 startingOffset = LA(1).getOffset();
|
||||||
int endOffset = 0;
|
int endOffset = 0;
|
||||||
List<IASTNode> list= null;
|
List<IASTNode> list= null;
|
||||||
|
@ -596,7 +598,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IASTNode templateArgument(TemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
private IASTNode templateArgument(ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException {
|
||||||
IToken argStart = mark();
|
IToken argStart = mark();
|
||||||
ICPPASTTypeId typeId= null;
|
ICPPASTTypeId typeId= null;
|
||||||
int lt1= 0;
|
int lt1= 0;
|
||||||
|
@ -742,7 +744,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
return expression(ExprKind.eConstant, BinaryExprCtx.eNotInTemplateID, null, null);
|
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;
|
final boolean allowComma= kind==ExprKind.eExpression;
|
||||||
boolean allowAssignment= kind !=ExprKind.eConstant;
|
boolean allowAssignment= kind !=ExprKind.eConstant;
|
||||||
|
|
||||||
|
@ -750,12 +752,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
return throwExpression();
|
return throwExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean handleVariants= strat == null;
|
|
||||||
if (handleVariants) {
|
|
||||||
strat= new TemplateIdStrategy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset();
|
final int startOffset= expr != null ? ((ASTNode) expr).getOffset() : LA(1).getOffset();
|
||||||
int lt1;
|
int lt1;
|
||||||
int conditionCount= 0;
|
int conditionCount= 0;
|
||||||
|
@ -763,7 +759,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
NameOrTemplateIDVariants variants= null;
|
NameOrTemplateIDVariants variants= null;
|
||||||
|
|
||||||
if (expr == null) {
|
if (expr == null) {
|
||||||
Object e = castExpressionForBinaryExpression(handleVariants, strat);
|
Object e = castExpressionForBinaryExpression(strat);
|
||||||
if (e instanceof IASTExpression) {
|
if (e instanceof IASTExpression) {
|
||||||
expr= (IASTExpression) e;
|
expr= (IASTExpression) e;
|
||||||
} else {
|
} else {
|
||||||
|
@ -934,7 +930,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
// Cast expression
|
// Cast expression
|
||||||
IToken m= mark();
|
IToken m= mark();
|
||||||
try {
|
try {
|
||||||
Object e = castExpressionForBinaryExpression(handleVariants, strat);
|
Object e = castExpressionForBinaryExpression(strat);
|
||||||
if (e instanceof IASTExpression) {
|
if (e instanceof IASTExpression) {
|
||||||
expr= (IASTExpression) e;
|
expr= (IASTExpression) e;
|
||||||
} else {
|
} else {
|
||||||
|
@ -999,18 +995,19 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
return buildExpression(lastOperator, expr);
|
return buildExpression(lastOperator, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object castExpressionForBinaryExpression(boolean handleVariants, final TemplateIdStrategy strat)
|
public Object castExpressionForBinaryExpression(ITemplateIdStrategy s)
|
||||||
throws EndOfFileException, BacktrackException {
|
throws EndOfFileException, BacktrackException {
|
||||||
if (!handleVariants)
|
if (s != null) {
|
||||||
return castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
return castExpression(CastExprCtx.eDirectlyInBExpr, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateIdStrategy strat= new TemplateIdStrategy();
|
||||||
Variant variants= null;
|
Variant variants= null;
|
||||||
IASTExpression singleExpression= null;
|
IASTExpression singleExpression= null;
|
||||||
IASTName[] firstNames= null;
|
IASTName[] firstNames= null;
|
||||||
|
|
||||||
final IToken mark= mark();
|
final IToken mark= mark();
|
||||||
IToken lastToken= null;
|
IToken lastToken= null;
|
||||||
strat.reset();
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
try {
|
try {
|
||||||
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
IASTExpression e = castExpression(CastExprCtx.eDirectlyInBExpr, strat);
|
||||||
|
@ -1554,7 +1551,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
isTemplate = true;
|
isTemplate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
IASTName name = qualifiedName(strat, ctx);
|
IASTName name = qualifiedName(ctx, strat);
|
||||||
|
|
||||||
if (name == null)
|
if (name == null)
|
||||||
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
||||||
|
@ -1577,7 +1574,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
isTemplate = true;
|
isTemplate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = qualifiedName(strat, ctx);
|
name = qualifiedName(ctx, strat);
|
||||||
|
|
||||||
if (name == null)
|
if (name == null)
|
||||||
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
throwBacktrack(((ASTNode) firstExpression).getOffset(),
|
||||||
|
@ -1690,7 +1687,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
case IToken.t_operator:
|
case IToken.t_operator:
|
||||||
case IToken.tCOMPLETION:
|
case IToken.tCOMPLETION:
|
||||||
case IToken.tBITCOMPLEMENT: {
|
case IToken.tBITCOMPLEMENT: {
|
||||||
IASTName name = qualifiedName(strat, ctx);
|
IASTName name = qualifiedName(ctx, strat);
|
||||||
IASTIdExpression idExpression = nodeFactory.newIdExpression(name);
|
IASTIdExpression idExpression = nodeFactory.newIdExpression(name);
|
||||||
((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset()
|
((ASTNode) idExpression).setOffsetAndLength(((ASTNode) name).getOffset(), ((ASTNode) name).getOffset()
|
||||||
+ ((ASTNode) name).getLength() - ((ASTNode) name).getOffset());
|
+ ((ASTNode) name).getLength() - ((ASTNode) name).getOffset());
|
||||||
|
|
|
@ -27,25 +27,19 @@ final class TemplateIdStrategy implements ITemplateIdStrategy {
|
||||||
private IASTName[] fTemplateNames;
|
private IASTName[] fTemplateNames;
|
||||||
|
|
||||||
public TemplateIdStrategy() {
|
public TemplateIdStrategy() {
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
fCurrentBranchPoint= -1;
|
fCurrentBranchPoint= -1;
|
||||||
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
|
fTemplateNames= IASTName.EMPTY_NAME_ARRAY;
|
||||||
if (fSimpleIDs != null) {
|
|
||||||
fSimpleIDs.clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean ignoreTemplateID() {
|
public boolean shallParseAsTemplateID(IASTName name) {
|
||||||
fCurrentBranchPoint++;
|
fCurrentBranchPoint++;
|
||||||
return fSimpleIDs == null ? false : fSimpleIDs.get(fCurrentBranchPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTemplateName(IASTName name) {
|
boolean templateID= fSimpleIDs == null || !fSimpleIDs.get(fCurrentBranchPoint);
|
||||||
|
if (templateID) {
|
||||||
fTemplateNames= ArrayUtil.append(fTemplateNames, name);
|
fTemplateNames= ArrayUtil.append(fTemplateNames, name);
|
||||||
}
|
}
|
||||||
|
return templateID;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean setNextAlternative() {
|
public boolean setNextAlternative() {
|
||||||
final int bp = fCurrentBranchPoint;
|
final int bp = fCurrentBranchPoint;
|
||||||
|
|
Loading…
Add table
Reference in a new issue