1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-21 21:52:10 +02:00

Add basic support for c++17 deduction guides

This commit is contained in:
Igor V. Kovalenko 2023-03-27 22:49:10 +03:00 committed by Jonah Graham
parent aafb1d951a
commit f17675be16
25 changed files with 1017 additions and 59 deletions

View file

@ -57,6 +57,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
@ -544,7 +545,10 @@ public class CModelBuilder2 implements IContributedModelBuilder {
return createTypeDef(parent, declSpecifier, declarator);
}
IASTDeclarator typeRelevant = ASTQueries.findTypeRelevantDeclarator(declarator);
if (typeRelevant instanceof IASTFunctionDeclarator) {
if (typeRelevant instanceof ICPPASTDeductionGuide) {
// TODO [cmodel] deduction guide
return null;
} else if (typeRelevant instanceof IASTFunctionDeclarator) {
return createFunctionDeclaration(parent, declSpecifier, (IASTFunctionDeclarator) typeRelevant, isTemplate);
}
return createVariable(parent, declSpecifier, declarator, isTemplate);

View file

@ -118,6 +118,7 @@ public interface IScope {
private boolean fPrefixLookup;
private boolean fIgnorePointOfDeclaration;
private boolean fArgumentDependent;
private boolean fDeductionGuidesOnly = false;
public ScopeLookupData(IASTName name, boolean resolve, boolean prefixLookup) {
if (name == null)
@ -172,6 +173,11 @@ public interface IScope {
fArgumentDependent = argumentDependent;
}
/** @since 8.1 */
public final void setDeductionGuidesOnly(boolean deductionGuidesOnly) {
fDeductionGuidesOnly = deductionGuidesOnly;
}
public final void setLookupKey(char[] key) {
fLookupKey = key;
}
@ -201,6 +207,11 @@ public interface IScope {
return fArgumentDependent;
}
/** @since 8.1 */
public final boolean isDeductionGuidesOnly() {
return fDeductionGuidesOnly;
}
public final IIndexFileSet getIncludedFiles() {
return fTu == null ? IIndexFileSet.EMPTY : fTu.getIndexFileSet();
}

View file

@ -0,0 +1,25 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
/**
* Deduction guide, introduced in C++17.
*
* @since 8.1
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPASTDeductionGuide extends ICPPASTFunctionDeclarator {
}

View file

@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
/**
* Marker for deduction guide synthesized from class constructor
*
* @since 8.1
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPClassConstructorDeductionGuide {
}

View file

@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
/**
* Marker for deduction guide synthesized from class constructor template
*
* @since 8.1
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPClassConstructorTemplateDeductionGuide {
}

View file

@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
/**
* Marker for copy deduction candidate used with Class Template Argument Deduction, introduced in C++17.
*
* @since 8.1
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPCopyDeductionCandidate {
}

View file

@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
/**
* Deduction guide, introduced in C++17.
*
* @since 8.1
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPDeductionGuide extends ICPPBinding {
public static final ICPPDeductionGuide[] EMPTY_BINDING_ARRAY = {};
public ICPPFunction getFunctionBinding();
}

View file

@ -253,6 +253,11 @@ public interface ICPPNodeFactory extends INodeFactory {
public ICPPASTFoldExpression newFoldExpression(int opToken, boolean isComma, IASTExpression lhs,
IASTExpression rhs);
/**
* @since 8.1
*/
public ICPPASTDeductionGuide newDeductionGuide();
public ICPPASTLinkageSpecification newLinkageSpecification(String literal);
@Override

View file

@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
/**
* Marker for user-defined deduction guide for Class Template Argument Deduction, introduced in C++17.
*
* @since 8.1
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPUserDefinedDeductionGuide {
}

View file

@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeductionGuide;
/**
* Implementation for deduction guide.
*/
public class CPPASTDeductionGuide extends CPPASTFunctionDeclarator implements ICPPASTDeductionGuide {
public CPPASTDeductionGuide() {
}
@Override
public CPPASTDeductionGuide copy() {
return copy(CopyStyle.withoutLocations);
}
@Override
public CPPASTDeductionGuide copy(CopyStyle style) {
CPPASTDeductionGuide copy = new CPPASTDeductionGuide();
return super.copy(copy, style);
}
}

View file

@ -73,13 +73,17 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS
@Override
public CPPASTFunctionDeclarator copy(CopyStyle style) {
CPPASTFunctionDeclarator copy = new CPPASTFunctionDeclarator();
copy.varArgs = varArgs;
copy.pureVirtual = pureVirtual;
copy.isVolatile = isVolatile;
copy.isConst = isConst;
copy.isMutable = isMutable;
copy.refQualifier = refQualifier;
copy.isConstexpr = isConstexpr;
return copy(copy, style);
}
protected <T extends CPPASTFunctionDeclarator> T copy(T copy, CopyStyle style) {
copy.setVarArgs(varArgs);
copy.setPureVirtual(pureVirtual);
copy.setVolatile(isVolatile);
copy.setConst(isConst);
copy.setMutable(isMutable);
copy.setRefQualifier(refQualifier);
copy.setConstexpr(isConstexpr);
for (IASTParameterDeclaration param : getParameters()) {
copy.addParameterDeclaration(param == null ? null : param.copy(style));
@ -97,7 +101,7 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS
for (ICPPASTVirtSpecifier virtSpecifier : getVirtSpecifiers()) {
copy.addVirtSpecifier(virtSpecifier.copy(style));
}
return copy(copy, style);
return super.copy(copy, style);
}
@Override

View file

@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.core.runtime.PlatformObject;
/**
* Represents c++17 deduction guide.
*/
public class CPPDeductionGuide extends PlatformObject implements ICPPDeductionGuide {
protected IASTDeclarator definition;
protected ICPPFunction functionBinding;
public CPPDeductionGuide(IASTDeclarator fnDecl, ICPPFunction functionBinding) {
this.definition = fnDecl;
this.functionBinding = functionBinding;
}
@Override
public ICPPFunction getFunctionBinding() {
return functionBinding;
}
@Override
public String[] getQualifiedName() throws DOMException {
return functionBinding.getQualifiedName();
}
@Override
public char[][] getQualifiedNameCharArray() throws DOMException {
return functionBinding.getQualifiedNameCharArray();
}
@Override
public boolean isGloballyQualified() throws DOMException {
return functionBinding.isGloballyQualified();
}
@Override
public String getName() {
return functionBinding.getName();
}
@Override
public char[] getNameCharArray() {
return functionBinding.getNameCharArray();
}
@Override
public ILinkage getLinkage() {
return functionBinding.getLinkage();
}
@Override
public IBinding getOwner() {
return functionBinding.getOwner();
}
protected IASTName getASTName() {
return definition.getName().getLastName();
}
@Override
public IScope getScope() throws DOMException {
return CPPVisitor.getContainingScope(getASTName());
}
}

View file

@ -77,6 +77,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignatedInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
@ -577,6 +578,11 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory {
return new CPPASTFoldExpression(operator, fIsComma, lhs, rhs);
}
@Override
public ICPPASTDeductionGuide newDeductionGuide() {
return new CPPASTDeductionGuide();
}
@Override
public ICPPASTLinkageSpecification newLinkageSpecification(String literal) {
return new CPPASTLinkageSpecification(literal);

View file

@ -31,6 +31,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
@ -226,6 +227,12 @@ abstract public class CPPScope implements ICPPASTInternalScope {
CCorePlugin.log(e);
}
}
// Deduction guides are not visible to ordinary name lookup
if (result.length > 0) {
result = ArrayUtil.filter(result, lookup.isDeductionGuidesOnly() ? CPPSemantics.opIsDeductionGuide
: CPPSemantics.opIsNotDeductionGuide);
}
}
}
@ -313,6 +320,11 @@ abstract public class CPPScope implements ICPPASTInternalScope {
binding = (IBinding) candidate;
}
// Deduction guides are not visible to ordinary name lookup
if (lookup.isDeductionGuidesOnly() ^ binding instanceof ICPPDeductionGuide) {
return result;
}
if (binding != null)
result = ArrayUtil.append(result, binding);
return result;

View file

@ -94,6 +94,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignatedInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignator;
@ -2443,7 +2444,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
}
if (LT(1) == IToken.tLPAREN) {
ICPPASTFunctionDeclarator dtor = functionDeclarator(true);
ICPPASTFunctionDeclarator dtor = functionDeclarator((IASTName) null, (IASTDeclSpecifier) null, true);
lambdaExpr.setDeclarator(dtor);
if (LT(1) == IToken.tEOC)
return setRange(lambdaExpr, offset, calculateEndOffset(dtor));
@ -4292,7 +4293,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
private void verifyDtor(IASTDeclSpecifier declspec, IASTDeclarator dtor, DeclarationOptions opt)
throws BacktrackException {
if (CPPVisitor.doesNotSpecifyType(declspec)) {
if (ASTQueries.findTypeRelevantDeclarator(dtor) instanceof IASTFunctionDeclarator) {
if (ASTQueries.findTypeRelevantDeclarator(dtor) instanceof IASTFunctionDeclarator typeRelevantDtor) {
if (typeRelevantDtor instanceof ICPPASTDeductionGuide) {
return;
}
boolean isQualified = false;
IASTName name = ASTQueries.findInnermostDeclarator(dtor).getName();
if (name instanceof ICPPASTQualifiedName) {
@ -4373,7 +4377,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
*/
private IASTDeclarator initDeclarator(DtorStrategy strategy, IASTDeclSpecifier declspec, DeclarationOptions option)
throws EndOfFileException, BacktrackException, FoundAggregateInitializer {
final IASTDeclarator dtor = declarator(strategy, option);
final IASTDeclarator dtor = declarator(strategy, declspec, option);
if (option.fAllowInitializer) {
final IASTDeclarator typeRelevantDtor = ASTQueries.findTypeRelevantDeclarator(dtor);
if (option != DeclarationOptions.PARAMETER && typeRelevantDtor instanceof IASTFunctionDeclarator) {
@ -4767,7 +4771,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
* @throws BacktrackException
* request a backtrack
*/
protected IASTDeclarator declarator(DtorStrategy strategy, DeclarationOptions option)
protected IASTDeclarator declarator(DtorStrategy strategy, IASTDeclSpecifier declspec, DeclarationOptions option)
throws EndOfFileException, BacktrackException {
final int startingOffset = LA(1).getOffset();
int endOffset = startingOffset;
@ -4810,7 +4814,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
final IASTName declaratorName = !option.fRequireSimpleName ? qualifiedName() : identifier();
endOffset = calculateEndOffset(declaratorName);
return declarator(pointerOps, hasEllipsis, declaratorName, null, startingOffset, endOffset, strategy,
option, attributes);
declspec, option, attributes);
}
if (lt1 == IToken.tLPAREN) {
@ -4821,7 +4825,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
final IToken mark = mark();
try {
cand1 = declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), null, startingOffset,
endOffset, strategy, option, attributes);
endOffset, strategy, declspec, option, attributes);
if (option.fRequireAbstract || !option.fAllowNested || hasEllipsis)
return cand1;
@ -4835,7 +4839,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (!option.fAllowNested || hasEllipsis) {
if (option.fAllowAbstract) {
return declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), null, startingOffset,
endOffset, strategy, option, attributes);
endOffset, strategy, declspec, option, attributes);
}
throwBacktrack(LA(1));
}
@ -4846,10 +4850,10 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
if (LT(1) == IToken.tRPAREN)
throwBacktrack(LA(1));
final IASTDeclarator nested = declarator(DtorStrategy.PREFER_FUNCTION, option);
final IASTDeclarator nested = declarator(DtorStrategy.PREFER_FUNCTION, declspec, option);
endOffset = consume(IToken.tRPAREN).getEndOffset();
final IASTDeclarator cand2 = declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), nested,
startingOffset, endOffset, strategy, option, attributes);
startingOffset, endOffset, strategy, declspec, option, attributes);
if (cand1 == null || cand1End == null)
return cand2;
final IToken cand2End = LA(1);
@ -4877,7 +4881,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
throwBacktrack(LA(1));
}
return declarator(pointerOps, hasEllipsis, getNodeFactory().newName(), null, startingOffset, endOffset,
strategy, option, attributes);
strategy, declspec, option, attributes);
}
/**
@ -5000,15 +5004,15 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
private IASTDeclarator declarator(List<? extends IASTPointerOperator> pointerOps, boolean hasEllipsis,
IASTName declaratorName, IASTDeclarator nestedDeclarator, int startingOffset, int endOffset,
DtorStrategy strategy, DeclarationOptions option, List<IASTAttributeSpecifier> attributes)
throws EndOfFileException, BacktrackException {
DtorStrategy strategy, IASTDeclSpecifier declspec, DeclarationOptions option,
List<IASTAttributeSpecifier> attributes) throws EndOfFileException, BacktrackException {
ICPPASTDeclarator result = null;
loop: while (true) {
final int lt1 = LTcatchEOF(1);
switch (lt1) {
case IToken.tLPAREN:
if (option.fAllowFunctions && strategy == DtorStrategy.PREFER_FUNCTION) {
result = functionDeclarator(false);
result = functionDeclarator(declaratorName, declspec, false);
setDeclaratorID(result, hasEllipsis, declaratorName, nestedDeclarator);
}
break loop;
@ -5086,16 +5090,47 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
declarator.setDeclaresParameterPack(hasEllipsis);
}
/**
* Parse a function declarator or a deduction guide, starting with the left parenthesis.
*/
private ICPPASTFunctionDeclarator functionDeclarator(IASTName declaratorName, IASTDeclSpecifier declspec,
boolean isLambdaDeclarator) throws EndOfFileException, BacktrackException {
final IToken mark = mark();
ICPPASTFunctionDeclarator fc = getNodeFactory().newFunctionDeclarator(null);
functionDeclarator(fc, isLambdaDeclarator);
// Test if this is a deduction guide and retry with correct object type
final IASTTypeId typeId = fc.getTrailingReturnType();
if (!isLambdaDeclarator && typeId != null && CPPVisitor.doesNotSpecifyType(declspec) && declaratorName != null
&& typeId.getDeclSpecifier() instanceof IASTNamedTypeSpecifier namedTypeSpec
&& namedTypeSpec.getName() instanceof ICPPASTTemplateId templateId) {
if (CharArrayUtils.equals(templateId.getTemplateName().getLookupKey(), declaratorName.getLookupKey())) {
if (declspec instanceof ICPPASTSimpleDeclSpecifier simpleDeclSpecifier) {
// TODO: This enables auto type resolution from return type, validate implementation in CreateType()
simpleDeclSpecifier.setType(IASTSimpleDeclSpecifier.t_auto);
}
backup(mark);
fc = getNodeFactory().newDeductionGuide();
functionDeclarator(fc, isLambdaDeclarator);
}
}
return fc;
}
/**
* Parse a function declarator starting with the left parenthesis.
*/
private ICPPASTFunctionDeclarator functionDeclarator(boolean isLambdaDeclarator)
private void functionDeclarator(final ICPPASTFunctionDeclarator fc, boolean isLambdaDeclarator)
throws EndOfFileException, BacktrackException {
IToken last = consume(IToken.tLPAREN);
final int startOffset = last.getOffset();
int endOffset = last.getEndOffset();
final ICPPASTFunctionDeclarator fc = getNodeFactory().newFunctionDeclarator(null);
ICPPASTParameterDeclaration pd = null;
paramLoop: while (true) {
switch (LT(1)) {
@ -5245,7 +5280,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
endOffset = calculateEndOffset(typeId);
}
return setRange(fc, startOffset, endOffset);
setRange(fc, startOffset, endOffset);
}
/**

View file

@ -157,12 +157,16 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassConstructorDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassConstructorTemplateDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPCopyDeductionCandidate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeferredFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
@ -188,6 +192,7 @@ 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.ICPPTemplateTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUserDefinedDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
@ -224,10 +229,14 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPCompositeBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredConstructor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplate;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitConstructor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScope;
@ -274,6 +283,13 @@ public class CPPSemantics {
private static final char[] CALL_FUNCTION = "call-function".toCharArray(); //$NON-NLS-1$
private static final ICPPEvaluation[] NO_INITCLAUSE_EVALUATION = {};
public static final IUnaryPredicate<IBinding> opIsDeductionGuide = (argument) -> {
return argument instanceof ICPPDeductionGuide;
};
public static final IUnaryPredicate<IBinding> opIsNotDeductionGuide = (argument) -> {
return !(argument instanceof ICPPDeductionGuide);
};
// Set to true for debugging.
public static boolean traceBindingResolution = false;
public static int traceIndent = 0;
@ -399,6 +415,289 @@ public class CPPSemantics {
return postResolution(binding, data);
}
private static IBinding doClassTemplateArgumentDeduction(ICPPClassTemplate classTemplate, LookupData data) {
// Implementation common to all candidate function non-templates
class CTADDeductionCandidateProbeFunction extends CPPFunction {
ICPPFunction method;
ICPPFunctionType functionType;
public CTADDeductionCandidateProbeFunction(ICPPFunction method) {
super(null);
this.method = method;
}
@Override
public char[] getNameCharArray() {
return method.getNameCharArray();
}
@Override
public ICPPFunctionType getType() {
if (functionType == null) {
ICPPFunctionType ft = method.getType();
functionType = new CPPFunctionType(ft.getReturnType(), ft.getParameterTypes(),
ft.getNoexceptSpecifier(), ft.isConst(), ft.isVolatile(), ft.hasRefQualifier(),
ft.isRValueReference(), ft.takesVarArgs());
}
return functionType;
}
@Override
public IType[] getExceptionSpecification() {
return method.getExceptionSpecification();
}
@Override
public ICPPParameter[] getParameters() {
return method.getParameters();
}
@Override
public boolean takesVarArgs() {
return method.takesVarArgs();
}
@Override
public boolean hasParameterPack() {
return method.hasParameterPack();
}
}
// Implementation common to all candidate function templates
class CTADDeductionCandidateProbeFunctionTemplate extends CPPFunctionTemplate {
ICPPClassTemplate classTemplate;
ICPPFunction method;
boolean isClassConstructor;
private ICPPTemplateParameter[] deductionTemplateParameters;
ICPPFunctionType functionType;
private final void resetCachedValues() {
deductionTemplateParameters = null;
functionType = null;
}
public CTADDeductionCandidateProbeFunctionTemplate(ICPPClassTemplate classTemplate) {
super(null);
this.classTemplate = classTemplate;
}
public CTADDeductionCandidateProbeFunctionTemplate(ICPPClassTemplate classTemplate, ICPPFunction method,
boolean isClassConstructor) {
this(classTemplate);
setMethod(method);
setIsClassConstructor(isClassConstructor);
}
protected void setMethod(ICPPFunction method) {
this.method = method;
resetCachedValues(); // Force recalculation of type and template args
}
protected void setIsClassConstructor(boolean isClassConstructor) {
this.isClassConstructor = isClassConstructor;
resetCachedValues(); // Force recalculation of type and template args
}
@Override
public char[] getNameCharArray() {
return method.getNameCharArray();
}
@Override
public ICPPFunctionType getType() {
if (functionType == null) {
ICPPFunctionType ft = method.getType();
IType returnType;
if (isClassConstructor) {
returnType = (ICPPClassType) classTemplate.asDeferredInstance();
} else {
returnType = ft.getReturnType();
}
functionType = new CPPFunctionType(returnType, ft.getParameterTypes(), ft.getNoexceptSpecifier(),
ft.isConst(), ft.isVolatile(), ft.hasRefQualifier(), ft.isRValueReference(),
ft.takesVarArgs());
}
return functionType;
}
@Override
public IType[] getExceptionSpecification() {
//return method.getExceptionSpecification();
// TODO: this requires class owner; see if exception specification is required to implement CTAD
return IType.EMPTY_TYPE_ARRAY;
}
@Override
public ICPPParameter[] getParameters() {
return method.getParameters();
}
@Override
public boolean takesVarArgs() {
return method.takesVarArgs();
}
@Override
public boolean hasParameterPack() {
return method.hasParameterPack();
}
@Override
public ICPPTemplateParameter[] getTemplateParameters() {
// TODO: make sure template parameter identifiers are consistent with where parameters are coming from
// Maybe need to re-instantiate all of them?
if (deductionTemplateParameters == null) {
ICPPTemplateParameter[] candParams = ICPPTemplateParameter.EMPTY_TEMPLATE_PARAMETER_ARRAY;
if (isClassConstructor) {
candParams = ArrayUtil.addAll(candParams, classTemplate.getTemplateParameters());
}
if (method instanceof ICPPTemplateDefinition ctorTemplate) {
candParams = ArrayUtil.addAll(candParams, ctorTemplate.getTemplateParameters());
}
deductionTemplateParameters = ArrayUtil.trim(candParams);
}
return deductionTemplateParameters;
}
}
// Implementation for candidate function synthesized from constructor non-template
class CTADGuideFromConstructor extends CTADDeductionCandidateProbeFunctionTemplate
implements ICPPClassConstructorDeductionGuide {
public CTADGuideFromConstructor(ICPPClassTemplate classTemplate, ICPPFunction method) {
super(classTemplate, method, true);
}
}
// Implementation for candidate function synthesized from constructor template
class CTADGuideFromConstructorTemplate extends CTADDeductionCandidateProbeFunctionTemplate
implements ICPPClassConstructorTemplateDeductionGuide {
public CTADGuideFromConstructorTemplate(ICPPClassTemplate classTemplate, ICPPFunction method) {
super(classTemplate, method, true);
}
}
// Implementation for candidate function from user-defined template deduction guide
class CTADUserDefinedGuideTemplate extends CTADDeductionCandidateProbeFunctionTemplate
implements ICPPUserDefinedDeductionGuide {
public CTADUserDefinedGuideTemplate(ICPPClassTemplate classTemplate, ICPPTemplateDefinition method) {
super(classTemplate, (ICPPFunction) method, false);
}
}
// Implementation for candidate function from user-defined non-template deduction guide
class CTADUserDefinedGuide extends CTADDeductionCandidateProbeFunction
implements ICPPUserDefinedDeductionGuide {
public CTADUserDefinedGuide(ICPPFunction method) {
super(method);
}
}
// Implementation for "copy deduction candidate" synthesized from hypothetical constructor C(C)
class CTADCopyDeductionCandidate extends CTADDeductionCandidateProbeFunctionTemplate
implements ICPPCopyDeductionCandidate {
public CTADCopyDeductionCandidate(ICPPClassTemplate classTemplate) {
super(classTemplate);
char[] className = classTemplate.getNameCharArray();
ICPPParameter[] copyDeductionCandidateParams = new ICPPParameter[] {
new CPPParameter((ICPPClassType) classTemplate.asDeferredInstance(), 0) };
ICPPMethod copyDeductionCandidate = new CPPImplicitConstructor(
(ICPPClassScope) classTemplate.getCompositeScope(), className, copyDeductionCandidateParams,
null);
setMethod(copyDeductionCandidate);
setIsClassConstructor(true);
}
}
final IASTName lookupName = data.getLookupName();
if (lookupName == null)
return classTemplate;
char[] className = lookupName.getLookupKey();
ICPPConstructor[] ctors = classTemplate.getConstructors();
ICPPFunction[] deductionGuideCandidateFunctions = new ICPPFunction[ctors.length + 1];
if (ctors.length > 0) {
// Add template probe functions synthesized from class constructors
for (ICPPConstructor ctor : ctors) {
if (ctor instanceof ICPPTemplateDefinition ctorTemplate) {
deductionGuideCandidateFunctions = ArrayUtil.append(deductionGuideCandidateFunctions,
new CTADGuideFromConstructorTemplate(classTemplate, ctor));
} else {
deductionGuideCandidateFunctions = ArrayUtil.append(deductionGuideCandidateFunctions,
new CTADGuideFromConstructor(classTemplate, ctor));
}
}
} else {
// If class is not defined or does not declare any constructors, add hypothetical constructor C()
ICPPMethod defaultConstructor = new CPPImplicitConstructor(
(ICPPClassScope) classTemplate.getCompositeScope(), className,
ICPPParameter.EMPTY_CPPPARAMETER_ARRAY, null);
deductionGuideCandidateFunctions = ArrayUtil.append(deductionGuideCandidateFunctions,
new CTADDeductionCandidateProbeFunctionTemplate(classTemplate, defaultConstructor, true));
}
deductionGuideCandidateFunctions = ArrayUtil.append(deductionGuideCandidateFunctions,
new CTADCopyDeductionCandidate(classTemplate));
// Add user-defined deduction guides
try {
// TODO: add support for lookup in containing class scope of classTemplate
IScope lookupScope = getContainingNamespaceScope(classTemplate, data.getTranslationUnit());
if (lookupScope instanceof ICPPASTInternalScope internalScope) {
LookupData guideLookupData = new LookupData(className, null, lookupName);
guideLookupData.setDeductionGuidesOnly(true);
IBinding[] bindings = getBindingsFromScope(internalScope, guideLookupData);
for (IBinding binding : bindings) {
if (binding instanceof ICPPDeductionGuide guide) {
IBinding guideBinding = guide.getFunctionBinding();
if (guideBinding instanceof ICPPTemplateDefinition guideFunctionTemplate) {
deductionGuideCandidateFunctions = ArrayUtil.append(deductionGuideCandidateFunctions,
new CTADUserDefinedGuideTemplate(classTemplate, guideFunctionTemplate));
} else if (guideBinding instanceof ICPPFunction guideFunction) {
deductionGuideCandidateFunctions = ArrayUtil.append(deductionGuideCandidateFunctions,
new CTADUserDefinedGuide(guideFunction));
}
}
}
}
} catch (DOMException e) {
}
// Perform overload resolution for initializer clause.
// Deduced class type is the return type of the function selected by overload resolution.
try {
IBinding resolved = resolveFunction(data, deductionGuideCandidateFunctions, true, false);
if (resolved instanceof ICPPFunction selected) {
if (selected.getType().getReturnType() instanceof IBinding binding) {
return binding;
}
}
} catch (DOMException e) {
}
// Not deduced
return null;
}
private static IBinding postResolution(IBinding binding, LookupData data) {
final IASTName lookupName = data.getLookupName();
if (lookupName == null)
@ -468,17 +767,61 @@ public class CPPSemantics {
*/
if (binding instanceof ICPPClassTemplate && !(binding instanceof ICPPClassSpecialization)
&& !(binding instanceof ICPPTemplateParameter) && !(lookupName instanceof ICPPASTTemplateId)) {
ASTNodeProperty prop = lookupName.getPropertyInParent();
if (prop != ICPPASTTemplateId.TEMPLATE_NAME && !lookupName.isQualified()) {
if (prop != ICPPASTTemplateId.TEMPLATE_NAME) {
if (!lookupName.isQualified()) {
// You cannot use a class template name outside of the class template scope,
// mark it as a problem.
// mark it as a problem - unless Class Template Argument Deduction needs to be done
IBinding user = CPPTemplates.isUsedInClassTemplateScope((ICPPClassTemplate) binding, lookupName);
if (user instanceof ICPPClassTemplate) {
binding = ((ICPPClassTemplate) user).asDeferredInstance();
} else if (user != null) {
binding = user;
} else {
// Attempt class template argument deduction if appropriate
if (data.getTranslationUnit().getEnableClassTemplateArgumentDeduction()) {
if (lookupName.getParent() instanceof IASTIdExpression idExpression
&& idExpression.getPropertyInParent() == IASTFunctionCallExpression.FUNCTION_NAME) {
// Class name for class type argument deduction is a type
return doClassTemplateArgumentDeduction((ICPPClassTemplate) binding, data);
}
}
boolean ok = false;
// Attempt class template argument deduction if appropriate
if (data.getTranslationUnit().getEnableClassTemplateArgumentDeduction()
&& lookupName.getParent() instanceof IASTNamedTypeSpecifier namedTypeSpecifier
&& namedTypeSpecifier.getPropertyInParent() == IASTSimpleDeclaration.DECL_SPECIFIER
&& namedTypeSpecifier.getParent() instanceof IASTSimpleDeclaration declaration) {
IASTDeclarator[] declarators = declaration.getDeclarators();
if (declarators != null && declarators.length > 0) {
IASTDeclarator declarator = declarators[0];
// Cannot deduce pointer or reference class template argument
if (declarator.getPointerOperators().length == 0) {
// Class name for class type argument deduction is a type
ICPPASTInitializerClause initializerClause = CPPVisitor
.getAutoInitClauseForDeclarator(declarator);
if (initializerClause != null) {
data.setFunctionArguments(false,
new ICPPASTInitializerClause[] { initializerClause });
} else {
data.setFunctionArguments(false, NO_INITCLAUSE_EVALUATION);
}
IBinding b = doClassTemplateArgumentDeduction((ICPPClassTemplate) binding, data);
if (b != null) {
// Deduced class template arguments
binding = b;
// No need to check other cases
ok = true;
}
}
}
}
IASTNode node = lookupName.getParent();
while (node != null && !ok) {
if (node instanceof ICPPASTTemplateId
@ -504,6 +847,41 @@ public class CPPSemantics {
data.getFoundBindings());
}
}
} else {
// Name is qualified-name
// Attempt class template argument deduction if appropriate
if (data.getTranslationUnit().getEnableClassTemplateArgumentDeduction()
&& lookupName.getParent() instanceof ICPPASTQualifiedName qualifiedName
&& qualifiedName.getParent() instanceof IASTNamedTypeSpecifier namedTypeSpecifier
&& namedTypeSpecifier.getPropertyInParent() == IASTSimpleDeclaration.DECL_SPECIFIER
&& namedTypeSpecifier.getParent() instanceof IASTSimpleDeclaration declaration) {
IASTDeclarator[] declarators = declaration.getDeclarators();
if (declarators != null && declarators.length > 0) {
IASTDeclarator declarator = declarators[0];
// Cannot deduce pointer or reference class template argument
if (declarator.getPointerOperators().length == 0) {
// Class name for class type argument deduction is a type
ICPPASTInitializerClause initializerClause = CPPVisitor
.getAutoInitClauseForDeclarator(declarator);
if (initializerClause != null) {
data.setFunctionArguments(false,
new ICPPASTInitializerClause[] { initializerClause });
} else {
data.setFunctionArguments(false, NO_INITCLAUSE_EVALUATION);
}
IBinding b = doClassTemplateArgumentDeduction((ICPPClassTemplate) binding, data);
if (b != null) {
// Deduced class template arguments
binding = b;
}
}
}
}
}
}
} else if (binding instanceof ICPPDeferredClassInstance) {
// Try to replace binding by the one pointing to the enclosing template declaration.
@ -1442,6 +1820,12 @@ public class CPPSemantics {
});
}
// Deduction guides are not visible to ordinary name lookup
if (bindings.length > 0) {
bindings = ArrayUtil.filter(bindings,
data.isDeductionGuidesOnly() ? opIsDeductionGuide : opIsNotDeductionGuide);
}
return expandUsingDeclarationsAndRemoveObjects(bindings, data);
}
@ -1863,8 +2247,9 @@ public class CPPSemantics {
declarator = declarator.getNestedDeclarator();
}
if (innermost != null) {
IASTName declaratorName = innermost.getName();
ASTInternal.addName(scope, declaratorName);
// NOTE This now may include deduction guides which are filtered later during lookup
IASTName declaratorOrDeductionGuideName = innermost.getName();
ASTInternal.addName(scope, declaratorOrDeductionGuideName);
}
}
}

