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 d620376eed4..7c43c703e56 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 @@ -24,6 +24,7 @@ import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IBasicType; @@ -2478,7 +2479,7 @@ public class AST2TemplateTests extends AST2BaseTest { // // const int i= 1; // A a1; - public void _testNonTypeArgumentIsIDExpression_229942_a() throws Exception { + public void testNonTypeArgumentIsIDExpression_229942_a() throws Exception { IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP, true, true); CPPNameCollector col = new CPPNameCollector(); tu.accept(col); @@ -2497,7 +2498,7 @@ public class AST2TemplateTests extends AST2BaseTest { // // const int i= 1; // }; - public void _testNonTypeArgumentIsIDExpression_229942_b() throws Exception { + public void testNonTypeArgumentIsIDExpression_229942_b() throws Exception { IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP, true, true); CPPNameCollector col = new CPPNameCollector(); tu.accept(col); @@ -2592,7 +2593,7 @@ public class AST2TemplateTests extends AST2BaseTest { // template // inline const void foo(void (*f)(A), T* t) { // disallowed, but we're testing the AST // } - public void _testTypeIdAsTemplateArgumentIsTypeId_229942_g() throws Exception { + public void testTypeIdAsTemplateArgumentIsTypeId_229942_g() throws Exception { IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP, true, true); CPPNameCollector col = new CPPNameCollector(); tu.accept(col); @@ -2605,6 +2606,21 @@ public class AST2TemplateTests extends AST2BaseTest { assertInstance(col.getName(17).getParent(), IASTIdExpression.class); } + // typedef int td; + // template<> class Alias { + // }; + public void testNonAmbiguityCase_229942_h() throws Exception { + IASTTranslationUnit tu= parse(getAboveComment(), ParserLanguage.CPP); + CPPNameCollector col= new CPPNameCollector(); + tu.accept(col); + + // 2 is Alias + ICPPASTTemplateId tid= assertInstance(col.getName(2).getParent(), ICPPASTTemplateId.class); + IASTNode[] args= tid.getTemplateArguments(); + assertEquals(1, args.length); + assertInstance(args[0], IASTTypeId.class); + } + // // From discussion in 207840. See 14.3.4. // class A {}; // diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTAmbiguousTemplateArgument.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTAmbiguousTemplateArgument.java new file mode 100644 index 00000000000..80811ba9454 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTAmbiguousTemplateArgument.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2008 Symbian Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Andrew Ferguson (Symbian) - Initial Implementation + *******************************************************************************/ +package org.eclipse.cdt.core.dom.ast.cpp; + +import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTTypeId; + +/** + * Place-holder in the AST for template arguments that are not yet + * understood. + */ +public interface ICPPASTAmbiguousTemplateArgument extends IASTNode { + /** + * Add an partial parse tree that could be a suitable subtree representing + * the template argument + * @param idExpression a non-null id-expression + */ + public void addIdExpression(IASTIdExpression idExpression); + + /** + * Add an partial parse tree that could be a suitable subtree representing + * the template argument + * @param typeId a non-null type-id + */ + public void addTypeId(IASTTypeId typeId); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTTemplateId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTTemplateId.java index 983d499825c..1485149a186 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTTemplateId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTTemplateId.java @@ -1,12 +1,13 @@ /******************************************************************************* - * Copyright (c) 2004, 2005 IBM Corporation and others. + * Copyright (c) 2004, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * IBM - Initial API and implementation + * IBM - Initial API and implementation + * Andrew Ferguson (Symbian) *******************************************************************************/ package org.eclipse.cdt.core.dom.ast.cpp; @@ -57,19 +58,24 @@ public interface ICPPASTTemplateId extends IASTName, IASTNameOwner { /** * Add template argument. * - * @param typeId - * IASTTypeId + * @param typeId IASTTypeId */ public void addTemplateArgument(IASTTypeId typeId); /** * Add template argument. * - * @param expression - * IASTExpression + * @param expression IASTExpression */ public void addTemplateArgument(IASTExpression expression); + /** + * Add an ambiguity node for later resolution. + * + * @param ambiguity + */ + public void addTemplateArgument(ICPPASTAmbiguousTemplateArgument ambiguity); + /** * Get all template arguments. (as nodes) * diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousTemplateArgument.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousTemplateArgument.java new file mode 100644 index 00000000000..93c7cbed273 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousTemplateArgument.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2008 Symbian Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Andrew Ferguson (Symbian) - Initial Implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTTypeId; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument; +import org.eclipse.cdt.internal.core.parser.ParserMessages; + +/** + * Ambiguity node for deciding between type-id and id-expression in a template argument. + */ +public class CPPASTAmbiguousTemplateArgument extends CPPASTAmbiguity implements ICPPASTAmbiguousTemplateArgument { + private List fNodes; + + /** + * @param nodes nodes of type {@link IASTTypeId} or {@link IASTIdExpression} + */ + /* + * We can replace this with a version taking ICPPASTTemplateArgument... + * in the future + */ + public CPPASTAmbiguousTemplateArgument(IASTNode... nodes) { + fNodes= new ArrayList(); + for(IASTNode node : nodes) { + if(node instanceof IASTTypeId || node instanceof IASTIdExpression) { + fNodes.add(node); + } else { + String ns= node == null ? "null" : node.getClass().getName(); //$NON-NLS-1$ + String msg= MessageFormat.format(ParserMessages.getString("CPPASTAmbiguousTemplateArgument_InvalidConstruction"), ns); //$NON-NLS-1$ + throw new IllegalArgumentException(msg); + } + } + } + + @Override + protected IASTNode[] getNodes() { + return fNodes.toArray(new IASTNode[fNodes.size()]); + } + + public void addTypeId(IASTTypeId typeId) { + addNode(typeId); + } + + public void addIdExpression(IASTIdExpression idExpression) { + addNode(idExpression); + } + + private void addNode(IASTNode node) { + fNodes.add(node); + node.setParent(this); + node.setPropertyInParent(CPPASTTemplateId.TEMPLATE_ID_ARGUMENT); + } +} + diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java index 79aa14876de..c8c46ad0f0c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java @@ -8,6 +8,7 @@ * Contributors: * IBM - Initial API and implementation * Markus Schorn (Wind River Systems) + * Andrew Ferguson (Symbian) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -20,6 +21,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNameOwner; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.Linkage; @@ -69,6 +71,14 @@ public class CPPASTTemplateId extends CPPASTNode implements ICPPASTTemplateId, I expression.setPropertyInParent(TEMPLATE_ID_ARGUMENT); } } + + public void addTemplateArgument(ICPPASTAmbiguousTemplateArgument ata) { + templateArguments = (IASTNode[]) ArrayUtil.append(IASTNode.class, templateArguments, ata); + if (ata != null) { + ata.setParent(this); + ata.setPropertyInParent(TEMPLATE_ID_ARGUMENT); + } + } public IASTNode[] getTemplateArguments() { if (templateArguments == null) return ICPPASTTemplateId.EMPTY_ARG_ARRAY; 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 a5eabd913fb..d9f7c3fabfc 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 @@ -11,6 +11,7 @@ * Bryan Wilkinson (QNX) - https://bugs.eclipse.org/bugs/show_bug.cgi?id=151207 * Ed Swartz (Nokia) * Mike Kucera (IBM) + * Andrew Ferguson (Symbian) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -77,6 +78,7 @@ import org.eclipse.cdt.core.dom.ast.IASTWhileStatement; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; @@ -270,64 +272,87 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } return last; } - protected List templateArgumentList() throws EndOfFileException, BacktrackException { - IToken start = LA(1); - int startingOffset = start.getOffset(); - int endOffset = 0; - start = null; - List list = new ArrayList(); + IToken start = LA(1); + int startingOffset = start.getOffset(); + int endOffset = 0; + start = null; + List list = new ArrayList(); - boolean completedArg = false; - boolean failed = false; + boolean failed = false; - final int initialTemplateIdScopesSize= templateIdScopes.size(); - templateIdScopes.push(IToken.tLT); - try { - while (LT(1) != IToken.tGT && LT(1) != IToken.tEOC) { - completedArg = false; + final int initialTemplateIdScopesSize= templateIdScopes.size(); + templateIdScopes.push(IToken.tLT); + try { + while (LT(1) != IToken.tGT && LT(1) != IToken.tEOC) { + IToken argStart = mark(); + IASTTypeId typeId = typeId(false); - IToken mark = mark(); - IASTTypeId typeId = typeId(false); - if (typeId == null) { - backup(mark); - } else if (LT(1) != IToken.tCOMMA && LT(1) != IToken.tGT && LT(1) != IToken.tEOC){ - //didn't consume the whole argument, probably confused typeId with idExpression - //backup and try the assignmentExpression - backup(mark); - } else { - list.add(typeId); - completedArg = true; - } - if (!completedArg) { - try { - IASTExpression expression = assignmentExpression(); - list.add(expression); - completedArg = true; - } catch (BacktrackException e) { - backup(mark); - } - } + if(typeId != null && (LT(1)==IToken.tCOMMA || LT(1)==IToken.tGT || LT(1)==IToken.tEOC)) { + // potentially a type-id - check for id-expression ambiguity + IToken typeIdEnd= mark(); - if (LT(1) == IToken.tCOMMA) { - consume(); - } else if (LT(1) != IToken.tGT && LT(1) != IToken.tEOC) { - failed = true; - endOffset = LA(1).getEndOffset(); - break; - } - } - } - finally { - do { - templateIdScopes.pop(); - } while (templateIdScopes.size() > initialTemplateIdScopesSize); - } - if (failed) - throwBacktrack(startingOffset, endOffset - startingOffset); + backup(argStart); + try { + IASTExpression expression = assignmentExpression(); + if(expression instanceof IASTIdExpression) { + IASTIdExpression idExpression= (IASTIdExpression) expression; + if(idExpression.getName() instanceof ICPPASTTemplateId) { + /* + * A template-id cannot be used in an id-expression as a template argument. + * + * 5.1-11 A template-id shall be used as an unqualified-id only as specified in + * 14.7.2, 14.7, and 14.5.4. + */ + throw backtrack; + } - return list; + if (mark() != typeIdEnd) + throw backtrack; + + ICPPASTAmbiguousTemplateArgument ambiguity= createAmbiguousTemplateArgument(); + ambiguity.addTypeId(typeId); + ambiguity.addIdExpression(idExpression); + list.add(ambiguity); + } else { + // prefer the typeId at this stage + throw backtrack; + } + } catch (BacktrackException e) { + // no ambiguity - its a type-id + list.add(typeId); + backup(typeIdEnd); + } + } else { + // not a type-id - try as expression + backup(argStart); + try { + IASTExpression expression = assignmentExpression(); + list.add(expression); + } catch (BacktrackException e) { + backup(argStart); + } + } + + if (LT(1) == IToken.tCOMMA) { + consume(); + } else if (LT(1) != IToken.tGT && LT(1) != IToken.tEOC) { + failed = true; + endOffset = LA(1).getEndOffset(); + break; + } + } + } + finally { + do { + templateIdScopes.pop(); + } while (templateIdScopes.size() > initialTemplateIdScopesSize); + } + if (failed) + throwBacktrack(startingOffset, endOffset - startingOffset); + + return list; } /** @@ -1610,6 +1635,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { protected IASTAmbiguousExpression createAmbiguousExpression() { return new CPPASTAmbiguousExpression(); } + + protected ICPPASTAmbiguousTemplateArgument createAmbiguousTemplateArgument() { + return new CPPASTAmbiguousTemplateArgument(); + } protected IASTArraySubscriptExpression createArraySubscriptExpression() { return new CPPASTArraySubscriptExpression(); @@ -2540,10 +2569,13 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (args != null) for (int i = 0; i < args.size(); ++i) { IASTNode n = args.get(i); - if (n instanceof IASTTypeId) + if (n instanceof IASTTypeId) { result.addTemplateArgument((IASTTypeId) n); - else if(n instanceof IASTExpression) + } else if(n instanceof IASTExpression) { result.addTemplateArgument((IASTExpression) n); + } else if(n instanceof ICPPASTAmbiguousTemplateArgument) { + result.addTemplateArgument((ICPPASTAmbiguousTemplateArgument) n); + } } } return result; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index d38cadbf3cd..7f08231ce5a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -349,7 +349,11 @@ public class CPPSemantics { if (name.getPropertyInParent() == IASTNamedTypeSpecifier.NAME && !(binding instanceof IType || binding instanceof ICPPConstructor)) { IASTNode parent = name.getParent().getParent(); if (parent instanceof IASTTypeId && parent.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT) { - //don't do a problem here + if(!(binding instanceof IType)) { + // a type id needs to hold a type + binding = new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_INVALID_TYPE, data.name()); + } + // don't create a problem here } else { binding = new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_INVALID_TYPE, data.name()); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties index 0d8d8cd8c22..8c754004476 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.properties @@ -88,3 +88,4 @@ ASTProblemFactory.error.semantic.dom.invalidRedeclaration=Invalid redeclaration ASTProblemFactory.error.semantic.dom.recursionInResolution=Recursion while looking up ''{0}'' ASTProblemFactory.error.semantic.dom.badScope=A scope could not be created to represent the name {0} ASTProblemFactory.error.semantic.dom.memberDeclNotFound=A declaration could not be found for this member definition: {0} +CPPASTAmbiguousTemplateArgument_InvalidConstruction=Internal parser error: Template argument ambiguity constructed with {0}