1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-09 17:25:38 +02:00

Bug 408470 - Add partial support for C++14 return type deduction

Out-of-line definitions where the definition is in a different file
than the declaration are not supported yet.

Change-Id: I3631bdb3e08abe2aab266065c7858c66170fb570
This commit is contained in:
Nathan Ridge 2017-02-26 17:52:44 -05:00
parent fb847a82ce
commit 619da2a170
35 changed files with 1019 additions and 151 deletions

View file

@ -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;

View file

@ -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 <typename T> constexpr int foo();
// template <> constexpr int foo<int>() { return 42; };
// template <> constexpr int foo<int&>() { return 43; };
//
// template <typename T>
// constexpr int bar(T arg) {
// // Bind a TypeOfDependentExpression to an 'auto'.
// auto local = *&arg;
//
// // Leak the deduced type via the return value.
// return foo<decltype(local)>();
// }
//
// // 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);
}
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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_);
}
}

View file

@ -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 <typename T>
// 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 <typename T> auto f(T t) { return t; }
// template <typename T> 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 <typename T>
// 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_);
}
}

View file

@ -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 {
{

View file

@ -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);

View file

@ -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.

View file

@ -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
*/

View file

@ -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;
}
}

View file

@ -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

View file

@ -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);

View file

@ -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());

View file

@ -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() {

View file

@ -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;

View file

@ -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]);
}
}

View file

@ -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;

View file

@ -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;
}

View file

@ -52,6 +52,11 @@ public class CPPImplicitFunction extends CPPFunction {
public ICPPFunctionType getType() {
return functionType;
}
@Override
public ICPPFunctionType getDeclaredType() {
return functionType;
}
@Override
public String getName() {

View file

@ -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);
}
}

View file

@ -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,

View file

@ -47,6 +47,11 @@ class AutoTypeResolver implements ICPPFunctionTemplate {
return TEMPLATE_PARAMETERS;
}
@Override
public ICPPFunctionType getDeclaredType() {
return functionType;
}
@Override
public ICPPFunctionType getType() {
return functionType;

View file

@ -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;
}

View file

@ -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);

View file

@ -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<IASTDeclSpecifier> 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);

View file

@ -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.

View file

@ -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;
}

View file

@ -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() {

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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) {

View file

@ -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.
}