diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index a8629e522cd..f7f7b791973 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -10170,6 +10170,30 @@ public class AST2CPPTests extends AST2TestBase { public void testOverrideSpecifierAfterTrailingReturnType_489876() throws Exception { parseAndCheckBindings(); } + + // auto (*x1)() -> int; + // int (*x2)(); + // + // auto (*y1)() -> int(*)(); + // int (*(*y2)())(); + // + // auto (*z1)() -> auto(*)() -> int(*)(); + // int (*(*(*z2)())())(); + public void testTrailingReturnTypeInFunctionPointer() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + + ICPPVariable x1 = bh.assertNonProblem("x1"); + ICPPVariable x2 = bh.assertNonProblem("x2"); + assertSameType(x1.getType(), x2.getType()); + + ICPPVariable y1 = bh.assertNonProblem("y1"); + ICPPVariable y2 = bh.assertNonProblem("y2"); + assertSameType(y1.getType(), y2.getType()); + + ICPPVariable z1 = bh.assertNonProblem("z1"); + ICPPVariable z2 = bh.assertNonProblem("z2"); + assertSameType(z1.getType(), z2.getType()); + } // struct CHAINER { // CHAINER const & operator,(int x) const; 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 ebd82c2bff3..3718b1c15ac 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 @@ -10306,4 +10306,26 @@ public class AST2TemplateTests extends AST2TestBase { public void testReferenceBinding_Regression_516284() throws Exception { parseAndCheckBindings(); } + + // // Declare a constexpr function that turns int and int& into different values. + // template constexpr int foo(); + // template <> constexpr int foo() { return 42; }; + // template <> constexpr int foo() { return 43; }; + // + // template + // constexpr int bar(T arg) { + // // Bind a TypeOfDependentExpression to an 'auto'. + // auto local = *&arg; + // + // // Leak the deduced type via the return value. + // return foo(); + // } + // + // // Instantiate with [T = int] and capture the return value. + // constexpr int waldo = bar(0); + public void testDependentTypeBindingToAuto_408470() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + // Check that the TypeOfDependentExpression instantiated to the correct type. + helper.assertVariableValue("waldo", 42); + } } 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 d0c7ee30264..6367f83e926 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.ReturnTypeDeductionTests; import org.eclipse.cdt.core.parser.tests.ast2.cxx14.VariableTemplateTests; import org.eclipse.cdt.core.parser.tests.prefix.CompletionTestSuite; @@ -59,6 +60,7 @@ public class DOMParserTestSuite extends TestCase { suite.addTest(VariableReadWriteFlagsTest.suite()); suite.addTest(AST2CPPAttributeTests.suite()); suite.addTest(VariableTemplateTests.suite()); + suite.addTestSuite(ReturnTypeDeductionTests.class); return suite; } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java index c7fc2da1d65..27ad1d7cfdd 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/SemanticTestBase.java @@ -20,6 +20,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding; +import org.eclipse.cdt.core.dom.ast.IProblemType; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.testplugin.util.BaseTestCase; @@ -348,6 +349,11 @@ public class SemanticTestBase extends BaseTestCase { assertSameType(expectedType, var.getType()); } + public void assertVariableTypeProblem(String variableName) { + IVariable var = assertNonProblem(variableName); + assertInstance(var.getType(), IProblemType.class); + } + public void assertVariableValue(String variableName, long expectedValue) { IVariable var = assertNonProblem(variableName); BaseTestCase.assertVariableValue(var, expectedValue); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java new file mode 100644 index 00000000000..3470cb7c8a2 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionIndexTests.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.internal.index.tests.IndexBindingResolutionTestBase; + +public class ReturnTypeDeductionIndexTests extends IndexBindingResolutionTestBase { + public ReturnTypeDeductionIndexTests() { + setStrategy(new SinglePDOMTestStrategy(true)); + } + + // struct A { + // auto f(); + // }; + // auto A::f() { return 42; } + + // auto waldo = A().f(); + public void testOutOfLineMethod1() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableType("waldo", CommonCPPTypes.int_); + } + + // struct A { + // auto f(); + // }; + + // auto A::f() { return 42; } + // auto waldo = A().f(); + public void _testOutOfLineMethod2() throws Exception { + // TODO(nathanridge): Definition is a different file from the declaration is not supported yet. + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableType("waldo", CommonCPPTypes.int_); + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java new file mode 100644 index 00000000000..09f7c18b63a --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/ReturnTypeDeductionTests.java @@ -0,0 +1,282 @@ +/******************************************************************************* + * 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.IProblemType; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.ITypedef; +import org.eclipse.cdt.core.parser.ParserLanguage; +import org.eclipse.cdt.core.parser.tests.ast2.AST2TestBase; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; + +public class ReturnTypeDeductionTests extends AST2TestBase { + private BindingAssertionHelper getAssertionHelper() throws Exception { + return getAssertionHelper(ParserLanguage.CPP); + } + + private void assertReturnType(String functionName, IType returnType) throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + ICPPFunction f = bh.assertNonProblem(functionName); + assertSameType(f.getType().getReturnType(), returnType); + } + + private void assertReturnTypeProblem(String functionName) throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + ICPPFunction f = bh.assertNonProblem(functionName); + assertInstance(f.getType().getReturnType(), IProblemType.class); + } + + private void assertLambdaReturnType(String lambdaName, IType returnType) throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + ICPPVariable lambda = bh.assertNonProblem(lambdaName); + IType lambdaType = lambda.getType(); + assertInstance(lambdaType, CPPClosureType.class); + ICPPFunction f = ((CPPClosureType) lambdaType).getFunctionCallOperator(); + assertSameType(f.getType().getReturnType(), returnType); + } + + // auto f() { return 42; } + public void testSingleReturn() throws Exception { + assertReturnType("f", CommonCPPTypes.int_); + } + + // auto f(int x) { + // if (x < 10) + // return 42; + // else + // return 0; + // } + public void testMultipleReturnsSameType() throws Exception { + assertReturnType("f", CommonCPPTypes.int_); + } + + // auto f(int x) { + // if (x < 10) + // return 42; + // else + // return 0.0; + // } + public void testMultipleReturnsDifferentTypes() throws Exception { + assertReturnTypeProblem("f"); + } + + // auto f() { + // return f(); + // } + public void testFullyRecursiveFunction() throws Exception { + assertReturnTypeProblem("f"); + } + + // auto sum(int i) { + // if (i == 1) + // return i; + // else + // return sum(i - 1) + i; + // } + public void testPartiallyRecursiveFunction() throws Exception { + assertReturnType("sum", CommonCPPTypes.int_); + } + + // template + // auto f(T t) { + // return t; + // } + // typedef decltype(f(1)) fint_t; + public void testFunctionTemplate() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + ITypedef t = bh.assertNonProblem("fint_t"); + assertSameType(t, CommonCPPTypes.int_); + } + + // template auto f(T t) { return t; } + // template auto f(T* t) { return *t; } + // void g() { int (*p)(int*) = &f; } + public void testAddressOfFunction() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + ICPPFunctionTemplate f2 = bh.assertNonProblem("f(T*", 1); + ICPPTemplateInstance fi = bh.assertNonProblem("f;", 1); + assertSame(f2, fi.getSpecializedBinding()); + } + + // struct A { static int i; }; + // auto& f1() { return A::i; } + // auto&& f2() { return A::i; } + // auto&& f3() { return 42; } + // const auto& f4() { return A::i; } + // const auto&& f5() { return 42; } + public void testAutoRef() throws Exception { + assertReturnType("f1", CommonCPPTypes.referenceToInt); + assertReturnType("f2", CommonCPPTypes.referenceToInt); + assertReturnType("f3", CommonCPPTypes.rvalueReferenceToInt); + assertReturnType("f4", CommonCPPTypes.referenceToConstInt); + assertReturnType("f5", CommonCPPTypes.rvalueReferenceToConstInt); + } + + // struct A { static int i; }; + // auto* f1() { return &A::i; } + // const auto* f2() { return &A::i; } + public void testAutoPointer() throws Exception { + assertReturnType("f1", CommonCPPTypes.pointerToInt); + assertReturnType("f2", CommonCPPTypes.pointerToConstInt); + } + + // auto f1() {} + // auto& f2() {} + // auto* f3() {} + public void testVoidFunction() throws Exception { + assertReturnType("f1", CommonCPPTypes.void_); + assertReturnTypeProblem("f2"); + assertReturnTypeProblem("f3"); + } + + // struct A { static int i; }; + // auto f1() -> auto { return 42; } + // auto f2() -> auto& { return A::i; } + // auto f3() -> auto&& { return A::i; } + // auto f4() -> auto&& { return 42; } + // auto f5() -> const auto& { return A::i; } + // auto f6() -> const auto&& { return 42; } + // auto f7() -> auto* { return &A::i; } + // auto f8() -> const auto* { return &A::i; } + public void testAutoInTrailingReturnType() throws Exception { + assertReturnType("f1", CommonCPPTypes.int_); + assertReturnType("f2", CommonCPPTypes.referenceToInt); + assertReturnType("f3", CommonCPPTypes.referenceToInt); + assertReturnType("f4", CommonCPPTypes.rvalueReferenceToInt); + assertReturnType("f5", CommonCPPTypes.referenceToConstInt); + assertReturnType("f6", CommonCPPTypes.rvalueReferenceToConstInt); + assertReturnType("f7", CommonCPPTypes.pointerToInt); + assertReturnType("f8", CommonCPPTypes.pointerToConstInt); + } + + // int i; + // auto f1 = []() -> auto { return 42; }; + // auto f2 = []() -> auto& { return i; }; + // auto f3 = []() -> auto&& { return i; }; + // auto f4 = []() -> auto&& { return 42; }; + public void testAutoInLambdaReturnType() throws Exception { + assertLambdaReturnType("f1", CommonCPPTypes.int_); + assertLambdaReturnType("f2", CommonCPPTypes.referenceToInt); + assertLambdaReturnType("f3", CommonCPPTypes.referenceToInt); + assertLambdaReturnType("f4", CommonCPPTypes.rvalueReferenceToInt); + } + + // struct A { + // virtual auto f() { return 42; } + // virtual decltype(auto) g() { return 42; } + // }; + public void testVirtualAutoFunction() throws Exception { + assertReturnTypeProblem("f"); + assertReturnTypeProblem("g"); + } + + // auto f() { return {1, 2, 3}; } + public void testInitializerList() throws Exception { + assertReturnTypeProblem("f"); + } + + // int f(int); + // int g(int); + // template + // auto foo(bool cond, T arg) { + // if (cond) { + // return f(arg); + // } else { + // return g(arg); + // } + // } + // void bar(bool cond) { + // foo(cond, 0); + // } + public void _testMultipleDependentReturns() throws Exception { + // TODO: To pass this test, we need to defer the checking of whether + // all paths return the same type, until after instantiation. + BindingAssertionHelper bh = getAssertionHelper(); + bh.assertNonProblem("foo(cond", "foo"); + } + + // decltype(auto) f() { return 42; } + // decltype(auto) g(int* arg) { return *arg; } + public void testDecltypeAuto() throws Exception { + assertReturnType("f", CommonCPPTypes.int_); + assertReturnType("g", CommonCPPTypes.referenceToInt); + } + + // auto f() -> decltype(auto) { return 42; } + // auto g(int* arg) -> decltype(auto) { return *arg; } + // auto L1 = []() -> decltype(auto) { return 42; }; + // auto L2 = [](int* arg) -> decltype(auto) { return *arg; }; + public void testDecltypeAutoInTrailingReturnType() throws Exception { + assertReturnType("f", CommonCPPTypes.int_); + assertReturnType("g", CommonCPPTypes.referenceToInt); + assertLambdaReturnType("L1", CommonCPPTypes.int_); + assertLambdaReturnType("L2", CommonCPPTypes.referenceToInt); + } + + // int i; + // decltype(auto)& f() { return i; } + // decltype(auto)* g() { return &i; } + // auto f2() -> decltype(auto)& { return i; } + // auto g2() -> decltype(auto)* { return &i; } + public void testDecltypeAutoWithDecoration() throws Exception { + assertReturnTypeProblem("f"); + assertReturnTypeProblem("g"); + assertReturnTypeProblem("f2"); + assertReturnTypeProblem("g2"); + } + + // auto f(); + // auto waldo = f(); + public void testUseWithoutDefinition() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableTypeProblem("waldo"); + } + + // auto f(); + // auto f() { return 42; } + // auto waldo = f(); + public void testUseAfterDefinition() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableType("waldo", CommonCPPTypes.int_); + } + + // auto f(); + // auto waldo = f(); + // auto f() { return 42; } + public void _testUseBeforeDefinition() throws Exception { + // TODO: To pass this test, we need to apply declaredBefore() filtering + // to the definition search in CPPFunction.getType(). + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableTypeProblem("waldo"); + } + + // auto f() { return 42; } + // int f(); + public void testRedeclaration() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ICPPFunction autoFunction = helper.assertNonProblem("auto f", "f"); + // If we start diagnosing invalid redeclarations as errors, it would be + // appropriate to start doing assertProblem() for the "f" in "int f" instead. + ICPPFunction intFunction = helper.assertNonProblem("int f", "f"); + assertNotSame(autoFunction, intFunction); + } + + // struct A { + // auto f(); + // }; + // auto A::f() { return 42; } + // auto waldo = A().f(); + public void testOutOfLineMethod() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableType("waldo", CommonCPPTypes.int_); + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java index 8ba165b3c0e..14b10991fcd 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBindingResolutionTestBase.java @@ -385,6 +385,12 @@ public abstract class IndexBindingResolutionTestBase extends SemanticTestBase { } return i - offset; } + + // Get a BindingAssertionHelper for the last AST. + protected BindingAssertionHelper getAssertionHelper() { + int index = strategy.getAstCount() - 1; + return new BindingAssertionHelper(strategy.getAstSource(index).toString(), strategy.getAst(index)); + } static protected class NameCollector extends ASTVisitor { { 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 abca9c24f3d..fa332dafe62 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,8 @@ *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; +import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionIndexTests; + import junit.framework.Test; import junit.framework.TestSuite; @@ -35,6 +37,8 @@ public class IndexTests extends TestSuite { suite.addTest(IndexMultiVariantHeaderTest.suite()); suite.addTest(IndexMultiFileTest.suite()); + suite.addTestSuite(ReturnTypeDeductionIndexTests.class); + IndexCPPBindingResolutionBugs.addTests(suite); IndexCPPBindingResolutionTest.addTests(suite); IndexGPPBindingResolutionTest.addTests(suite); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java index ed1cbe84578..4323debb875 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ISemanticProblem.java @@ -45,6 +45,8 @@ public interface ISemanticProblem { int TYPE_ENUMERATION_EXPECTED = 10006; /** @since 6.1 */ int TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = 10007; + /** @since 6.3 */ + int TYPE_AUTO_FOR_VIRTUAL_METHOD = 10008; /** * Returns the ID of the problem. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunction.java index 32b486443bb..e9bc623f64b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPFunction.java @@ -53,12 +53,23 @@ public interface ICPPFunction extends IFunction, ICPPBinding { public IType[] getExceptionSpecification(); /** - * {@inheritDoc} + * Returns the function's type. + * Any placeholders in the type are resolved. + * If the type contains placeholders and a function definition is not available to + * resolve them, a ProblemType is returned (call sites that do not need the + * placeholders resolved should call getDeclaredType() instead). * @since 5.1 */ @Override public ICPPFunctionType getType(); + /** + * Returns the function's declared type. + * This is the function's type without any placeholders resolved. + * @since 6.3 + */ + public ICPPFunctionType getDeclaredType(); + /** * @since 5.2 */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/util/ReturnStatementVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/util/ReturnStatementVisitor.java new file mode 100644 index 00000000000..4da39f21c24 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/util/ReturnStatementVisitor.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * 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.dom.ast.util; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; +import org.eclipse.cdt.core.dom.ast.IASTStatement; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression; + +/** + * An ASTVisitor that visits every return statement in a function + * body and calls onReturnStatement() on it. + * + * @since 6.3 + */ +public abstract class ReturnStatementVisitor extends ASTVisitor { + private final IASTFunctionDefinition fFunction; + + /** + * Constructs a ReturnStatementVisitor that will visit the + * body of a function. + * @param function the function to be visited + */ + protected ReturnStatementVisitor(IASTFunctionDefinition function) { + shouldVisitStatements = true; + shouldVisitDeclarations = true; + shouldVisitExpressions = true; + this.fFunction = function; + } + + /** + * Gets the function being visited. + */ + protected IASTFunctionDefinition getFunction() { + return fFunction; + } + + /** + * Called when a return statement is encountered in the function body. + * @param stmt the return statement that was encountered + */ + protected abstract void onReturnStatement(IASTReturnStatement stmt); + + @Override + public int visit(IASTDeclaration element) { + if (element != fFunction) + return PROCESS_SKIP; // skip inner functions + return PROCESS_CONTINUE; + } + + @Override + public int visit(IASTExpression expr) { + if (expr instanceof ICPPASTLambdaExpression) { + return PROCESS_SKIP; + } + return PROCESS_CONTINUE; + } + + @Override + public int visit(IASTStatement stmt) { + if (stmt instanceof IASTReturnStatement) { + onReturnStatement((IASTReturnStatement) stmt); + return PROCESS_SKIP; + } + return PROCESS_CONTINUE; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java index a27522ab04c..22872e3a964 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java @@ -44,7 +44,8 @@ public interface ITypeMarshalBuffer { UNKNOWN_MEMBER_TYPE = 0x10, INITIALIZER_LIST_TYPE = 0x11, DEFERRED_FUNCTION = 0x12, - DEFERRED_VARIABLE_INSTANCE = 0x13; + DEFERRED_VARIABLE_INSTANCE = 0x13, + PLACEHOLDER_TYPE = 0x14; // Can add more types up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE. final static byte diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java index 79c5db46a3a..eea497c10b6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ProblemType.java @@ -21,6 +21,7 @@ import org.eclipse.core.runtime.CoreException; */ public class ProblemType implements IProblemType, ISerializableType { public static final IType AUTO_FOR_NON_STATIC_FIELD = new ProblemType(TYPE_AUTO_FOR_NON_STATIC_FIELD); + public static final IType AUTO_FOR_VIRTUAL_METHOD = new ProblemType(TYPE_AUTO_FOR_VIRTUAL_METHOD); public static final IType CANNOT_DEDUCE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_AUTO_TYPE); public static final IType CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE); public static final IType ENUMERATION_EXPECTED = new ProblemType(TYPE_ENUMERATION_EXPECTED); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassSpecialization.java index 1d1cc7d212e..5b5bcbd38c9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassSpecialization.java @@ -129,6 +129,11 @@ public class CPPClassSpecialization extends CPPSpecialization return false; } + @Override + public ICPPFunctionType getDeclaredType() { + return new ProblemFunctionType(getID()); + } + @Override public ICPPFunctionType getType() { return new ProblemFunctionType(getID()); 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 991f4d758dd..4b8717511b4 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 @@ -22,11 +22,10 @@ import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.dom.ast.EScopeKind; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; -import org.eclipse.cdt.core.dom.ast.IASTExpression; +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.IASTReturnStatement; -import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IBinding; @@ -52,9 +51,9 @@ import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.IContentAssistMatcher; import org.eclipse.cdt.internal.core.dom.Linkage; -import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; +import org.eclipse.cdt.internal.core.dom.parser.ProblemType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType.PlaceholderKind; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; -import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory; import org.eclipse.core.runtime.PlatformObject; @@ -143,33 +142,29 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP } private IType getReturnType() { + IASTDeclSpecifier declSpecForDeduction = null; + IASTDeclarator declaratorForDeduction = null; ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator(); + PlaceholderKind placeholder = null; if (lambdaDtor != null) { IASTTypeId trailingReturnType = lambdaDtor.getTrailingReturnType(); if (trailingReturnType != null) { - return CPPVisitor.createType(trailingReturnType); + IASTDeclSpecifier declSpec = trailingReturnType.getDeclSpecifier(); + placeholder = CPPVisitor.usesAuto(declSpec); + if (placeholder != null) { + declSpecForDeduction = declSpec; + declaratorForDeduction = trailingReturnType.getAbstractDeclarator(); + } else { + return CPPVisitor.createType(trailingReturnType); + } } } IASTCompoundStatement body = fLambdaExpression.getBody(); if (body != null) { - IASTStatement[] stmts = body.getStatements(); - if (stmts.length > 0) { - // Gnu extension allows to deduce return type in complex compound statements - IASTStatement stmt= stmts[stmts.length - 1]; - if (stmt instanceof IASTReturnStatement) { - IASTReturnStatement rtstmt= (IASTReturnStatement) stmt; - IASTExpression expr= rtstmt.getReturnValue(); - if (expr != null) { - IType type= expr.getExpressionType(); - type= Conversions.lvalue_to_rvalue(type, false); - if (type != null) { - return type; - } - } - } - } + return CPPVisitor.deduceReturnType(body, declSpecForDeduction, declaratorForDeduction, + placeholder, body); } - return CPPSemantics.VOID_TYPE; + return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; } private IType[] getParameterTypes() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java index 3c284f5f7cf..59c01799955 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java @@ -117,6 +117,11 @@ public class CPPDeferredFunction extends CPPUnknownBinding implements ICPPDeferr return ICPPParameter.EMPTY_CPPPARAMETER_ARRAY; } + @Override + public ICPPFunctionType getDeclaredType() { + return FUNCTION_TYPE; + } + @Override public ICPPFunctionType getType() { return FUNCTION_TYPE; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java index 52925f4c5ac..034e501b699 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java @@ -51,6 +51,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.ProblemFunctionType; +import org.eclipse.cdt.internal.core.dom.parser.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.core.runtime.PlatformObject; @@ -68,6 +69,7 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt protected IASTDeclarator[] declarations; protected ICPPASTFunctionDeclarator definition; + protected ICPPFunctionType declaredType; protected ICPPFunctionType type; private static final int FULLY_RESOLVED = 1; @@ -294,23 +296,47 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt return null; } - @Override + // Helper function for getDeclaredType() and getType(). + public static ICPPFunctionType toFunctionType(IType type) { + if (type instanceof ICPPFunctionType) { + return (ICPPFunctionType) type; + } else { + type = getNestedType(type, TDEF); + if (type instanceof ICPPFunctionType) { + return (ICPPFunctionType) type; + } else if (type instanceof ISemanticProblem) { + return new ProblemFunctionType(((ISemanticProblem) type).getID()); + } else { + // This case is unexpected + return new ProblemFunctionType(ISemanticProblem.TYPE_UNRESOLVED_NAME); + } + } + } + + @Override + public ICPPFunctionType getDeclaredType() { + if (declaredType == null) { + IType t = CPPVisitor.createType((definition != null) ? definition : declarations[0], + CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS); + declaredType = toFunctionType(t); + } + return declaredType; + } + + @Override public ICPPFunctionType getType() { if (type == null) { + // TODO: As an optimization, check if declaredType contains placeholders, + // and if it doesn't, just return that. IType t = CPPVisitor.createType((definition != null) ? definition : declarations[0]); - if (t instanceof ICPPFunctionType) { - type = (ICPPFunctionType) t; - } else { - t = getNestedType(t, TDEF); - if (t instanceof ICPPFunctionType) { - type = (ICPPFunctionType) t; - } else if (t instanceof ISemanticProblem) { - type= new ProblemFunctionType(((ISemanticProblem) t).getID()); - } else { - // This case is unexpected - type = new ProblemFunctionType(ISemanticProblem.TYPE_UNRESOLVED_NAME); + // The declaration may not specify the return type, so look at the definition. + if (t == ProblemType.NO_NAME) { + findDefinition(); + if (definition != null) { + t = CPPVisitor.createType(definition); } } + type = toFunctionType(t); } return type; } @@ -713,4 +739,13 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt } return null; } + + private void findDefinition() { + if (definition != null) + return; + + IASTName[] definitions = declarations[0].getTranslationUnit().getDefinitionsInAST(this); + if (definitions.length != 0) + addDefinition(definitions[0]); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java index 4e4760ef565..347465a9b5b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java @@ -85,6 +85,11 @@ public class CPPFunctionSpecialization extends CPPSpecialization implements ICPP return null; } + @Override + public ICPPFunctionType getDeclaredType() { + return fType; + } + @Override public ICPPFunctionType getType() { return fType; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java index 1ba0c943bad..2f6bc36efe4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java @@ -12,9 +12,6 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; - import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; @@ -29,7 +26,6 @@ import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IScope; -import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; @@ -40,7 +36,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.parser.util.AttributeUtil; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; -import org.eclipse.cdt.internal.core.dom.parser.ProblemFunctionType; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; @@ -49,6 +44,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; */ public class CPPFunctionTemplate extends CPPTemplateDefinition implements ICPPFunctionTemplate, ICPPInternalFunction { + protected ICPPFunctionType declaredType; protected ICPPFunctionType type; public CPPFunctionTemplate(IASTName name) { @@ -169,6 +165,20 @@ public class CPPFunctionTemplate extends CPPTemplateDefinition return null; } + @Override + public ICPPFunctionType getDeclaredType() { + if (declaredType == null) { + IASTName name = getTemplateName(); + IASTNode parent = name.getParent(); + while (parent.getParent() instanceof IASTDeclarator) + parent = parent.getParent(); + + IType t = CPPVisitor.createType((IASTDeclarator) parent, CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS); + declaredType = CPPFunction.toFunctionType(t); + } + return declaredType; + } + @Override public ICPPFunctionType getType() { if (type == null) { @@ -176,16 +186,11 @@ public class CPPFunctionTemplate extends CPPTemplateDefinition IASTNode parent = name.getParent(); while (parent.getParent() instanceof IASTDeclarator) parent = parent.getParent(); - - IType t = getNestedType(CPPVisitor.createType((IASTDeclarator) parent), TDEF); - if (t instanceof ICPPFunctionType) { - type = (ICPPFunctionType) t; - } else if (t instanceof ISemanticProblem) { - type= new ProblemFunctionType(((ISemanticProblem) t).getID()); - } else { - // This case is unexpected. - type= new ProblemFunctionType(ISemanticProblem.TYPE_UNRESOLVED_NAME); - } + + IType t = CPPVisitor.createType((IASTDeclarator) parent); + // TODO(nathanridge): Do we need to search for the definition here, if t is + // ProblemType.NO_NAME, as in CPPFunction? + type = CPPFunction.toFunctionType(t); } return type; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitFunction.java index 037c827724b..80f95de70c2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPImplicitFunction.java @@ -52,6 +52,11 @@ public class CPPImplicitFunction extends CPPFunction { public ICPPFunctionType getType() { return functionType; } + + @Override + public ICPPFunctionType getDeclaredType() { + return functionType; + } @Override public String getName() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPPlaceholderType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPPlaceholderType.java new file mode 100644 index 00000000000..aae6e0f33df --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPPlaceholderType.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * 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.IType; +import org.eclipse.cdt.internal.core.dom.parser.ISerializableType; +import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; +import org.eclipse.core.runtime.CoreException; + +/** + * Represents an occurrence of 'auto' or 'decltype(auto)' that has + * not been resolved (replaced with a real type) because the information + * necessary to resolve it (the function's body) is not available yet. + */ +public class CPPPlaceholderType implements ISerializableType, IType { + public enum PlaceholderKind { + Auto, + DecltypeAuto + } + + private final PlaceholderKind fPlaceholderKind; + + public CPPPlaceholderType(PlaceholderKind placeholderKind) { + fPlaceholderKind = placeholderKind; + } + + public PlaceholderKind getPlaceholderKind() { + return fPlaceholderKind; + } + + @Override + public void marshal(ITypeMarshalBuffer buffer) throws CoreException { + short firstBytes = ITypeMarshalBuffer.PLACEHOLDER_TYPE; + if (fPlaceholderKind == PlaceholderKind.DecltypeAuto) { + firstBytes |= ITypeMarshalBuffer.FLAG1; + } + buffer.putShort(firstBytes); + } + + @Override + public boolean isSameType(IType type) { + if (type instanceof CPPPlaceholderType) { + return fPlaceholderKind == ((CPPPlaceholderType) type).fPlaceholderKind; + } + return false; + } + + @Override + public Object clone() { + IType t = null; + try { + t = (IType) super.clone(); + } catch (CloneNotSupportedException e) { + // not going to happen + } + return t; + } + + public static IType unmarshal(short firstBytes, ITypeMarshalBuffer buffer) { + PlaceholderKind kind = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0 + ? PlaceholderKind.DecltypeAuto + : PlaceholderKind.Auto; + return new CPPPlaceholderType(kind); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUnknownMethod.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUnknownMethod.java index 897c00935b4..78eca5e6179 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUnknownMethod.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUnknownMethod.java @@ -65,6 +65,11 @@ public class CPPUnknownMethod extends CPPUnknownMember implements ICPPMethod { return ICPPParameter.EMPTY_CPPPARAMETER_ARRAY; } + @Override + public ICPPFunctionType getDeclaredType() { + return FUNCTION_TYPE; + } + @Override public ICPPFunctionType getType() { // TODO(nathanridge): We'd like to return a TypeOfUnknownMember here, diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AutoTypeResolver.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AutoTypeResolver.java index 72f88969624..67373b6e82a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AutoTypeResolver.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AutoTypeResolver.java @@ -47,6 +47,11 @@ class AutoTypeResolver implements ICPPFunctionTemplate { return TEMPLATE_PARAMETERS; } + @Override + public ICPPFunctionType getDeclaredType() { + return functionType; + } + @Override public ICPPFunctionType getType() { return functionType; 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 ece87713b22..c53f6b44ef6 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 @@ -4318,8 +4318,9 @@ public class CPPSemantics { declarator= ASTQueries.findTypeRelevantDeclarator(declarator); if (declarator instanceof ICPPASTFunctionDeclarator) { - IType type = function.getType(); - return type.isSameType(CPPVisitor.createType(declarator)); + // For declaration matching, compare the declared types (placeholders not resolved). + IType type = function.getDeclaredType(); + return type.isSameType(CPPVisitor.createType(declarator, CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS)); } return false; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index 3e5e49aa2d2..ed2697d8a40 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -1523,10 +1523,15 @@ public class CPPTemplates { if (type instanceof ICPPUnknownBinding) { if (type instanceof TypeOfDependentExpression) { - ICPPEvaluation eval = ((TypeOfDependentExpression) type).getEvaluation(); + TypeOfDependentExpression dependentType = (TypeOfDependentExpression) type; + ICPPEvaluation eval = dependentType.getEvaluation(); ICPPEvaluation instantiated = eval.instantiate(context, IntegralValue.MAX_RECURSION_DEPTH); if (instantiated != eval) { - return CPPSemantics.getDeclTypeForEvaluation(instantiated, context.getPoint()); + if (dependentType.isForDecltype()) { + return CPPSemantics.getDeclTypeForEvaluation(instantiated, context.getPoint()); + } else { + return instantiated.getType(context.getPoint()); + } } } else { IBinding binding= resolveUnknown((ICPPUnknownBinding) type, context); 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 ea745bd177a..1c148f0e7c8 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 @@ -72,6 +72,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPointer; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTProblemHolder; +import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; @@ -170,6 +171,7 @@ 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.ICPPUsingDeclaration; +import org.eclipse.cdt.core.dom.ast.util.ReturnStatementVisitor; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -210,6 +212,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceAlias; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameter; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType.PlaceholderKind; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; @@ -241,6 +245,12 @@ public class CPPVisitor extends ASTQueries { private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = {}; public static final IASTInitializerClause[] NO_ARGS = {}; + // Flags for createType(). + public static final int RESOLVE_PLACEHOLDERS = 0x1; + + // Common combinations of flags. + public static final int DO_NOT_RESOLVE_PLACEHOLDERS = 0; + // Thread-local set of DeclSpecifiers for which auto types are being created. // Used to prevent infinite recursion while processing invalid self-referencing // auto-type declarations. @@ -1889,7 +1899,7 @@ public class CPPVisitor extends ASTQueries { return pt; } - private static IType createType(IType returnType, ICPPASTFunctionDeclarator fnDtor) { + private static IType createFunctionType(IType returnType, ICPPASTFunctionDeclarator fnDtor) { IType[] pTypes = createParameterTypes(fnDtor); IASTName name = fnDtor.getName().getLastName(); @@ -2038,7 +2048,24 @@ public class CPPVisitor extends ASTQueries { return type; } + public static PlaceholderKind usesAuto(IASTDeclSpecifier declSpec) { + if (declSpec instanceof ICPPASTSimpleDeclSpecifier) { + int declSpecType = ((ICPPASTSimpleDeclSpecifier) declSpec).getType(); + if (declSpecType == IASTSimpleDeclSpecifier.t_auto) { + return PlaceholderKind.Auto; + } else if (declSpecType == IASTSimpleDeclSpecifier.t_decltype_auto) { + return PlaceholderKind.DecltypeAuto; + } + } + return null; + } + public static IType createType(IASTDeclarator declarator) { + // Resolve placeholders by default. + return createType(declarator, RESOLVE_PLACEHOLDERS); + } + + public static IType createType(IASTDeclarator declarator, int flags) { if (declarator == null) return ProblemType.NO_NAME; @@ -2061,14 +2088,9 @@ public class CPPVisitor extends ASTQueries { throw new IllegalArgumentException(); } - if (declSpec instanceof ICPPASTSimpleDeclSpecifier) { - ICPPASTSimpleDeclSpecifier simpleDeclSpecifier = (ICPPASTSimpleDeclSpecifier) declSpec; - int declSpecifierType = simpleDeclSpecifier.getType(); - if (declSpecifierType == IASTSimpleDeclSpecifier.t_auto) { - return createAutoType(declSpec, declarator); - } else if (declSpecifierType == IASTSimpleDeclSpecifier.t_decltype_auto) { - return createDecltypeAutoType(declarator, simpleDeclSpecifier); - } + PlaceholderKind placeholder = usesAuto(declSpec); + if (placeholder != null) { + return createAutoType(declSpec, declarator, flags, placeholder); } IType type = createType(declSpec); @@ -2096,51 +2118,21 @@ public class CPPVisitor extends ASTQueries { return type; } - private static IType createDecltypeAutoType(IASTDeclarator declarator, ICPPASTSimpleDeclSpecifier simpleDeclSpecifier) { - IASTInitializerClause initializerClause = getInitializerClauseForDecltypeAuto(declarator); - if (initializerClause instanceof IASTExpression) { - return getDeclType((IASTExpression) initializerClause); - } - return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; - } - - private static IASTInitializerClause getInitializerClauseForDecltypeAuto(IASTDeclarator declarator) { - IASTInitializer initializer = declarator.getInitializer(); - if (initializer == null) { - ICPPASTNewExpression newExpression = findAncestorWithType(declarator, ICPPASTNewExpression.class); - if (newExpression != null) { - initializer = newExpression.getInitializer(); - } - } - if (initializer instanceof IASTEqualsInitializer) { - return ((IASTEqualsInitializer) initializer).getInitializerClause(); - } else if (initializer instanceof ICPPASTConstructorInitializer) { - ICPPASTConstructorInitializer constructorInitializer = (ICPPASTConstructorInitializer) initializer; - IASTInitializerClause[] arguments = constructorInitializer.getArguments(); - if (arguments.length == 1) { - return arguments[0]; - } - } else if (initializer instanceof IASTInitializerList) { - IASTInitializerList initializerList = (IASTInitializerList) initializer; - IASTInitializerClause[] clauses = initializerList.getClauses(); - if (clauses.length == 1) { - return clauses[0]; - } - } - - return null; - } - - private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator) { + private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator, + int flags, PlaceholderKind placeholderKind) { + IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ? + ProblemType.CANNOT_DEDUCE_AUTO_TYPE : + ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; Set recursionProtectionSet = autoTypeDeclSpecs.get(); if (!recursionProtectionSet.add(declSpec)) { // Detected a self referring auto type, e.g.: auto x = x; - return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; + return cannotDeduce; } try { if (declarator instanceof ICPPASTFunctionDeclarator) { - return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator); + return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator, flags, + placeholderKind); } ICPPASTInitializerClause autoInitClause= null; IASTNode parent = declarator.getParent().getParent(); @@ -2179,7 +2171,7 @@ public class CPPVisitor extends ASTQueries { beginExpr= new CPPASTFunctionCallExpression(new CPPASTIdExpression(name), beginCallArguments); } } else { - return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; + return cannotDeduce; } } autoInitClause= new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr); @@ -2198,74 +2190,239 @@ public class CPPVisitor extends ASTQueries { if (arguments.length == 1) autoInitClause = (ICPPASTInitializerClause) arguments[0]; } else if (initClause instanceof ICPPASTInitializerClause) { - autoInitClause= (ICPPASTInitializerClause) initClause; + if (initClause instanceof ICPPASTInitializerList) { + IASTInitializerClause[] clauses = ((ICPPASTInitializerList) initClause).getClauses(); + if (clauses.length == 1) { + autoInitClause = (ICPPASTInitializerClause) clauses[0]; + } + } + if (autoInitClause == null) { + autoInitClause= (ICPPASTInitializerClause) initClause; + } + } + } + if (autoInitClause == null) { + return cannotDeduce; + } + if (placeholderKind == PlaceholderKind.Auto) { + return createAutoType(autoInitClause.getEvaluation(), declSpec, declarator, autoInitClause); + } else /* decltype(auto) */ { + if (declarator.getPointerOperators().length > 0) { + // 'decltype(auto)' cannot be combined with * or & the way 'auto' can. + return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; + } + if (autoInitClause instanceof IASTExpression) { + return getDeclType((IASTExpression) autoInitClause); + } else { + return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; } } - return createAutoType(autoInitClause, declSpec, declarator); } finally { recursionProtectionSet.remove(declSpec); } } - private static IType createAutoType(ICPPASTInitializerClause initClause, IASTDeclSpecifier declSpec, - IASTDeclarator declarator) { + private static IType createAutoType(final ICPPEvaluation evaluation, IASTDeclSpecifier declSpec, + IASTDeclarator declarator, IASTNode point) { // C++0x: 7.1.6.4 - if (initClause == null) { - return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; - } - IType type = AutoTypeResolver.AUTO_TYPE; IType initType = null; ValueCategory valueCat= null; + initType = evaluation.getType(declarator); + valueCat = evaluation.getValueCategory(declarator); + if (initType == null || initType instanceof ISemanticProblem) { + return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; + } ICPPClassTemplate initializer_list_template = null; - if (initClause instanceof ICPPASTInitializerList) { + if (evaluation instanceof EvalInitList) { initializer_list_template = get_initializer_list(declSpec); if (initializer_list_template == null) { return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; } type = (IType) CPPTemplates.instantiate(initializer_list_template, - new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, initClause); + new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, point); if (type instanceof IProblemBinding) { return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; } } type = decorateType(type, declSpec, declarator); - final ICPPEvaluation evaluation = initClause.getEvaluation(); - initType= evaluation.getType(declarator); - valueCat= evaluation.getValueCategory(declarator); - if (initType == null || initType instanceof ISemanticProblem) { - return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; - } ICPPFunctionTemplate template = new AutoTypeResolver(type); CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1); TemplateArgumentDeduction.deduceFromFunctionArgs(template, Collections.singletonList(initType), - Collections.singletonList(valueCat), paramMap, initClause); + Collections.singletonList(valueCat), paramMap, point); ICPPTemplateArgument argument = paramMap.getArgument(0, 0); if (argument == null) { return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; } type = argument.getTypeValue(); + if (type instanceof TypeOfDependentExpression) { + // After binding to 'auto', a dependent type no longer acts like 'decltype(expr)'. + // For example, after instantiation it's no longer wrapped into a reference type + // if it's an lvalue the way 'decltype(expr)' usually is. + ((TypeOfDependentExpression) type).setIsForDecltype(false); + } IType t = SemanticUtil.substituteTypedef(type, initType); if (t != null) type = t; - if (initClause instanceof ICPPASTInitializerList) { + if (evaluation instanceof EvalInitList) { type = (IType) CPPTemplates.instantiate(initializer_list_template, - new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, initClause); + new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, point); } return decorateType(type, declSpec, declarator); } + + private static class ReturnTypeDeducer extends ReturnStatementVisitor { + private static final ICPPEvaluation voidEval = new EvalFixed( + CPPSemantics.VOID_TYPE, ValueCategory.PRVALUE, IntegralValue.UNKNOWN); + + private ICPPEvaluation fReturnEval = null; + private boolean fEncounteredReturnStatement = false; + + protected ReturnTypeDeducer(IASTFunctionDefinition func) { + super(func); + } + @Override + protected void onReturnStatement(IASTReturnStatement stmt) { + fEncounteredReturnStatement = true; + ICPPEvaluation returnEval = null; + IASTInitializerClause returnExpression = stmt.getReturnArgument(); + if (returnExpression == null) { + returnEval = voidEval; + } else { + + returnEval = ((ICPPASTInitializerClause) returnExpression).getEvaluation(); + } + IType returnType = returnEval.getType(stmt); + if (returnType instanceof ISemanticProblem) { + // If a function makes a recursive call in some of its return statements, + // the type those return expressions will be a problem type. We ignore + // these, because we can still successfully deduce from another return + // statement that is not recursive. + // If all return statements are recursive, fReturnEval will remain null + // and getReturnEvaluation() will construct an EvalFixed.INCOMPLETE as desired. + return; + } + + if (fReturnEval == null) { + fReturnEval = returnEval; + } else if (!fReturnEval.getType(stmt).isSameType(returnType)) { + fReturnEval = EvalFixed.INCOMPLETE; + } + } + + public ICPPEvaluation getReturnEvaluation() { + if (fReturnEval == null) { + if (!fEncounteredReturnStatement) { + return voidEval; + } + fReturnEval = EvalFixed.INCOMPLETE; + } + return fReturnEval; + } + } + + public static IType deduceReturnType(IASTStatement functionBody, IASTDeclSpecifier autoDeclSpec, + IASTDeclarator autoDeclarator, PlaceholderKind placeholder, IASTNode point) { + ICPPEvaluation returnEval = null; + if (functionBody != null) { + ReturnTypeDeducer deducer = new ReturnTypeDeducer(null); + functionBody.accept(deducer); + returnEval = deducer.getReturnEvaluation(); + } + if (returnEval == null || returnEval == EvalFixed.INCOMPLETE) { + return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; + } + + // [dcl.spec.auto] p7: + // If the deduction is for a return statement and the initializer is a + // braced-init-list, the proram is ill-formed. + if (returnEval instanceof EvalInitList) { + return ProblemType.CANNOT_DEDUCE_AUTO_TYPE; + } + + if (placeholder == PlaceholderKind.DecltypeAuto) { + if (autoDeclarator != null && autoDeclarator.getPointerOperators().length > 0) { + // 'decltype(auto)' cannot be combined with * or & the way 'auto' can. + return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE; + } + return CPPSemantics.getDeclTypeForEvaluation(returnEval, point); + } else /* auto */ { + if (autoDeclSpec == null || autoDeclarator == null) { + return returnEval.getType(point); + } else { + return createAutoType(returnEval, autoDeclSpec, autoDeclarator, autoDeclarator); + } + } + } + /** * C++0x: [8.3.5-2] */ - private static IType createAutoFunctionType(IASTDeclSpecifier declSpec, ICPPASTFunctionDeclarator declarator) { - IASTTypeId id= declarator.getTrailingReturnType(); - if (id == null) - return ProblemType.NO_NAME; - - IType t= createType(id.getAbstractDeclarator()); - t= qualifyType(t, declSpec); - return createType(t, declarator); + private static IType createAutoFunctionType(IASTDeclSpecifier declSpec, + ICPPASTFunctionDeclarator declarator, int flags, PlaceholderKind placeholder) { + IType returnType = null; + IASTDeclSpecifier declSpecForDeduction = null; + IASTDeclarator declaratorForDeduction = null; + IASTTypeId trailingReturnType = declarator.getTrailingReturnType(); + if (trailingReturnType == null) { + // No trailing return type. + if ((flags & RESOLVE_PLACEHOLDERS) != 0) { + declSpecForDeduction = declSpec; + declaratorForDeduction = declarator; + } else { + returnType = new CPPPlaceholderType(PlaceholderKind.Auto); + } + } else { + IASTDeclSpecifier trailingDeclSpec = trailingReturnType.getDeclSpecifier(); + IASTDeclarator trailingDeclarator = trailingReturnType.getAbstractDeclarator(); + PlaceholderKind trailingPlaceholder = usesAuto(trailingDeclSpec); + if (trailingPlaceholder != null && !(trailingDeclarator instanceof IASTFunctionDeclarator)) { + // Trailing return type uses 'auto', other than to introduce + // another trailing return type for a function type, so we'll + // need to look at the function body and deduce the return type. + declSpecForDeduction = trailingDeclSpec; + declaratorForDeduction = trailingDeclarator; + placeholder = trailingPlaceholder; + } else { + // Trailing return type specifies the type. + returnType = createType(trailingDeclarator); + returnType = qualifyType(returnType, declSpec); + } + } + + if (returnType == null) { + // Try to deduce return type from return statement. + + // [dcl.spec.auto] p14: + // A function declared with a return type that uses a placeholder type + // shall not be virtual. + if (((ICPPASTDeclSpecifier) declSpec).isVirtual()) + return ProblemType.AUTO_FOR_VIRTUAL_METHOD; + + ICPPASTFunctionDefinition definition= CPPFunction.getFunctionDefinition(declarator); + if (definition != null) { + returnType = deduceReturnType(definition.getBody(), declSpecForDeduction, + declaratorForDeduction, placeholder, declaratorForDeduction); + } + } + + if (returnType != null) { + // Do not use createFunctionType() because that would decorate the return type + // with pointer operators from e.g. an 'auto &', but we have already done that + // above. + IType[] pTypes = createParameterTypes(declarator); + RefQualifier refQualifier = declarator.getRefQualifier(); + IType result = new CPPFunctionType(returnType, pTypes, declarator.isConst(), declarator.isVolatile(), + refQualifier != null, refQualifier == RefQualifier.RVALUE, declarator.takesVarArgs()); + final IASTDeclarator nested = declarator.getNestedDeclarator(); + if (nested != null) { + result = createType(result, nested); + } + return result; + } + return ProblemType.NO_NAME; + } public static IType createType(IASTDeclSpecifier declSpec) { @@ -2310,10 +2467,12 @@ public class CPPVisitor extends ASTQueries { return ProblemType.UNRESOLVED_NAME; } + // Helper function for createAutoType(). private static IType decorateType(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) { type = qualifyType(type, declSpec); type = makeConstIfConstexpr(type, declSpec, declarator); - return createType(type, declarator); + // Ignore function declarator because we already handled that in createAutoFunctionType(). + return createType(type, declarator, true /* ignore function declarator */); } private static IType makeConstIfConstexpr(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) { @@ -2333,8 +2492,12 @@ public class CPPVisitor extends ASTQueries { } private static IType createType(IType baseType, IASTDeclarator declarator) { - if (declarator instanceof ICPPASTFunctionDeclarator) - return createType(baseType, (ICPPASTFunctionDeclarator) declarator); + return createType(baseType, declarator, false); + } + + private static IType createType(IType baseType, IASTDeclarator declarator, boolean ignoreFunctionDeclarator) { + if (!ignoreFunctionDeclarator && declarator instanceof ICPPASTFunctionDeclarator) + return createFunctionType(baseType, (ICPPASTFunctionDeclarator) declarator); IType type = baseType; type = applyAttributes(type, declarator); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java index 6d2489f18ee..11cbefdc4d7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -251,6 +251,10 @@ public class TemplateArgumentDeduction { TemplateArgumentDeduction deduct, IASTNode point) throws DOMException { boolean isReferenceTypeParameter= false; if (par instanceof ICPPReferenceType) { + // Cannot deduce a reference type from a void type. + if (SemanticUtil.isVoidType(arg)) { + return false; + } // If P is an rvalue reference to a cv-unqualified template parameter and the argument // is an lvalue, the type "lvalue reference to A" is used in place of A for type // deduction. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java index 687ba79c864..c0d3c6f09ea 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeOfDependentExpression.java @@ -27,15 +27,30 @@ import org.eclipse.core.runtime.CoreException; */ public class TypeOfDependentExpression extends CPPUnknownBinding implements ICPPUnknownType, ISerializableType { private final ICPPEvaluation fEvaluation; + // Whether this represents a decltype(expr), or a dependent type in another context. + private boolean fIsForDecltype; public TypeOfDependentExpression(ICPPEvaluation evaluation) { - super(null); - fEvaluation= evaluation; + this(evaluation, true); } - + + public TypeOfDependentExpression(ICPPEvaluation evaluation, boolean isForDecltype) { + super(null); + fEvaluation = evaluation; + fIsForDecltype = isForDecltype; + } + public ICPPEvaluation getEvaluation() { return fEvaluation; } + + public boolean isForDecltype() { + return fIsForDecltype; + } + + public void setIsForDecltype(boolean isForDecltype) { + fIsForDecltype = isForDecltype; + } @Override public boolean isSameType(IType type) { @@ -61,14 +76,20 @@ public class TypeOfDependentExpression extends CPPUnknownBinding implements ICPP @Override public void marshal(ITypeMarshalBuffer buffer) throws CoreException { - buffer.putShort(ITypeMarshalBuffer.DEPENDENT_EXPRESSION_TYPE); + short firstBytes = ITypeMarshalBuffer.DEPENDENT_EXPRESSION_TYPE; + if (fIsForDecltype) { + firstBytes |= ITypeMarshalBuffer.FLAG1; + } + buffer.putShort(firstBytes); buffer.marshalEvaluation(fEvaluation, false); } public static IType unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException { ICPPEvaluation eval= buffer.unmarshalEvaluation(); - if (eval != null) - return new TypeOfDependentExpression(eval); + if (eval != null) { + boolean isForDecltype = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0; + return new TypeOfDependentExpression(eval, isForDecltype); + } return ProblemType.UNKNOWN_FOR_EXPRESSION; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunction.java index b3251520216..caa9dfeea7c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPFunction.java @@ -70,6 +70,12 @@ class CompositeCPPFunction extends CompositeCPPBinding implements ICPPFunction, IType rtype = ((ICPPFunction) rbinding).getType(); return (ICPPFunctionType) cf.getCompositeType(rtype); } + + @Override + public ICPPFunctionType getDeclaredType() { + IType rtype = ((ICPPFunction) rbinding).getDeclaredType(); + return (ICPPFunctionType) cf.getCompositeType(rtype); + } @Override public boolean isDeleted() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.java index 9c8cdcb399f..6d88cac65cc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserMessages.java @@ -101,6 +101,7 @@ public class ParserMessages { case ISemanticProblem.TYPE_NOT_PERSISTED: return "ISemanticProblem.TYPE_NOT_PERSISTED"; case ISemanticProblem.TYPE_ENUMERATION_EXPECTED: return "ISemanticProblem.TYPE_ENUMERATION_EXPECTED"; case ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE: return "ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE"; + case ISemanticProblem.TYPE_AUTO_FOR_VIRTUAL_METHOD: return "ISemanticProblem.TYPE_AUTO_FOR_VIRTUAL_METHOD"; } return null; } 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 10a69519e75..ed4a546ed4b 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 @@ -75,3 +75,4 @@ ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION=Failure to determine type of expres ISemanticProblem.TYPE_NOT_PERSISTED=Failure to store type in the index ISemanticProblem.TYPE_ENUMERATION_EXPECTED=Enumeration expected ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE=Failure to determine decltype(auto)-type +ISemanticProblem.TYPE_AUTO_FOR_VIRTUAL_METHOD=Illegally auto-typed virtual method \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 333e9e7e9a5..051d16e9dc3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -285,10 +285,11 @@ public class PDOM extends PlatformObject implements IPDOM { * 207.0 - Store a caller record for macro reference names. * 208.0 - Trigger index rebuild to rebuild corrupted binding reference lists, bug 399147. * 209.0 - Alias templates and their instances take up more space than required, bug 516385. + * 210.0 - Return type deduction, bug 408470. */ - private static final int MIN_SUPPORTED_VERSION= version(209, 0); - private static final int MAX_SUPPORTED_VERSION= version(209, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(209, 0); + private static final int MIN_SUPPORTED_VERSION= version(210, 0); + private static final int MAX_SUPPORTED_VERSION= version(210, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(210, 0); private static int version(int major, int minor) { return (major << 16) + minor; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunction.java index 5891d316af3..9068cb45d9d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunction.java @@ -78,15 +78,19 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl /** Offset of the function body execution for constexpr functions. */ private static final int FUNCTION_BODY = REQUIRED_ARG_COUNT + 2; // Database.EXECUTION_SIZE + /** Offset of the function's declared type. */ + private static final int DECLARED_TYPE = FUNCTION_BODY + Database.EXECUTION_SIZE; // Database.TYPE_SIZE + /** * The size in bytes of a PDOMCPPFunction record in the database. */ @SuppressWarnings("hiding") - protected static final int RECORD_SIZE = FUNCTION_BODY + Database.EXECUTION_SIZE; + protected static final int RECORD_SIZE = DECLARED_TYPE + Database.TYPE_SIZE; private short fAnnotations = -1; private int fRequiredArgCount = -1; private ICPPFunctionType fType; // No need for volatile, all fields of ICPPFunctionTypes are final. + private ICPPFunctionType fDeclaredType; public PDOMCPPFunction(PDOMCPPLinkage linkage, PDOMNode parent, ICPPFunction function, boolean setTypes, IASTNode point) throws CoreException, DOMException { @@ -105,10 +109,11 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl return PDOMCPPAnnotations.encodeFunctionAnnotations(function); } - public void initData(ICPPFunctionType ftype, ICPPParameter[] params, IType[] exceptionSpec, - ICPPExecution functionBody) { + public void initData(ICPPFunctionType ftype, ICPPFunctionType declaredType, ICPPParameter[] params, + IType[] exceptionSpec, ICPPExecution functionBody) { try { setType(ftype); + setDeclaredType(declaredType); setParameters(params); storeExceptionSpec(exceptionSpec); getLinkage().storeExecution(record + FUNCTION_BODY, functionBody); @@ -124,16 +129,20 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl ICPPFunction func = (ICPPFunction) newBinding; ICPPFunctionType newType; + ICPPFunctionType newDeclaredType; ICPPParameter[] newParams; short newAnnotation; int newBindingRequiredArgCount; newType = func.getType(); + newDeclaredType = func.getDeclaredType(); newParams = func.getParameters(); newAnnotation = getAnnotations(func); newBindingRequiredArgCount = func.getRequiredArgumentCount(); fType = null; + fDeclaredType = null; linkage.storeType(record + FUNCTION_TYPE, newType); + linkage.storeType(record + DECLARED_TYPE, newDeclaredType); PDOMCPPParameter oldParams = getFirstParameter(null); int requiredCount; @@ -206,6 +215,11 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl fType = null; getLinkage().storeType(record + FUNCTION_TYPE, ft); } + + private void setDeclaredType(ICPPFunctionType ft) throws CoreException { + fType = null; + getLinkage().storeType(record + DECLARED_TYPE, ft); + } @Override public int getSignatureHash() throws CoreException { @@ -303,6 +317,19 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl } } + @Override + public ICPPFunctionType getDeclaredType() { + if (fDeclaredType == null) { + try { + fDeclaredType = (ICPPFunctionType) getLinkage().loadType(record + DECLARED_TYPE); + } catch (CoreException e) { + CCorePlugin.log(e); + fDeclaredType = new ProblemFunctionType(ISemanticProblem.TYPE_NOT_PERSISTED); + } + } + return fDeclaredType; + } + @Override public final ICPPFunctionType getType() { if (fType == null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionSpecialization.java index f2145aff430..2f34a9d1fef 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPFunctionSpecialization.java @@ -61,14 +61,18 @@ class PDOMCPPFunctionSpecialization extends PDOMCPPSpecialization /** Offset of the function body execution for constexpr functions. */ private static final int FUNCTION_BODY = REQUIRED_ARG_COUNT + 2; // Database.EXECUTION_SIZE + + /** Offset of the function's declared type. */ + private static final int DECLARED_TYPE = FUNCTION_BODY + Database.EXECUTION_SIZE; // Database.TYPE_SIZE /** * The size in bytes of a PDOMCPPFunctionSpecialization record in the database. */ @SuppressWarnings("hiding") - protected static final int RECORD_SIZE = FUNCTION_BODY + Database.EXECUTION_SIZE; + protected static final int RECORD_SIZE = DECLARED_TYPE + Database.TYPE_SIZE; private ICPPFunctionType fType; // No need for volatile, all fields of ICPPFunctionTypes are final. + private ICPPFunctionType fDeclaredType; private short fAnnotations= -1; private int fRequiredArgCount= -1; @@ -82,6 +86,10 @@ class PDOMCPPFunctionSpecialization extends PDOMCPPSpecialization if (astFt != null) { getLinkage().storeType(record + FUNCTION_TYPE, astFt); } + IFunctionType astDeclaredType = astFunction.getDeclaredType(); + if (astDeclaredType != null) { + getLinkage().storeType(record + DECLARED_TYPE, astDeclaredType); + } ICPPFunction origAstFunc= (ICPPFunction) ((ICPPSpecialization) astFunction).getSpecializedBinding(); ICPPParameter[] origAstParams= origAstFunc.getParameters(); @@ -201,6 +209,19 @@ class PDOMCPPFunctionSpecialization extends PDOMCPPSpecialization } } + @Override + public ICPPFunctionType getDeclaredType() { + if (fDeclaredType == null) { + try { + fDeclaredType = (ICPPFunctionType) getLinkage().loadType(record + DECLARED_TYPE); + } catch (CoreException e) { + CCorePlugin.log(e); + fDeclaredType = new ProblemFunctionType(ISemanticProblem.TYPE_NOT_PERSISTED); + } + } + return fDeclaredType; + } + @Override public ICPPFunctionType getType() { if (fType == null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java index 2f30bed6356..0dbc8d6e935 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java @@ -100,6 +100,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitMethod; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType; @@ -291,6 +292,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { class ConfigureFunction implements Runnable { private final PDOMCPPFunction fFunction; private final ICPPFunctionType fOriginalFunctionType; + private final ICPPFunctionType fDeclaredType; private final ICPPParameter[] fOriginalParameters; private final IType[] fOriginalExceptionSpec; private final ICPPExecution fFunctionBody; @@ -299,6 +301,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { throws DOMException { fFunction = function; fOriginalFunctionType= original.getType(); + fDeclaredType = original.getDeclaredType(); fOriginalParameters= original.getParameters(); fOriginalExceptionSpec= function.extractExceptionSpec(original); fFunctionBody = CPPFunction.getFunctionBodyExecution(original, point); @@ -307,8 +310,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { @Override public void run() { - fFunction.initData(fOriginalFunctionType, fOriginalParameters, fOriginalExceptionSpec, - fFunctionBody); + fFunction.initData(fOriginalFunctionType, fDeclaredType, fOriginalParameters, + fOriginalExceptionSpec, fFunctionBody); } } @@ -399,6 +402,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { private final IPDOMCPPTemplateParameter[] fTemplateParameters; private final ICPPTemplateParameter[] fOriginalTemplateParameters; private final ICPPFunctionType fOriginalFunctionType; + private final ICPPFunctionType fDeclaredType; private final ICPPParameter[] fOriginalParameters; private final IType[] fOriginalExceptionSpec; private final ICPPExecution fFunctionBody; @@ -409,6 +413,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { fTemplateParameters= template.getTemplateParameters(); fOriginalTemplateParameters= original.getTemplateParameters(); fOriginalFunctionType= original.getType(); + fDeclaredType = original.getDeclaredType(); fOriginalParameters= original.getParameters(); fOriginalExceptionSpec= template.extractExceptionSpec(original); fFunctionBody = CPPFunction.getFunctionBodyExecution(original, point); @@ -422,8 +427,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { if (tp != null) tp.configure(fOriginalTemplateParameters[i]); } - fTemplate.initData(fOriginalFunctionType, fOriginalParameters, fOriginalExceptionSpec, - fFunctionBody); + fTemplate.initData(fOriginalFunctionType, fDeclaredType, fOriginalParameters, + fOriginalExceptionSpec, fFunctionBody); } } @@ -1542,6 +1547,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { return TypeOfUnknownMember.unmarshal(getPDOM(), firstBytes, buffer); case ITypeMarshalBuffer.INITIALIZER_LIST_TYPE: return InitializerListType.unmarshal(firstBytes, buffer); + case ITypeMarshalBuffer.PLACEHOLDER_TYPE: + return CPPPlaceholderType.unmarshal(firstBytes, buffer); // Don't handle DEFERRED_FUNCTION, because it's never a type. }