diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index 4b1d5d9e4d3..e1caf59801a 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -5583,4 +5583,26 @@ public class AST2TemplateTests extends AST2BaseTest { public void testDirectlyNestedAmbiguity_362976() throws Exception { parseAndCheckBindings(); } + + // template + // struct MaxOfN { + // template struct Max2 { + // static const X result = (x1>x2)?x1:x2; + // }; + // static const T result = Max2::result), + // p3>::result),p4>::result),p5>::result),p6>::result),p7>::result),p8>::result), + // p9>::result),p10>::result),p11>::result),p12>::result),p13>::result),p14>::result), + // p15>::result),p16>::result),p17>::result),p18>::result),p19>::result),p20>::result; + // }; + // int main(){ + // return MaxOfN::result; + // } + public void testNestedTemplateAmbiguity_363609() throws Exception { + parseAndCheckBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 54e46eacea2..946044da4b2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -243,7 +243,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { throw backtrack; } - public IASTCompletionNode getCompletionNode() { + @Override + public IASTCompletionNode getCompletionNode() { return completionNode; } @@ -555,7 +556,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { parsePassed = false; } - public synchronized void cancel() { + @Override + public synchronized void cancel() { isCancelled = true; } @@ -642,7 +644,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { throwBacktrack(n.getOffset(), n.getLength()); } - public IASTTranslationUnit parse() { + @Override + public IASTTranslationUnit parse() { long startTime = System.currentTimeMillis(); translationUnit(); log.traceLog("Parse " //$NON-NLS-1$ @@ -1173,22 +1176,27 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { return fUnaryOperatorOffset; } + @Override public IASTExpression copy() { throw new UnsupportedOperationException(); } + @Override public IASTExpression copy(CopyStyle style) { throw new UnsupportedOperationException(); } + @Override public IType getExpressionType() { throw new UnsupportedOperationException(); } + @Override public boolean isLValue() { throw new UnsupportedOperationException(); } + @Override public ValueCategory getValueCategory() { throw new UnsupportedOperationException(); } @@ -1198,11 +1206,14 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { if (LT(1) == IToken.tLPAREN) { final IToken mark= mark(); final int startingOffset= mark.getOffset(); + final boolean canBeCast= canBeCastExpression(); consume(); IASTTypeId typeId= null; - try { - typeId= typeId(DeclarationOptions.TYPEID); - } catch (BacktrackException e) { + if (canBeCast) { + try { + typeId= typeId(DeclarationOptions.TYPEID); + } catch (BacktrackException e) { + } } if (typeId != null && LT(1) == IToken.tRPAREN) { consume(); @@ -1562,7 +1573,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { return skipProblemConditionInParenthesis(mark.getOffset()); } - public boolean encounteredError() { + @Override + public boolean encounteredError() { return !parsePassed; } @@ -2399,7 +2411,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { if (token.getType() == IGCCToken.t__declspec) { consume(); if (LT(1) == IToken.tLPAREN) { - skipBrackets(IToken.tLPAREN, IToken.tRPAREN); + skipBrackets(IToken.tLPAREN, IToken.tRPAREN, 0); } } } @@ -2433,24 +2445,68 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } } - /** - * In case a cast expression is followed by +/- or & we should avoid it: - * (a)+1 vs. (int)+1; - * @since 4.0 - */ - protected boolean avoidCastExpressionByHeuristics() throws EndOfFileException { - if (LT(1) == IToken.tIDENTIFIER) { - if (LT(2) == IToken.tRPAREN) { - switch (LT(3)) { - case IToken.tPLUS: - case IToken.tMINUS: - case IToken.tAMPER: - case IToken.tSTAR: - return true; - } - } + protected boolean canBeCompoundLiteral() throws EndOfFileException { + IToken m= mark(); + try { + // The parenthesis cannot be followed by a binary operator + skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI); + return LTcatchEOF(1) == IToken.tLBRACE; + } catch (BacktrackException bt) { + return false; + } finally { + backup(m); + } + } + + protected boolean canBeCastExpression() throws EndOfFileException { + IToken m= mark(); + try { + // The parenthesis cannot be followed by a binary operator + skipBrackets(IToken.tLPAREN, IToken.tRPAREN, IToken.tSEMI); + switch (LTcatchEOF(1)) { + case IToken.tAMPERASSIGN: + case IToken.tAND: + case IToken.tARROW: + case IToken.tARROWSTAR: + case IToken.tASSIGN: + case IToken.tBITOR: + case IToken.tBITORASSIGN: + case IToken.tCOLON: + case IToken.tCOMMA: + case IToken.tDIV: + case IToken.tDIVASSIGN: + case IToken.tDOT: + case IToken.tDOTSTAR: + case IToken.tEQUAL: + case IToken.tGT: + case IToken.tGT_in_SHIFTR: + case IToken.tGTEQUAL: + case IToken.tLBRACKET: + case IToken.tLTEQUAL: + case IToken.tMINUSASSIGN: + case IToken.tMOD: + case IToken.tMODASSIGN: + case IToken.tNOTEQUAL: + case IToken.tOR: + case IToken.tPLUSASSIGN: + case IToken.tQUESTION: + case IToken.tRBRACE: + case IToken.tRBRACKET: + case IToken.tRPAREN: + case IToken.tSEMI: + case IToken.tSHIFTL: + case IToken.tSHIFTLASSIGN: + case IToken.tSHIFTR: + case IToken.tSHIFTRASSIGN: + case IToken.tSTARASSIGN: + return false; + } + return true; + } catch (BacktrackException bt) { + return false; + } finally { + backup(m); } - return false; } protected boolean canBeTypeSpecifier() throws EndOfFileException { @@ -2511,12 +2567,12 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser { } } - protected void skipBrackets(int left, int right) throws EndOfFileException, BacktrackException { + protected void skipBrackets(int left, int right, int terminator) throws EndOfFileException, BacktrackException { consume(left); int nesting= 0; while(true) { final int lt1= LT(1); - if (lt1 == IToken.tEOC) + if (lt1 == IToken.tEOC || lt1 == terminator) throwBacktrack(LA(1)); consume(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index cb269070476..fc43de3fe4d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -1754,7 +1754,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { final IToken current = LA(1); int startingOffset = current.getOffset(); if (current.getType() == IToken.tLBRACKET && supportParameterInfoBlock) { - skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET); + skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0); } IASTDeclSpecifier declSpec = null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index 46bbf254f39..0631dec1572 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -1454,14 +1454,16 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // ( type-name ) { initializer-list , } IToken m = mark(); try { - int offset = consume().getOffset(); - IASTTypeId t= typeId(DeclarationOptions.TYPEID); - consume(IToken.tRPAREN); - if (LT(1) == IToken.tLBRACE) { - IASTInitializer i = bracedInitList(false); - firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); - setRange(firstExpression, offset, calculateEndOffset(i)); - break; + if (canBeCompoundLiteral()) { + int offset = consume().getOffset(); + IASTTypeId t= typeId(DeclarationOptions.TYPEID); + consume(IToken.tRPAREN); + if (LT(1) == IToken.tLBRACE) { + IASTInitializer i = bracedInitList(false); + firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); + setRange(firstExpression, offset, calculateEndOffset(i)); + break; + } } } catch (BacktrackException bt) { } @@ -2568,7 +2570,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { final int startOffset= LA(1).getOffset(); if (LT(1) == IToken.tLBRACKET && supportParameterInfoBlock) { - skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET); + skipBrackets(IToken.tLBRACKET, IToken.tRBRACKET, 0); } IASTDeclSpecifier declSpec= null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java index 11243a01cad..ea0ab8fc01e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/TemplateIdStrategy.java @@ -14,6 +14,8 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import java.util.BitSet; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser.ITemplateIdStrategy; @@ -48,29 +50,36 @@ final class TemplateIdStrategy implements ITemplateIdStrategy { } public boolean setNextAlternative() { - final int bp = fCurrentBranchPoint; + int bp = fCurrentBranchPoint; if (bp < 0) return false; fCurrentBranchPoint= -1; + IASTName[] names = getTemplateNames(); + int nameLen= names.length; fTemplateNames= IASTName.EMPTY_NAME_ARRAY; if (fSimpleIDs == null) { fSimpleIDs= new BitSet(); } // Set a new branch as far right as possible. - final int len = fSimpleIDs.length(); - if (len <= bp) { - fSimpleIDs.set(bp); - return true; - } - - for (int branch= Math.min(bp, len-2); branch>=0; branch--) { - if (!fSimpleIDs.get(branch)) { - fSimpleIDs.clear(branch+1, len); - fSimpleIDs.set(branch); - return true; + while (bp >= 0) { + if (!fSimpleIDs.get(bp)) { + if (nameLen == 0 || !hasMultipleArgs(names[--nameLen])) { + fSimpleIDs.clear(bp+1, Integer.MAX_VALUE); + fSimpleIDs.set(bp); + return true; + } } + bp--; + } + return false; + } + + private boolean hasMultipleArgs(IASTName templateName) { + IASTNode parent= templateName.getParent(); + if (parent instanceof ICPPASTTemplateId) { + return ((ICPPASTTemplateId) parent).getTemplateArguments().length > 1; } return false; }