View file

@ -117,6 +117,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
@ -212,6 +213,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConstructorTemplate;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeductionGuide;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumeration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPEnumerator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPField;
@ -883,6 +885,7 @@ public class CPPVisitor extends ASTQueries {
binding = scope.getBinding(name, forceResolve);
}
boolean isDeductionGuide = false;
boolean isFunction = false;
if (parent instanceof ICPPASTFunctionDefinition) {
isFunction = true;
@ -908,6 +911,9 @@ public class CPPVisitor extends ASTQueries {
binding = td;
} else if (typeRelevantDtor instanceof IASTFunctionDeclarator) {
// Function declaration via function declarator.
if (typeRelevantDtor instanceof ICPPASTDeductionGuide) {
isDeductionGuide = true;
}
isFunction = true;
} else {
// Looks like a variable declaration.
@ -991,11 +997,17 @@ public class CPPVisitor extends ASTQueries {
} else {
binding = template ? (ICPPFunction) new CPPFunctionTemplate(name) : new CPPFunction(typeRelevantDtor);
}
if (isDeductionGuide) {
binding = new CPPDeductionGuide(typeRelevantDtor, (ICPPFunction) binding);
} else {
binding = CPPSemantics.checkDeclSpecifier(binding, name, parent);
if (isFriendDecl && scope instanceof IASTInternalScope) {
((IASTInternalScope) scope).addBinding(binding);
}
}
}
return binding;
}
@ -2473,7 +2485,7 @@ public class CPPVisitor extends ASTQueries {
return autoInitClause;
}
private static ICPPASTInitializerClause getAutoInitClauseForDeclarator(IASTDeclarator declarator) {
protected static ICPPASTInitializerClause getAutoInitClauseForDeclarator(IASTDeclarator declarator) {
IASTInitializer initClause = declarator.getInitializer();
return getInitClauseForInitializer(initClause);
}

View file

@ -28,12 +28,16 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassConstructorDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassConstructorTemplateDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPCopyDeductionCandidate;
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.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUserDefinedDeductionGuide;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates.TypeSelection;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.DeferredUDC;
@ -195,6 +199,10 @@ class FunctionCost {
if (cmp != 0)
return cmp;
cmp = compareAsDeductionGuides(f1, f2);
if (cmp != 0)
return cmp;
// At this point prefer non-index bindings
return -CPPSemantics.compareByRelevance(tu, f1, f2);
}
@ -205,6 +213,43 @@ class FunctionCost {
return 1;
}
private int compareAsDeductionGuides(ICPPFunction f1, ICPPFunction f2) {
ICPPFunction deductionCandidate = asTemplate(f1);
if (deductionCandidate == null) {
deductionCandidate = f1;
}
ICPPFunction otherDeductionCandidate = asTemplate(f2);
if (otherDeductionCandidate == null) {
otherDeductionCandidate = f2;
}
// 16.3.3-1.12 F1 is generated from a deduction-guide and F2 is not
final boolean isUserDefinedDeductionGuide = deductionCandidate instanceof ICPPUserDefinedDeductionGuide;
final boolean otherUserDefinedDeductionGuide = otherDeductionCandidate instanceof ICPPUserDefinedDeductionGuide;
if (isUserDefinedDeductionGuide != otherUserDefinedDeductionGuide) {
return isUserDefinedDeductionGuide ? -1 : 1;
}
// 16.3.3-1.13 F1 is the copy deduction candidate and F2 is not
final boolean isCopyDeductionCandidate = deductionCandidate instanceof ICPPCopyDeductionCandidate;
final boolean otherCopyDeductionCandidate = otherDeductionCandidate instanceof ICPPCopyDeductionCandidate;
if (isCopyDeductionCandidate != otherCopyDeductionCandidate) {
return isCopyDeductionCandidate ? -1 : 1;
}
// 16.3.3-1.14 F1 is generated from a non-template constructor and F2 is generated from a constructor template
final boolean isFromNonTemplateConstructor = deductionCandidate instanceof ICPPClassConstructorDeductionGuide;
final boolean otherFromTemplateConstructor = otherDeductionCandidate instanceof ICPPClassConstructorTemplateDeductionGuide;
if (isFromNonTemplateConstructor && otherFromTemplateConstructor) {
return -1;
}
return 0;
}
private int overridesUsingDeclaration(ICPPFunction f1, ICPPFunction f2) {
if (f1.takesVarArgs() != f2.takesVarArgs())
return 0;

View file

@ -77,4 +77,6 @@ public interface IIndexCPPBindingConstants {
int CPP_FIELD_TEMPLATE_PARTIAL_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 60;
int CPP_DEFERRED_VARIABLE_INSTANCE = IIndexBindingConstants.LAST_CONSTANT + 61;
int CPP_ALIAS_TEMPLATE_SPECIALIZATION = IIndexBindingConstants.LAST_CONSTANT + 62;
int CPP_DEDUCTION_GUIDE = IIndexBindingConstants.LAST_CONSTANT + 63;
int CPP_DEDUCTION_GUIDE_TEMPLATE = IIndexBindingConstants.LAST_CONSTANT + 64;
}

View file

@ -36,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecializationSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
@ -753,6 +754,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory {
return new CompositeCPPConstructorTemplate(this, (ICPPConstructor) binding);
} else if (binding instanceof ICPPMethod) {
return new CompositeCPPMethodTemplate(this, (ICPPMethod) binding);
} else if (binding instanceof ICPPDeductionGuide guide) {
return new CompositeCPPDeductionGuideTemplate(this, guide);
} else if (binding instanceof ICPPFunctionTemplate) {
return new CompositeCPPFunctionTemplate(this, (ICPPFunction) binding);
} else if (binding instanceof ICPPAliasTemplate) {
@ -810,6 +813,8 @@ public class CPPCompositesFactory extends AbstractCompositeFactory {
} else if (binding instanceof ICPPEnumeration) {
ICPPEnumeration def = (ICPPEnumeration) findOneBinding(binding);
result = def == null ? null : new CompositeCPPEnumeration(this, def);
} else if (binding instanceof ICPPDeductionGuide guide) {
result = new CompositeCPPDeductionGuide(this, guide);
} else if (binding instanceof ICPPFunction) {
result = new CompositeCPPFunction(this, (ICPPFunction) binding);
} else if (binding instanceof ICPPInternalEnumerator) {

View file

@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.index.composite.cpp;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory;
public class CompositeCPPDeductionGuide extends CompositeCPPFunction implements ICPPDeductionGuide {
public CompositeCPPDeductionGuide(ICompositesFactory cf, ICPPDeductionGuide rbinding) {
super(cf, rbinding.getFunctionBinding());
}
@Override
public ICPPFunction getFunctionBinding() {
return this;
}
}

View file

@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.index.composite.cpp;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory;
public class CompositeCPPDeductionGuideTemplate extends CompositeCPPFunctionTemplate implements ICPPDeductionGuide {
public CompositeCPPDeductionGuideTemplate(ICompositesFactory cf, ICPPDeductionGuide rbinding) {
super(cf, rbinding.getFunctionBinding());
}
@Override
public ICPPFunction getFunctionBinding() {
return this;
}
}

View file

@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
import org.eclipse.core.runtime.CoreException;
public class PDOMCPPDeductionGuide extends PDOMCPPFunction implements ICPPDeductionGuide {
public PDOMCPPDeductionGuide(PDOMLinkage linkage, long bindingRecord) {
super(linkage, bindingRecord);
}
public PDOMCPPDeductionGuide(PDOMCPPLinkage linkage, PDOMNode parent, ICPPDeductionGuide guide)
throws CoreException, DOMException {
super(linkage, parent, guide.getFunctionBinding(), true);
}
@Override
public int getNodeType() {
return IIndexCPPBindingConstants.CPP_DEDUCTION_GUIDE;
}
@Override
public ICPPFunction getFunctionBinding() {
return this;
}
}

View file

@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2023 Igor V. Kovalenko.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Igor V. Kovalenko - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode;
import org.eclipse.core.runtime.CoreException;
public class PDOMCPPDeductionGuideTemplate extends PDOMCPPFunctionTemplate implements ICPPDeductionGuide {
public PDOMCPPDeductionGuideTemplate(PDOMLinkage linkage, long bindingRecord) {
super(linkage, bindingRecord);
}
public PDOMCPPDeductionGuideTemplate(PDOMCPPLinkage linkage, PDOMNode parent, ICPPDeductionGuide guide)
throws CoreException, DOMException {
super(linkage, parent, (ICPPFunctionTemplate) guide.getFunctionBinding());
}
@Override
public int getNodeType() {
return IIndexCPPBindingConstants.CPP_DEDUCTION_GUIDE_TEMPLATE;
}
@Override
public ICPPFunction getFunctionBinding() {
return this;
}
}

View file

@ -60,6 +60,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPDeductionGuide;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFieldTemplate;
@ -851,6 +852,12 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
if (parent instanceof PDOMCPPClassType || parent instanceof PDOMCPPClassSpecialization) {
pdomBinding = new PDOMCPPMethod(this, parent, (ICPPMethod) binding);
}
} else if (binding instanceof ICPPDeductionGuide guide) {
if (guide.getFunctionBinding() instanceof ICPPFunctionTemplate) {
pdomBinding = new PDOMCPPDeductionGuideTemplate(this, parent, guide);
} else {
pdomBinding = new PDOMCPPDeductionGuide(this, parent, guide);
}
} else if (binding instanceof ICPPFunction) {
pdomBinding = new PDOMCPPFunction(this, parent, (ICPPFunction) binding, true);
} else if (binding instanceof ICPPNamespaceAlias) {
@ -1137,6 +1144,12 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
} else if (binding instanceof ICPPMethod) {
// this must be before functions
return CPPMETHOD;
} else if (binding instanceof ICPPDeductionGuide guide) {
if (guide.getFunctionBinding() instanceof ICPPFunctionTemplate) {
return CPP_DEDUCTION_GUIDE_TEMPLATE;
} else {
return CPP_DEDUCTION_GUIDE;
}
} else if (binding instanceof ICPPFunction) {
return CPPFUNCTION;
} else if (binding instanceof ICPPUnknownBinding) {
@ -1403,6 +1416,10 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
return new PDOMCPPFieldTemplatePartialSpecialization(this, record);
case CPP_ALIAS_TEMPLATE_SPECIALIZATION:
return new PDOMCPPAliasTemplateSpecialization(this, record);
case CPP_DEDUCTION_GUIDE:
return new PDOMCPPDeductionGuide(this, record);
case CPP_DEDUCTION_GUIDE_TEMPLATE:
return new PDOMCPPDeductionGuideTemplate(this, record);
}
assert false : "nodeid= " + nodeType; //$NON-NLS-1$
return null;