diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java index 6367f83e926..ff7ebd55b85 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; +import org.eclipse.cdt.core.parser.tests.ast2.cxx14.GenericLambdaTests; import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionTests; import org.eclipse.cdt.core.parser.tests.ast2.cxx14.VariableTemplateTests; import org.eclipse.cdt.core.parser.tests.prefix.CompletionTestSuite; @@ -59,8 +60,10 @@ public class DOMParserTestSuite extends TestCase { suite.addTest(AccessControlTests.suite()); suite.addTest(VariableReadWriteFlagsTest.suite()); suite.addTest(AST2CPPAttributeTests.suite()); + // C++14 tests suite.addTest(VariableTemplateTests.suite()); suite.addTestSuite(ReturnTypeDeductionTests.class); + suite.addTestSuite(GenericLambdaTests.class); return suite; } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java new file mode 100644 index 00000000000..65c546bc2d2 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaIndexTests.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2017 Nathan Ridge. + * 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 + *******************************************************************************/ +package org.eclipse.cdt.core.parser.tests.ast2.cxx14; + +import org.eclipse.cdt.core.dom.ast.IFunction; +import org.eclipse.cdt.internal.index.tests.IndexBindingResolutionTestBase; + +/** + * Index tests for C++14 generic lambdas. + */ +public class GenericLambdaIndexTests extends IndexBindingResolutionTestBase { + public GenericLambdaIndexTests() { + setStrategy(new SinglePDOMTestStrategy(true)); + } + + // auto Identity = [](auto a){ return a; }; + + // auto three = Identity(3); + // auto hello = Identity("hello"); + public void testBasicCall() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableType("three", CommonCPPTypes.int_); + helper.assertVariableType("hello", CommonCPPTypes.pointerToConstChar); + } + + // // Adapted from the example in [expr.prim.lambda] p7 in the standard. + // auto Identity = [](auto a){ return a; }; + + // void f1(int(*)(int)); + // void f2(char(*)(int)); + // void g(int(*)(int)); + // void g(char(*)(char)); + // void h(int(*)(int)); // #1 + // void h(char(*)(int)); // #2 + // int main() { + // f1(Identity); // ok + // f2(Identity); // error: not convertible + // g(Identity); // error: ambiguous + // h(Identity); // ok: calls #1 + // } + public void testConversionToFunctionPointer() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertNonProblem("f1(Id", "f1"); + helper.assertProblem("f2(Id", "f2"); + helper.assertProblem("g(Id", "g"); + IFunction h1 = helper.assertNonProblem("h(int", "h"); + IFunction hCall = helper.assertNonProblem("h(Id", "h"); + assertSame(h1, hCall); + } + + // template + // struct tuple {}; + // + // template + // tuple make_tuple(T...); + // + // auto L = [](auto... args) { return make_tuple(args...); }; + // + // struct Cat { void meow(); }; + // + // Cat foo(tuple); + // Cat bar(tuple); + // + // void waldo(Cat); + + // int main() { + // waldo(foo(L(42, 'x'))); + // waldo(bar(L(42, 'x', 42.0f))); + // } + public void _testVariadicAutoParameter() throws Exception { + // TODO: To pass this test, we need to store lambda parameters in the index. + checkBindings(); + } + + // // Adapted from the example in [expr.prim.lambda] p6 in the standard. + // namespace std { + // struct ostream { + // template + // ostream& operator<<(const T&); + // }; + // ostream cout; + // } + // auto vglambda = [](auto printer) { + // return [=](auto&&... ts) { + // return [=]() { + // return printer(ts...); + // }; + // }; + // }; + // auto p = vglambda( + // [](auto v1, auto v2, auto v3) { + // return std::cout << v1 << v2 << v3; + // }); + // auto q = p(1, 'a', 3.14); + // void waldo(const std::ostream&); + + // int main() { + // waldo(q()); + // } + public void testNestedGenericLambdas() throws Exception { + checkBindings(); + } + +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java new file mode 100644 index 00000000000..d83d10aaff8 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/GenericLambdaTests.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2017 Nathan Ridge. + * 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 + *******************************************************************************/ +package org.eclipse.cdt.core.parser.tests.ast2.cxx14; + +import org.eclipse.cdt.core.dom.ast.IFunction; +import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase; + +/** + * AST tests for C++14 generic lambdas. + */ +public class GenericLambdaTests extends AST2CPPTestBase { + // auto Identity = [](auto a){ return a; }; + // auto three = Identity(3); + // auto hello = Identity("hello"); + public void testBasicCall() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableType("three", CommonCPPTypes.int_); + helper.assertVariableType("hello", CommonCPPTypes.pointerToConstChar); + } + + // // Adapted from the example in [expr.prim.lambda] p7 in the standard. + // auto Identity = [](auto a){ return a; }; + // void f1(int(*)(int)); + // void f2(char(*)(int)); + // void g(int(*)(int)); + // void g(char(*)(char)); + // void h(int(*)(int)); // #1 + // void h(char(*)(int)); // #2 + // void j(int&(*)(int*)); + // int main() { + // f1(Identity); // ok + // f2(Identity); // error: not convertible + // g(Identity); // error: ambiguous + // h(Identity); // ok: calls #1 + // j([](auto* a) -> auto& { return *a; }); // ok + // } + public void testConversionToFunctionPointer() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertNonProblem("f1(Id", "f1"); + helper.assertProblem("f2(Id", "f2"); + helper.assertProblem("g(Id", "g"); + IFunction h1 = helper.assertNonProblem("h(int", "h"); + IFunction hCall = helper.assertNonProblem("h(Id", "h"); + assertSame(h1, hCall); + helper.assertNonProblem("j([]", "j"); + } + + // template + // struct tuple {}; + // + // template + // tuple make_tuple(T...); + // + // auto L = [](auto... args) { return make_tuple(args...); }; + // + // struct Cat { void meow(); }; + // + // Cat foo(tuple); + // Cat bar(tuple); + // + // void waldo(Cat); + // + // int main() { + // waldo(foo(L(42, 'x'))); + // waldo(bar(L(42, 'x', 42.0f))); + // } + public void testVariadicAutoParameter() throws Exception { + parseAndCheckBindings(); + } + + // // Adapted from the example in [expr.prim.lambda] p6 in the standard. + // namespace std { + // struct ostream { + // template + // ostream& operator<<(const T&); + // }; + // ostream cout; + // } + // auto vglambda = [](auto printer) { + // return [=](auto&&... ts) { + // return [=]() { + // return printer(ts...); + // }; + // }; + // }; + // auto p = vglambda( + // [](auto v1, auto v2, auto v3) { + // return std::cout << v1 << v2 << v3; + // }); + // auto q = p(1, 'a', 3.14); + // void waldo(const std::ostream&); + // int main() { + // waldo(q()); + // } + public void testNestedGenericLambdas() throws Exception { + parseAndCheckBindings(); + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java index fa332dafe62..48ba4c3debe 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexTests.java @@ -11,6 +11,7 @@ *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; +import org.eclipse.cdt.core.parser.tests.ast2.cxx14.GenericLambdaIndexTests; import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionIndexTests; import junit.framework.Test; @@ -37,7 +38,9 @@ public class IndexTests extends TestSuite { suite.addTest(IndexMultiVariantHeaderTest.suite()); suite.addTest(IndexMultiFileTest.suite()); + // C++14 index test suites suite.addTestSuite(ReturnTypeDeductionIndexTests.class); + suite.addTestSuite(GenericLambdaIndexTests.class); IndexCPPBindingResolutionBugs.addTests(suite); IndexCPPBindingResolutionTest.addTests(suite); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLambdaExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLambdaExpression.java index 9d540c73bec..3d33c1ee8a1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLambdaExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLambdaExpression.java @@ -40,6 +40,7 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr private IASTImplicitName fClosureTypeName; private IASTImplicitName fImplicitFunctionCallName; + private IASTImplicitName fImplicitConversionOperatorName; private ICPPEvaluation fEvaluation; @@ -105,10 +106,32 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr } return fImplicitFunctionCallName; } + + private IASTImplicitName getConversionOperatorName() { + if (fImplicitConversionOperatorName == null) { + final CPPClosureType closureType = getExpressionType(); + ICPPFunction conversionOperator = closureType.getConversionOperator(); + if (conversionOperator != null) { + CPPASTImplicitName name = new CPPASTImplicitName(closureType.getNameCharArray(), this); + name.setBinding(conversionOperator); + name.setIsDefinition(true); + + if (fBody instanceof ASTNode) { + name.setOffsetAndLength(((ASTNode) fBody).getOffset(), 1); + } + fImplicitConversionOperatorName = name; + } + } + return fImplicitConversionOperatorName; + } @Override public IASTImplicitName[] getImplicitNames() { - return new IASTImplicitName[] {getFunctionCallOperatorName()}; + IASTImplicitName conversionOperatorName = getConversionOperatorName(); + if (conversionOperatorName == null) { + return new IASTImplicitName[] { getFunctionCallOperatorName() }; + } + return new IASTImplicitName[] { getFunctionCallOperatorName(), getConversionOperatorName() }; } @Override @@ -138,8 +161,13 @@ public class CPPASTLambdaExpression extends ASTNode implements ICPPASTLambdaExpr if (fDeclarator != null && !fDeclarator.accept(visitor)) return false; - if (visitor.shouldVisitImplicitNames && !getFunctionCallOperatorName().accept(visitor)) - return false; + if (visitor.shouldVisitImplicitNames) { + for (IASTImplicitName name : getImplicitNames()) { + if (!name.accept(visitor)) { + return false; + } + } + } if (fBody != null && !fBody.accept(visitor)) return false; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java index 4b8717511b4..45460e1feaa 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClosureType.java @@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IBinding; @@ -35,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression.CaptureDefault; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; @@ -45,9 +47,11 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFileSet; +import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.dom.Linkage; @@ -65,6 +69,8 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP private final ICPPASTLambdaExpression fLambdaExpression; private ICPPMethod[] fMethods; private ClassScope fScope; + // Used for generic lambdas; null otherwise. + private ICPPTemplateParameter[] fInventedTemplateParameters; public CPPClosureType(ICPPASTLambdaExpression lambdaExpr) { fLambdaExpression= lambdaExpr; @@ -111,17 +117,45 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP for (int i = 0; i < params.length; i++) { params[i]= new CPPParameter(parameterTypes[i], i); } - m= new CPPImplicitMethod(scope, OverloadableOperator.PAREN.toCharArray(), ft, params, false) { - @Override - public boolean isImplicit() { return false; } - }; + char[] operatorParensName = OverloadableOperator.PAREN.toCharArray(); + if (isGeneric()) { + m = new CPPImplicitMethodTemplate(getInventedTemplateParameterList(), scope, operatorParensName, + ft, params, false) { + @Override + public boolean isImplicit() { return false; } + }; + } else { + m= new CPPImplicitMethod(scope, operatorParensName, ft, params, false) { + @Override + public boolean isImplicit() { return false; } + }; + } result[4]= m; // Conversion operator if (needConversionOperator) { final CPPFunctionType conversionTarget = new CPPFunctionType(returnType, parameterTypes); ft= new CPPFunctionType(conversionTarget, IType.EMPTY_TYPE_ARRAY, true, false, false, false, false); - m= new CPPImplicitMethod(scope, CPPASTConversionName.createName(conversionTarget, null), ft, params, false); + char[] conversionOperatorName = CPPASTConversionName.createName(conversionTarget, null); + if (isGeneric()) { + ICPPTemplateParameter[] templateParams = getInventedTemplateParameterList(); + // Clone the template parameters, since they are used by the function call operator, + // and the same parameters cannot participate in two different templates. + ICPPTemplateParameter[] templateParamClones = new ICPPTemplateParameter[templateParams.length]; + for (int i = 0; i < templateParams.length; ++i) { + templateParamClones[i] = (ICPPTemplateParameter) ((IType) templateParams[i]).clone(); + } + m = new CPPImplicitMethodTemplate(templateParamClones, scope, + conversionOperatorName, ft, params, false) { + @Override + public boolean isImplicit() { return false; } + }; + } else { + m= new CPPImplicitMethod(scope, conversionOperatorName, ft, params, false) { + @Override + public boolean isImplicit() { return false; } + }; + } result[5]= m; } return result; @@ -167,6 +201,40 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; } + public boolean isGeneric() { + return getInventedTemplateParameterList().length > 0; + } + + public ICPPTemplateParameter[] getInventedTemplateParameterList() { + if (fInventedTemplateParameters == null) { + fInventedTemplateParameters = computeInventedTemplateParameterList(); + } + return fInventedTemplateParameters; + } + + public ICPPTemplateParameter[] computeInventedTemplateParameterList() { + ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator(); + ICPPTemplateParameter[] result = ICPPTemplateParameter.EMPTY_TEMPLATE_PARAMETER_ARRAY; + if (lambdaDtor != null) { + // Create an invented template parameter for every "auto" in the lambda's + // function parameter list. + int position = 0; + ICPPASTParameterDeclaration[] params = lambdaDtor.getParameters(); + for (ICPPASTParameterDeclaration param : params) { + IASTDeclSpecifier declSpec = param.getDeclSpecifier(); + if (declSpec instanceof IASTSimpleDeclSpecifier) { + if (((IASTSimpleDeclSpecifier) declSpec).getType() == IASTSimpleDeclSpecifier.t_auto) { + boolean isPack = param.getDeclarator().declaresParameterPack(); + result = ArrayUtil.append(result, new CPPImplicitTemplateTypeParameter( + fLambdaExpression, position, isPack)); + position++; + } + } + } + } + return ArrayUtil.trim(result); + } + private IType[] getParameterTypes() { ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator(); if (lambdaDtor != null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitMethodTemplate.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitMethodTemplate.java new file mode 100644 index 00000000000..8abf9dca53b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitMethodTemplate.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2017 Nathan Ridge. + * 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 + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; + +/** + * Binding for implicit method templates. + * + * Used for the function call operator and pointer-to-function conversion operator + * of a generic lambda. + */ +public class CPPImplicitMethodTemplate extends CPPImplicitMethod implements ICPPFunctionTemplate { + private ICPPTemplateParameter[] fTemplateParameters; + + public CPPImplicitMethodTemplate(ICPPTemplateParameter[] templateParameters, ICPPClassScope scope, + char[] name, ICPPFunctionType type, ICPPParameter[] params, boolean isConstexpr) { + super(scope, name, type, params, isConstexpr); + fTemplateParameters = templateParameters; + for (ICPPTemplateParameter parameter : templateParameters) { + if (parameter instanceof CPPImplicitTemplateTypeParameter) { + ((CPPImplicitTemplateTypeParameter) parameter).setContainingTemplate(this); + } + } + } + + @Override + public ICPPTemplateParameter[] getTemplateParameters() { + return fTemplateParameters; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitTemplateTypeParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitTemplateTypeParameter.java new file mode 100644 index 00000000000..e5b552422da --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitTemplateTypeParameter.java @@ -0,0 +1,164 @@ +/******************************************************************************* + * Copyright (c) 2017 Nathan Ridge. + * 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 + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ILinkage; +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.ITypedef; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; +import org.eclipse.cdt.core.parser.util.CharArrayUtils; +import org.eclipse.cdt.internal.core.dom.Linkage; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; +import org.eclipse.core.runtime.PlatformObject; + +/** + * Binding for implicit template type parameters. + * + * Used for the template type parameters of implicit method templates. + */ +public class CPPImplicitTemplateTypeParameter extends PlatformObject implements ICPPTemplateTypeParameter, + ICPPUnknownType, ICPPUnknownBinding { + private int fParameterID; + private boolean fIsParameterPack; + private ICPPScope fUnknownScope; + + // The containing (implicit) template definition. + private ICPPTemplateDefinition fContainingTemplate; + + // The AST node that triggered the creation of the implicit template. + // For methods of generic lambdas, this is the lambda expression. + private IASTNode fNode; + + public CPPImplicitTemplateTypeParameter(IASTNode node, int position, boolean isParameterPack) { + fParameterID = computeParameterID(position); + fIsParameterPack = isParameterPack; + fNode = node; + } + + private int computeParameterID(int position) { + int nesting = 0; + for (IASTNode node = fNode; node != null; node = node.getParent()) { + if (node instanceof ICPPASTInternalTemplateDeclaration) { + nesting = ((ICPPASTInternalTemplateDeclaration) node).getNestingLevel(); + break; + } + } + return (nesting << 16) + (position & 0xffff); + } + + public void setContainingTemplate(ICPPTemplateDefinition containingTemplate) { + fContainingTemplate = containingTemplate; + } + + @Override + public String[] getQualifiedName() throws DOMException { + return new String[] { getName() }; + } + + @Override + public char[][] getQualifiedNameCharArray() throws DOMException { + return new char[][] { getNameCharArray() }; + } + + @Override + public boolean isGloballyQualified() throws DOMException { + return false; + } + + @Override + public String getName() { + return new String(); + } + + @Override + public char[] getNameCharArray() { + // Implicit template parameters are unnamed. + return CharArrayUtils.EMPTY; + } + + @Override + public ILinkage getLinkage() { + return Linkage.CPP_LINKAGE; + } + + @Override + public IBinding getOwner() { + return fContainingTemplate; + } + + @Override + public IScope getScope() throws DOMException { + // TODO: Do we need an implicit template scope for the implicit template + // parameter to live in? + return CPPVisitor.getContainingScope(fNode); + } + + @Override + public short getParameterPosition() { + return (short) fParameterID; + } + + @Override + public short getTemplateNestingLevel() { + return (short) (fParameterID >> 16); + } + + @Override + public int getParameterID() { + return fParameterID; + } + + @Override + public ICPPTemplateArgument getDefaultValue() { + // Implicit template parameters do not have default arguments. + return null; + } + + @Override + public boolean isParameterPack() { + return fIsParameterPack; + } + + @Override + public IType getDefault() throws DOMException { + return null; + } + + @Override + public boolean isSameType(IType type) { + if (type == this) + return true; + if (type instanceof ITypedef) + return type.isSameType(this); + if (!(type instanceof ICPPTemplateTypeParameter)) + return false; + + return getParameterID() == ((ICPPTemplateParameter) type).getParameterID(); + } + + @Override + public Object clone() { + return new CPPImplicitTemplateTypeParameter(fNode, getParameterPosition(), fIsParameterPack); + } + + @Override + public ICPPScope asScope() throws DOMException { + if (fUnknownScope == null) { + fUnknownScope = new CPPUnknownTypeScope(this, null); + } + return fUnknownScope; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 1c148f0e7c8..6f13aa060cb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -170,6 +170,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.dom.ast.util.ReturnStatementVisitor; import org.eclipse.cdt.core.index.IIndex; @@ -195,6 +196,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructor; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration; @@ -1887,10 +1889,17 @@ public class CPPVisitor extends ASTQueries { public static IType createType(final ICPPASTParameterDeclaration pdecl, boolean forFuncType) { IASTDeclSpecifier pDeclSpec = pdecl.getDeclSpecifier(); ICPPASTDeclarator pDtor = pdecl.getDeclarator(); - IType pt = createType(pDeclSpec); - if (pDtor != null) { - pt = createType(pt, pDtor); + IType pt; + PlaceholderKind placeholder = usesAuto(pDeclSpec); + if (placeholder != null) { + pt = createAutoType(pDeclSpec, pDtor, 0, placeholder); + } else { + pt = createType(pDeclSpec); + if (pDtor != null) { + pt = createType(pt, pDtor); + } } + pt= adjustParameterType(pt, forFuncType); if (pDtor != null && findInnermostDeclarator(pDtor).declaresParameterPack()) { @@ -2118,6 +2127,40 @@ public class CPPVisitor extends ASTQueries { return type; } + private static IType createAutoParameterType(IASTDeclSpecifier declSpec, IASTDeclarator declarator, + ICPPASTParameterDeclaration declaration, PlaceholderKind placeholder) { + // decltype(auto) is not allowed in parameters. + if (placeholder == PlaceholderKind.DecltypeAuto) { + return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; + } + + // In C++14, auto is only allowed in lambda parameters. + // In the Concepts TS (not implemented yet), this restriction is removed. + ICPPASTFunctionDeclarator functionDeclarator = (ICPPASTFunctionDeclarator) declaration.getParent(); + if (functionDeclarator.getParent() instanceof ICPPASTLambdaExpression) { + ICPPASTLambdaExpression lambda = (ICPPASTLambdaExpression) functionDeclarator.getParent(); + CPPClosureType closure = (CPPClosureType) lambda.getExpressionType(); + ICPPTemplateParameter[] templateParameters = closure.getInventedTemplateParameterList(); + + // Find the invented template parameter corresponding to this 'auto'. + int templateParameterIndex = -1; + for (ICPPASTParameterDeclaration parameter : functionDeclarator.getParameters()) { + if (usesAuto(parameter.getDeclSpecifier()) != null) { + ++templateParameterIndex; + } + if (parameter == declaration) + break; + } + if (templateParameterIndex >= 0 && templateParameterIndex < templateParameters.length) { + ICPPTemplateParameter templateParameter = templateParameters[templateParameterIndex]; + if (templateParameter instanceof ICPPTemplateTypeParameter) { + return createType((ICPPTemplateTypeParameter) templateParameter, declarator); + } + } + } + return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; + } + private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator, int flags, PlaceholderKind placeholderKind) { IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ? @@ -2134,6 +2177,10 @@ public class CPPVisitor extends ASTQueries { return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator, flags, placeholderKind); } + if (declarator.getParent() instanceof ICPPASTParameterDeclaration) { + return createAutoParameterType(declSpec, declarator, + (ICPPASTParameterDeclaration) declarator.getParent(), placeholderKind); + } ICPPASTInitializerClause autoInitClause= null; IASTNode parent = declarator.getParent().getParent(); if (parent instanceof ICPPASTNewExpression) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java index 4dd1aa86f5d..e76618215d2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/IndexerASTVisitor.java @@ -262,14 +262,19 @@ abstract public class IndexerASTVisitor extends ASTVisitor { final IASTName closureName = lambdaExpr.getClosureTypeName(); visit(closureName, fDefinitionName); - // Definition of call operator - IASTName callOp= lambdaExpr.getFunctionCallOperatorName(); - visit(callOp, closureName); - + + // Definition of call operator and conversion operator (if applicable) + IASTName[] ops = lambdaExpr.getImplicitNames(); + for (IASTName op : ops) { + visit(op, closureName); + + } + IBinding owner = CPPVisitor.findDeclarationOwner(lambdaExpr, true); boolean localToFunction = owner instanceof IFunction; if (!localToFunction) - push(callOp, lambdaExpr); // Local closures don't appear in the index, so don't refer to them. + // Local closures don't appear in the index, so don't refer to them. + push(lambdaExpr.getFunctionCallOperatorName(), lambdaExpr); ICPPASTFunctionDeclarator dtor = lambdaExpr.getDeclarator(); if (dtor != null && !dtor.accept(this))