diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java index a891a04463b..84c0a540ac5 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2016 IBM Corporation and others. + * Copyright (c) 2004, 2016, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -158,6 +158,7 @@ private static Map getStdCpp20Map() { Map map = getStdMap(); map.put("__cpp_impl_three_way_comparison", "201907L"); map.put("__cpp_char8_t", "201811L"); + map.put("__cpp_concepts", "201907L"); return map; } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx20/ConceptsTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx20/ConceptsTests.java new file mode 100644 index 00000000000..dd04aad12f9 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx20/ConceptsTests.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2025 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.parser.tests.ast2.cxx20; + +import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase; + +/** + * AST tests for C++20 requires expressions. + */ +public class ConceptsTests extends AST2CPPTestBase { + // template + // concept A = true; + // + // template + // concept B = A; + // + // template + // concept C = requires { + // true; + // }; + public void testConceptDefinitionExpressions() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // void x() requires true; + // + // template + // void y() requires requires () { + // true; + // }; + // + // template + // void z() requires true && false; + public void testFunctionDeclarationTrailingRequiresClauseTrue() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // concept A = false; + // template + // concept B = true; + // template + // concept C = true; + // + // template + // void x() requires true && false {} + // + // template + // void x_c() requires C {} + // + // template + // void x_abc() requires A || B && C {} + public void testFunctionDefinitionTrailingRequiresClause() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // concept A = false; + // template + // concept B = true; + // template + // concept C = true; + // + // template + // requires A || B && C + // void x() {} + public void testTemplateHeadRequiresClause() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // requires requires { true; } + // void x() {} + public void testTemplateHeadAdHocRequiresExpression() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // constexpr bool value = requires () { true; }; + public void testInitializerRequiresExpression() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // constexpr bool x() { + // if constexpr(requires { true; }) { + // return true; + // } else { + // return false; + // } + // } + public void testConstexprIfRequiresExpression() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // concept A = false; + // template + // concept B = true; + // template + // concept C = true; + // + // template + // void f_a(U a_u); + // template + // void f_abc(U1 a_u1, U2 b_u2, U3 c_u3); + public void testTemplateArgumentTypeConstraint() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } + + // template + // concept A = false; + // namespace Outer { + // template + // concept B = true; + // namespace Inner { + // template + // concept C = true; + // } + // } + // + // template + // void f_abc(U1 a_u1, U2 b_u2, U3 c_u3); + public void testTemplateArgumentTypeConstraintFromNamespace() throws Exception { + parseAndCheckBindings(ScannerKind.STDCPP20); + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexConceptTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexConceptTest.java new file mode 100644 index 00000000000..6ec4f10122d --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexConceptTest.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2025 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.index.tests; + +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConceptDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConcept; +import org.eclipse.cdt.core.testplugin.TestScannerProvider; + +import junit.framework.TestSuite; + +/** + * AST tests for C++20 concepts via PDOM. + */ +public abstract class IndexConceptTest extends IndexBindingResolutionTestBase { + public static class SingleProject extends IndexConceptTest { + public SingleProject() { + setStrategy(new SinglePDOMTestStrategy(true /* cpp */)); + } + + public static TestSuite suite() { + return suite(SingleProject.class); + } + } + + public static class SingleProjectReindexed extends IndexConceptTest { + public SingleProjectReindexed() { + setStrategy(new SinglePDOMReindexedTestStrategy(true /* cpp */)); + } + + public static TestSuite suite() { + return suite(SingleProjectReindexed.class); + } + } + + public static class ProjectWithDepProj extends IndexConceptTest { + public ProjectWithDepProj() { + setStrategy(new ReferencedProject(true /* cpp */)); + } + + public static TestSuite suite() { + return suite(ProjectWithDepProj.class); + } + } + + private static void cxx20SetUp() { + TestScannerProvider.sDefinedSymbols.put("__cpp_concepts", "201907L"); + } + + @Override + public void setUp() throws Exception { + cxx20SetUp(); + super.setUp(); + } + + public static void addTests(TestSuite suite) { + suite.addTest(SingleProject.suite()); + suite.addTest(SingleProjectReindexed.suite()); + suite.addTest(ProjectWithDepProj.suite()); + } + + // template + // concept A = true; + + // template + // concept B = A; + public void testConceptDefinitionFromHeader() throws Exception { + checkBindings(); + + ICPPConcept concept = getBindingFromASTName("B = A", 1); + ICPPASTConceptDefinition decl = concept.getConceptDefinition(); + } +} diff --git a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF index 2b120b41cd1..b9f1aed2d43 100644 --- a/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true -Bundle-Version: 9.2.100.qualifier +Bundle-Version: 9.3.0.qualifier Bundle-Activator: org.eclipse.cdt.core.CCorePlugin Bundle-Vendor: %providerName Bundle-Localization: plugin diff --git a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/IndexModelUtil.java b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/IndexModelUtil.java index ab0cd423037..683926edf6d 100644 --- a/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/IndexModelUtil.java +++ b/core/org.eclipse.cdt.core/browser/org/eclipse/cdt/internal/core/browser/IndexModelUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2015 QNX Software Systems and others. + * Copyright (c) 2006, 2015, 2025 QNX Software Systems and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -32,6 +32,7 @@ import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPAliasTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConcept; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias; import org.eclipse.cdt.core.index.IIndexMacroContainer; @@ -91,6 +92,10 @@ public static boolean bindingHasCElementType(IBinding binding, int[] kinds) { if (binding instanceof IEnumerator) return true; break; + case ICElement.C_CONCEPT: + if (binding instanceof ICPPConcept) + return true; + break; } } return false; @@ -152,6 +157,9 @@ public static int getElementType(IBinding binding) { if (binding instanceof IParameter) { elementType = ICElement.C_VARIABLE_LOCAL; } + if (binding instanceof ICPPConcept) { + elementType = ICElement.C_CONCEPT; + } return elementType; } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java index c4e069976ec..83f35f58b5d 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/ICElement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 QNX Software Systems and others. + * Copyright (c) 2000, 2014, 2025 QNX Software Systems and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -249,6 +249,12 @@ public interface ICElement extends IAdaptable { */ static final int C_PRAGMA = 95; + /** + * a C++ concept. + * @since 9.3 + */ + static final int C_CONCEPT = 96; + /** * @deprecated use {@link IMethodDeclaration#isConstructor()} * @noreference This field is not intended to be referenced by clients. diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/IConcept.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/IConcept.java new file mode 100644 index 00000000000..dc7bd22d4dc --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/core/model/IConcept.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2025 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.model; + +/** + * Represents a C++ concept. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * + * @since 9.3 + */ +public interface IConcept extends IDeclaration, ITemplate { + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java index 83db5b73b7e..0ae11989e7c 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CModelBuilder2.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2014 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2014, 2025 Wind River Systems, Inc. and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -56,6 +56,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.ICPPASTConceptDefinition; 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; @@ -450,6 +451,13 @@ private void createTemplateDeclaration(Parent parent, ICPPASTTemplateDeclaration } else if (declaration instanceof ICPPASTTemplateDeclaration) { // strange: template decl inside template decl createTemplateDeclaration(parent, (ICPPASTTemplateDeclaration) declaration); + } else if (declaration instanceof ICPPASTConceptDefinition conceptDefinition) { + Concept concept = createConcept(parent, conceptDefinition); + String[] parameterTypes = ASTStringUtil + .getTemplateParameterArray(templateDeclaration.getTemplateParameters()); + concept.setTemplateParameterTypes(parameterTypes); + // set the body position + setBodyPosition(concept, templateDeclaration); } else if (declaration instanceof IASTProblemDeclaration) { // ignore problem declarations (or create special elements for debugging?) } else { @@ -461,7 +469,7 @@ private void createTemplateDeclaration(Parent parent, ICPPASTTemplateDeclaration * Handle extern "C" and related kinds. * * @param parent - * @param declaration + * @param definition * @throws CModelException * @throws DOMException */ @@ -909,6 +917,31 @@ private VariableDeclaration createVariable(Parent parent, IASTDeclSpecifier spec return element; } + private Concept createConcept(Parent parent, ICPPASTConceptDefinition conceptDefinition) throws CModelException { + final IASTName astName = conceptDefinition.getName(); + if (astName == null) { + return null; + } + final String variableName = ASTStringUtil.getSimpleName(astName); + + final SourceManipulationInfo info; + + Concept element = new Concept(parent, variableName); + setIndex(element); + VariableInfo varInfo = (VariableInfo) getElementInfo(element); + varInfo.setTypeName(Keywords.CONCEPT); + info = varInfo; + + element.setActive(conceptDefinition.isActive()); + // TODO [cmodel] correctly resolve isStatic + // add to parent + parent.addChild(element); + + // set positions + setIdentifierPosition(info, astName); + return element; + } + private FunctionDeclaration createFunctionDefinition(Parent parent, IASTFunctionDefinition functionDeclaration, boolean isTemplate) throws CModelException, DOMException { final IASTFunctionDeclarator declarator = functionDeclaration.getDeclarator(); diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Concept.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Concept.java new file mode 100644 index 00000000000..987a0833a60 --- /dev/null +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/Concept.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2025 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.model; + +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.IConcept; + +public class Concept extends VariableTemplate implements IConcept { + public Concept(ICElement parent, String name) { + super(parent, name, ICElement.C_CONCEPT); + } +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/VariableTemplate.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/VariableTemplate.java index ac4fb2f9758..eea99ff8b39 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/VariableTemplate.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/VariableTemplate.java @@ -23,7 +23,11 @@ public class VariableTemplate extends Variable implements ITemplate { protected String[] templateParameterTypes; public VariableTemplate(ICElement parent, String name) { - super(parent, name, ICElement.C_TEMPLATE_VARIABLE); + this(parent, name, ICElement.C_TEMPLATE_VARIABLE); + } + + public VariableTemplate(ICElement parent, String name, int kind) { + super(parent, name, kind); templateParameterTypes = fgEmptyList; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTConceptDefinition.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTConceptDefinition.java new file mode 100644 index 00000000000..832100c975b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTConceptDefinition.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2025 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; + +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNameOwner; + +/** + * Represents a C++ concept definition. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 9.3 + */ +public interface ICPPASTConceptDefinition extends IASTDeclaration, IASTNameOwner, IASTAttributeOwner { + /** + * CONCEPT_NAME is the name that is brought into the local scope. + */ + public static final ASTNodeProperty CONCEPT_NAME = new ASTNodeProperty( + "ICPPASTConstraintDeclaration.CONCEPT_NAME - Introduced constraint name"); //$NON-NLS-1$ + + /** + * CONSTRAINT_EXPRESSON is constraint expression. + */ + public static final ASTNodeProperty CONSTRAINT_EXPRESSION = new ASTNodeProperty( + "ICPPASTConstraintDeclaration.CONSTRAINT_EXPRESSION - Constraint expression"); //$NON-NLS-1$ + + /** + * Returns the constraint name. + * + * @return IASTName + */ + public IASTName getName(); + + /** + * Sets the constraint name. + * + * @param name IASTName + */ + public void setName(IASTName name); + + /** + * Returns the constraint expression. + * + * @return IASTExpression + */ + public IASTExpression getExpression(); + + /** + * Sets the constraint expression. + * + * @param name IASTExpression + */ + public void setExpression(IASTExpression expr); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTConstraintOwner.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTConstraintOwner.java new file mode 100644 index 00000000000..d77deedb983 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTConstraintOwner.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2025 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; + +import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTNode; + +/** + * An AST node that may have C++ constraints. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 9.3 + */ +public interface ICPPASTConstraintOwner extends IASTNode { + public static final ASTNodeProperty CONSTRAINT_SPECIFIER = new ASTNodeProperty( + "ICPPASTAttributeOwner.CONSTRAINT_SPECIFIER"); //$NON-NLS-1$ + + /** + * Returns an array of all the node's constraint specifiers. + */ + public IASTExpression[] getConstraintExpressions(); + + /** + * Adds a constraint specifier to the node. + */ + public void addConstraintExpression(IASTExpression constraintExpression); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java index ca4304ce84c..499445987c3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionDeclarator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2014 IBM Corporation and others. + * Copyright (c) 2004, 2014, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -29,7 +29,8 @@ * @noimplement This interface is not intended to be implemented by clients. * @noextend This interface is not intended to be extended by clients. */ -public interface ICPPASTFunctionDeclarator extends IASTStandardFunctionDeclarator, ICPPASTDeclarator { +public interface ICPPASTFunctionDeclarator + extends IASTStandardFunctionDeclarator, ICPPASTDeclarator, ICPPASTConstraintOwner { /** * @since 5.9 */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionTryBlockDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionTryBlockDeclarator.java index 5d19877dd9f..2416c1ed020 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionTryBlockDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFunctionTryBlockDeclarator.java @@ -19,6 +19,7 @@ /** * @deprecated Use {@link ICPPASTFunctionWithTryBlock}, instead. * @noreference This interface is not intended to be referenced by clients. + * @noimplement This interface is not intended to be implemented by clients. */ @Deprecated public interface ICPPASTFunctionTryBlockDeclarator extends ICPPASTFunctionDeclarator { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSimpleTypeTemplateParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSimpleTypeTemplateParameter.java index 9d4e0e371a9..41dd8aecc14 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSimpleTypeTemplateParameter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSimpleTypeTemplateParameter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2012 IBM Corporation and others. + * Copyright (c) 2004, 2012, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -25,7 +25,8 @@ * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface ICPPASTSimpleTypeTemplateParameter extends ICPPASTTemplateParameter, IASTNameOwner { +public interface ICPPASTSimpleTypeTemplateParameter + extends ICPPASTTemplateParameter, IASTNameOwner, ICPPASTConstraintOwner { /** * Relation between template parameter and its name. */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPConcept.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPConcept.java new file mode 100644 index 00000000000..d56c3cfcc17 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPConcept.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2025 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; + +/** + * Concept, introduced in C++20. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 9.3 + */ +public interface ICPPConcept extends ICPPTemplateDefinition { + public ICPPASTConceptDefinition getConceptDefinition(); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java index cfa9f63ad5f..0038ed2ee2f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNodeFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2016 IBM Corporation and others. + * Copyright (c) 2006, 2016, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -258,6 +258,11 @@ public ICPPASTFoldExpression newFoldExpression(int opToken, boolean isComma, IAS */ public ICPPASTDeductionGuide newDeductionGuide(); + /** + * @since 9.3 + */ + public ICPPASTConceptDefinition newConcept(IASTName name, IASTExpression expr); + public ICPPASTLinkageSpecification newLinkageSpecification(String literal); @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java index 73bfbd1b022..69d191190a0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IToken.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2015 IBM Corporation and others. + * Copyright (c) 2002, 2015, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -126,6 +126,8 @@ public interface IToken { /** @since 5.2 */ int t_char32_t = 5203; int t_class = 65; + /** @since 9.3 */ + int t_concept = 9001; int t_const = 67; /** @since 5.4 */ @@ -166,6 +168,8 @@ public interface IToken { int t_public = 100; int t_register = 101; int t_reinterpret_cast = 102; + /** @since 9.3 */ + int t_requires = 9002; int t_return = 103; int t_short = 104; int t_sizeof = 105; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java index e9f68b1d806..223cdfede8c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/Keywords.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2015 IBM Corporation and others. + * Copyright (c) 2002, 2015, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -57,6 +57,8 @@ public class Keywords { public static final String CHAR32_T = "char32_t"; public static final String CLASS = "class"; public static final String COMPL = "compl"; + /** @since 9.3 */ + public static final String CONCEPT = "concept"; public static final String CONST = "const"; /** @since 5.4 */ public static final String CONSTEXPR = "constexpr"; @@ -106,6 +108,8 @@ public class Keywords { public static final String REGISTER = "register"; public static final String REINTERPRET_CAST = "reinterpret_cast"; public static final String RESTRICT = "restrict"; + /** @since 9.3 */ + public static final String REQUIRES = "requires"; public static final String RETURN = "return"; public static final String SHORT = "short"; public static final String SIGNED = "signed"; @@ -167,6 +171,8 @@ public class Keywords { public static final char[] cCHAR32_T = CHAR32_T.toCharArray(); public static final char[] cCLASS = "class".toCharArray(); public static final char[] cCOMPL = "compl".toCharArray(); + /** @since 9.3 */ + public static final char[] cCONCEPT = "concept".toCharArray(); public static final char[] cCONST = "const".toCharArray(); /** @since 5.4 */ public static final char[] cCONSTEXPR = "constexpr".toCharArray(); @@ -215,6 +221,8 @@ public class Keywords { public static final char[] cREGISTER = "register".toCharArray(); public static final char[] cREINTERPRET_CAST = "reinterpret_cast".toCharArray(); public static final char[] cRESTRICT = "restrict".toCharArray(); + /** @since 9.3 */ + public static final char[] cREQUIRES = "requires".toCharArray(); public static final char[] cRETURN = "return".toCharArray(); public static final char[] cSHORT = "short".toCharArray(); public static final char[] cSIGNED = "signed".toCharArray(); @@ -399,10 +407,6 @@ private static void addC(CharArrayIntMap ckeywords) { ckeywords.put(Keywords.c_IMAGINARY, IToken.t__Imaginary); } - private static void addCpp20(CharArrayIntMap cppkeywords) { - cppkeywords.put(Keywords.cCHAR8_T, IToken.t_char8_t); - } - private static void addCpp(CharArrayIntMap cppkeywords) { cppkeywords.put(Keywords.cALIGNAS, IToken.t_alignas); cppkeywords.put(Keywords.cALIGNOF, IToken.t_alignof); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index 5d056af9660..436a1a32f08 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2015 IBM Corporation and others. + * Copyright (c) 2005, 2015, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -186,7 +186,7 @@ protected static enum CastExprCtx { } protected static enum ExprKind { - eExpression, eAssignment, eConstant + eExpression, eAssignment, eConstant, eRequiresClauseExpression } protected static final int DEFAULT_DESIGNATOR_LIST_SIZE = 4; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousTypeConstraintVsNonTypeTemplateArgument.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousTypeConstraintVsNonTypeTemplateArgument.java new file mode 100644 index 00000000000..2ad51278fd2 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousTypeConstraintVsNonTypeTemplateArgument.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2025 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 java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; +import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; + +public class CPPASTAmbiguousTypeConstraintVsNonTypeTemplateArgument extends ASTAmbiguousNode + implements ICPPASTTemplateParameter { + private List fNodes = new ArrayList<>(2); + private IScope fScope; + private ICPPASTTemplateParameter fParameter; + + @Override + protected void beforeResolution() { + fScope = CPPVisitor.getContainingScope(this); + if (fScope instanceof ICPPASTInternalScope internalScope) { + internalScope.populateCache(); + } + } + + @Override + protected void beforeAlternative(IASTNode alternative) { + cleanupScope(); + if (alternative instanceof ICPPASTTemplateParameter parameter) { + if (fScope instanceof ICPPASTInternalScope internalScope) { + fParameter = parameter; + CPPSemantics.populateCache(internalScope, fParameter); + } + } + } + + private void cleanupScope() { + if (fScope instanceof ICPPASTInternalScope internalScope && fParameter != null) { + internalScope.removeNestedFromCache(fParameter); + } + } + + @Override + protected void afterResolution(ASTVisitor resolver, IASTNode best) { + beforeAlternative(best); + fParameter = null; + fScope = null; + } + + @Override + public boolean isParameterPack() { + throw new UnsupportedOperationException(); + } + + @Override + public ICPPASTTemplateParameter copy() { + throw new UnsupportedOperationException(); + } + + @Override + public ICPPASTTemplateParameter copy(CopyStyle style) { + throw new UnsupportedOperationException(); + } + + @Override + public IASTNode[] getNodes() { + return fNodes.toArray(new IASTNode[fNodes.size()]); + } + + public void addTypeConstraint(ICPPASTSimpleTypeTemplateParameter typeConstraint) { + assertNotFrozen(); + addNode(typeConstraint); + } + + public void addNonTypeParameter(ICPPASTParameterDeclaration nonTypeParameter) { + assertNotFrozen(); + addNode(nonTypeParameter); + } + + private void addNode(IASTNode node) { + fNodes.add(node); + node.setParent(this); + node.setPropertyInParent(ICPPASTTemplateDeclaration.PARAMETER); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConceptDefinition.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConceptDefinition.java new file mode 100644 index 00000000000..7959db65afc --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConceptDefinition.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2025 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.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConceptDefinition; + +public class CPPASTConceptDefinition extends CPPASTAttributeOwner implements ICPPASTConceptDefinition { + private IASTName name; + private IASTExpression expression; + + public CPPASTConceptDefinition(IASTName name, IASTExpression expr) { + setName(name); + setExpression(expr); + } + + @Override + public IASTName getName() { + return name; + } + + @Override + public void setName(IASTName name) { + assertNotFrozen(); + this.name = name; + if (name != null) { + name.setParent(this); + name.setPropertyInParent(CONCEPT_NAME); + } + this.name = name; + } + + @Override + public int getRoleForName(IASTName name) { + if (getName() == name) + return r_definition; + return r_unclear; + } + + @Override + public IASTExpression getExpression() { + return expression; + } + + @Override + public void setExpression(IASTExpression expr) { + // TODO Auto-generated method stub + assertNotFrozen(); + this.expression = expr; + if (expr != null) { + expr.setParent(this); + expr.setPropertyInParent(CONSTRAINT_EXPRESSION); + } + } + + @Override + public ICPPASTConceptDefinition copy() { + return copy(CopyStyle.withoutLocations); + } + + @Override + public ICPPASTConceptDefinition copy(CopyStyle style) { + IASTName nameCopy = name == null ? null : name.copy(style); + IASTExpression expressionCopy = expression == null ? null : expression.copy(style); + CPPASTConceptDefinition copy = new CPPASTConceptDefinition(nameCopy, expressionCopy); + return copy(copy, style); + } + + @Override + public boolean accept(ASTVisitor action) { + if (action.shouldVisitDeclarations) { + switch (action.visit(this)) { + case ASTVisitor.PROCESS_ABORT: + return false; + case ASTVisitor.PROCESS_SKIP: + return true; + default: + break; + } + } + + if (name != null && !name.accept(action)) + return false; + if (!acceptByAttributeSpecifiers(action)) + return false; + if (expression != null && !expression.accept(action)) + return false; + + if (action.shouldVisitDeclarations) { + switch (action.leave(this)) { + case ASTVisitor.PROCESS_ABORT: + return false; + case ASTVisitor.PROCESS_SKIP: + return true; + default: + break; + } + } + return true; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConstraintOwner.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConstraintOwner.java new file mode 100644 index 00000000000..92e870f5662 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConstraintOwner.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2025 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.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstraintOwner; +import org.eclipse.cdt.core.parser.util.ArrayUtil; + +public abstract class CPPASTConstraintOwner extends CPPASTAttributeOwner implements ICPPASTConstraintOwner { + private IASTExpression[] constraintExpressions = IASTExpression.EMPTY_EXPRESSION_ARRAY; + + protected T copy(T copy, CopyStyle style) { + for (IASTExpression constraintExpression : getConstraintExpressions()) { + copy.addConstraintExpression(constraintExpression.copy(style)); + } + return super.copy(copy, style); + } + + @Override + public IASTExpression[] getConstraintExpressions() { + constraintExpressions = ArrayUtil.trim(constraintExpressions); + return constraintExpressions; + } + + @Override + public void addConstraintExpression(IASTExpression expression) { + assertNotFrozen(); + if (expression != null) { + expression.setParent(this); + expression.setPropertyInParent(CONSTRAINT_SPECIFIER); + constraintExpressions = ArrayUtil.append(constraintExpressions, expression); + } + } + + protected boolean acceptByConstraints(ASTVisitor action) { + for (IASTExpression expr : constraintExpressions) { + if (expr == null) + break; + if (!expr.accept(action)) + return false; + } + + // return acceptByAttributeSpecifiers(action); + // TODO: see if chaining call to parent.accept() is desireable instead + return true; + } + + @Override + public boolean accept(ASTVisitor visitor) { + return acceptByConstraints(visitor); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java index 046ff4d4bf2..39f634f51d5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2015 IBM Corporation and others. + * Copyright (c) 2004, 2015, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -49,7 +49,7 @@ /** * C++ specific declarator. */ -public class CPPASTDeclarator extends CPPASTAttributeOwner +public class CPPASTDeclarator extends CPPASTConstraintOwner implements ICPPASTDeclarator, IASTImplicitNameOwner, ICPPExecutionOwner { private IASTInitializer initializer; private IASTName name; @@ -200,6 +200,9 @@ public boolean accept(ASTVisitor action) { if (!acceptByAttributeSpecifiers(action)) return false; + if (!acceptByConstraints(action)) + return false; + if (nested == null && name != null) { IASTDeclarator outermost = ASTQueries.findOutermostDeclarator(this); if (outermost.getPropertyInParent() != IASTTypeId.ABSTRACT_DECLARATOR) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeTemplateParameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeTemplateParameter.java index 370f5aa3972..b7ab7187117 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeTemplateParameter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSimpleTypeTemplateParameter.java @@ -15,6 +15,7 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; @@ -30,6 +31,25 @@ public class CPPASTSimpleTypeTemplateParameter extends ASTNode implements ICPPAS private boolean fUsesKeywordClass; private boolean fIsParameterPack; + private class TypeConstraintOwner extends CPPASTConstraintOwner { + @Override + public TypeConstraintOwner copy() { + return copy(CopyStyle.withoutLocations); + } + + @Override + public TypeConstraintOwner copy(CopyStyle style) { + TypeConstraintOwner copy = new TypeConstraintOwner(); + return copy(copy, style); + } + + protected T copy(T copy, CopyStyle style) { + return super.copy(copy, style); + } + } + + private TypeConstraintOwner fTypeConstraintOwner = null; + public CPPASTSimpleTypeTemplateParameter() { } @@ -51,6 +71,10 @@ public CPPASTSimpleTypeTemplateParameter copy(CopyStyle style) { copy.fIsParameterPack = fIsParameterPack; copy.setName(fName == null ? null : fName.copy(style)); copy.setDefaultType(fTypeId == null ? null : fTypeId.copy(style)); + if (fTypeConstraintOwner != null) { + copy.fTypeConstraintOwner = fTypeConstraintOwner.copy(style); + copy.fTypeConstraintOwner.setParent(copy); + } return copy(copy, style); } @@ -123,6 +147,8 @@ public boolean accept(ASTVisitor action) { return false; if (fTypeId != null && !fTypeId.accept(action)) return false; + if (fTypeConstraintOwner != null && !fTypeConstraintOwner.accept(action)) + return false; if (action.shouldVisitTemplateParameters && action.leave(this) == ASTVisitor.PROCESS_ABORT) return false; @@ -141,4 +167,21 @@ public int getRoleForName(IASTName n) { public String toString() { return getName().toString(); } + + @Override + public IASTExpression[] getConstraintExpressions() { + if (fTypeConstraintOwner == null) { + return IASTExpression.EMPTY_EXPRESSION_ARRAY; + } + return fTypeConstraintOwner.getConstraintExpressions(); + } + + @Override + public void addConstraintExpression(IASTExpression constraintExpression) { + if (fTypeConstraintOwner == null) { + fTypeConstraintOwner = new TypeConstraintOwner(); + fTypeConstraintOwner.setParent(this); + } + fTypeConstraintOwner.addConstraintExpression(constraintExpression); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateDeclaration.java index d048194b3da..fb58af37150 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateDeclaration.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateDeclaration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2013 IBM Corporation and others. + * Copyright (c) 2004, 2013, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -158,6 +158,13 @@ public void replace(IASTNode child, IASTNode other) { other.setPropertyInParent(child.getPropertyInParent()); declaration = (IASTDeclaration) other; } + for (int i = 0; i < parameters.length; ++i) { + if (child == parameters[i]) { + other.setPropertyInParent(child.getPropertyInParent()); + other.setParent(child.getParent()); + parameters[i] = (ICPPASTTemplateParameter) other; + } + } } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPConcept.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPConcept.java new file mode 100644 index 00000000000..1686f63a56c --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPConcept.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2025 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.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.ICPPASTConceptDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConcept; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.core.parser.util.ArrayUtil; +import org.eclipse.cdt.internal.core.dom.Linkage; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; +import org.eclipse.core.runtime.PlatformObject; + +public class CPPConcept extends PlatformObject implements ICPPConcept { + protected ICPPASTConceptDefinition definition; + private ICPPTemplateParameter[] templateParameters; + + public CPPConcept(ICPPASTConceptDefinition definition) { + this.definition = definition; + } + + private IASTName getTemplateName() { + return getASTName(); + } + + @Override + public ICPPTemplateParameter[] getTemplateParameters() { + if (templateParameters == null) { + ICPPTemplateParameter[] result = ICPPTemplateParameter.EMPTY_TEMPLATE_PARAMETER_ARRAY; + ICPPASTTemplateDeclaration template = CPPTemplates.getTemplateDeclaration(getTemplateName()); + if (template != null) { + ICPPASTTemplateParameter[] params = template.getTemplateParameters(); + for (ICPPASTTemplateParameter param : params) { + IBinding p = CPPTemplates.getTemplateParameterName(param).resolveBinding(); + if (p instanceof ICPPTemplateParameter) { + result = ArrayUtil.append(result, (ICPPTemplateParameter) p); + } + } + } + templateParameters = ArrayUtil.trim(result); + } + return templateParameters; + } + + @Override + public ICPPASTConceptDefinition getConceptDefinition() { + return definition; + } + + @Override + public String[] getQualifiedName() throws DOMException { + return CPPVisitor.getQualifiedName(this); + } + + @Override + public char[][] getQualifiedNameCharArray() throws DOMException { + return CPPVisitor.getQualifiedNameCharArray(this); + } + + @Override + public boolean isGloballyQualified() throws DOMException { + return true; + } + + @Override + public String getName() { + return getASTName().toString(); + } + + @Override + public char[] getNameCharArray() { + return getASTName().getSimpleID(); + } + + protected IASTName getASTName() { + return definition.getName(); + } + + @Override + public ILinkage getLinkage() { + return Linkage.CPP_LINKAGE; + } + + @Override + public IBinding getOwner() { + return CPPVisitor.findNameOwner(getASTName(), false); + } + + @Override + public IScope getScope() throws DOMException { + return CPPVisitor.getContainingScope(getASTName()); + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("concept "); //$NON-NLS-1$ + result.append(getName()); + return result.toString(); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java index ec3d36c8aef..fc168b482fd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNodeFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2016 IBM Corporation and others. + * Copyright (c) 2006, 2016, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -71,6 +71,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTClassVirtSpecifier; 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.ICPPASTConceptDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; @@ -583,6 +584,11 @@ public ICPPASTDeductionGuide newDeductionGuide() { return new CPPASTDeductionGuide(); } + @Override + public ICPPASTConceptDefinition newConcept(IASTName name, IASTExpression expr) { + return new CPPASTConceptDefinition(name, expr); + } + @Override public ICPPASTLinkageSpecification newLinkageSpecification(String literal) { return new CPPASTLinkageSpecification(literal); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariableTemplate.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariableTemplate.java index 7d321adbafb..d27cac52126 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariableTemplate.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariableTemplate.java @@ -1,6 +1,6 @@ /******************************************************************************* - * Copyright (c) 2015, 2016 Institute for Software, HSR Hochschule fuer Technik - * Rapperswil, University of applied sciences. + * Copyright (c) 2015, 2016, 2025 Institute for Software, HSR Hochschule fuer Technik + * Rapperswil, University of applied sciences, and others * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index 8f67748cc24..ff22fe7c5d3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2019 IBM Corporation and others. + * Copyright (c) 2002, 2019, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -88,6 +88,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTClassVirtSpecifier; 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.ICPPASTConceptDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; @@ -211,6 +212,7 @@ protected static enum DtorStrategy { private final boolean supportGCCStyleDesignators; private final boolean supportFoldExpression; private final boolean supportChar8TypeLiterals; + private final boolean supportConcepts; private final IIndex index; protected ICPPASTTranslationUnit translationUnit; @@ -250,6 +252,7 @@ public GNUCPPSourceParser(IScanner scanner, ParserMode mode, IParserLogService l additionalNumericalSuffixes = scanner.getAdditionalNumericLiteralSuffixes(); supportFoldExpression = true; supportChar8TypeLiterals = scanner.getMacroDefinitions().containsKey("__cpp_char8_t"); //$NON-NLS-1$ + supportConcepts = scanner.getMacroDefinitions().containsKey("__cpp_concepts"); //$NON-NLS-1$ } @Override @@ -1011,7 +1014,8 @@ protected ICPPASTExpression constantExpression() throws BacktrackException, EndO private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ctx, IASTInitializerClause expr, ITemplateIdStrategy strat) throws EndOfFileException, BacktrackException { final boolean allowComma = kind == ExprKind.eExpression; - boolean allowAssignment = kind != ExprKind.eConstant; + boolean allowAssignment = (kind != ExprKind.eConstant && kind != ExprKind.eRequiresClauseExpression); + final boolean primaryExpressionOnly = (kind == ExprKind.eRequiresClauseExpression); if (allowAssignment && LT(1) == IToken.t_throw) { return throwExpression(); @@ -1025,7 +1029,7 @@ private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ct IToken variantMark = mark(); if (expr == null) { - Object e = castExpressionForBinaryExpression(strat, ctx); + Object e = castOrPrimaryExpressionForBinaryExpression(strat, ctx, primaryExpressionOnly); if (e instanceof IASTExpression) { expr = (IASTExpression) e; } else { @@ -1211,7 +1215,7 @@ private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ct stopWithNextOperator = true; } else { // Could be ellipsis of any right fold expression or ellipsis of binary left fold expression - Object e = castExpressionForBinaryExpression(strat, ctx); + Object e = castOrPrimaryExpressionForBinaryExpression(strat, ctx, primaryExpressionOnly); if (e instanceof IASTExpression) { expr = (IASTExpression) e; @@ -1378,6 +1382,15 @@ public final IASTExpression buildExpression(BinaryOperator leftChain, IASTInitia return super.buildExpression(leftChain, expr); } + public Object castOrPrimaryExpressionForBinaryExpression(ITemplateIdStrategy s, final BinaryExprCtx ctx, + boolean primaryExpressionOnly) throws EndOfFileException, BacktrackException { + if (primaryExpressionOnly) { + return primaryExpression(CastExprCtx.eDirectlyInBExpr, s); + } else { + return castExpressionForBinaryExpression(s, ctx); + } + } + public Object castExpressionForBinaryExpression(ITemplateIdStrategy s, final BinaryExprCtx ctx) throws EndOfFileException, BacktrackException { @@ -2321,6 +2334,9 @@ protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy case IToken.tLBRACKET: return lambdaExpression(); + case IToken.t_requires: + return constraintExpression(); + default: IToken la = LA(1); int startingOffset = la.getOffset(); @@ -2633,6 +2649,35 @@ private IASTDeclaration aliasDeclaration(final int offset) throws EndOfFileExcep return setRange(aliasDeclaration, offset, endOffset); } + /** + * constraint-declaration + * constraint identifier attribute-specifier-seq? = constraint-expression ; + * + * @throws EndOfFileException + */ + private ICPPASTConceptDefinition conceptDefinition(final int offset) throws EndOfFileException, BacktrackException { + IToken identifierToken = consume(); + IASTName name = buildName(-1, identifierToken, false); + + consume(IToken.tASSIGN); + + IASTExpression constraintExpression = constraintExpression(); + + int endOffset; + switch (LT(1)) { + case IToken.tSEMI: + case IToken.tEOC: + endOffset = consume().getEndOffset(); + break; + default: + throw backtrack; + } + + ICPPASTConceptDefinition conceptDefinition = getNodeFactory().newConcept(name, constraintExpression); + + return setRange(conceptDefinition, offset, endOffset); + } + private ICPPASTUsingDeclaration usingDeclaration(final int offset) throws EndOfFileException, BacktrackException { boolean typeName = false; if (LT(1) == IToken.t_typename) { @@ -2770,14 +2815,36 @@ protected IASTDeclaration templateDeclaration(DeclarationOptions option) if (LT(1) != IToken.tEOC) { consume(IToken.tGT, IToken.tGT_in_SHIFTR); } - IASTDeclaration d = declaration(option); + + // TODO: add to list of constraints + IASTExpression requiresClause = requiresClause(); + // if (requiresClause != null) { + // int endOffset = calculateEndOffset(requiresClause); + // } + + IASTDeclaration d; + + if (LT(1) == IToken.t_concept) { + // concept declaration + int conceptOffset = consume().getEndOffset(); + d = conceptDefinition(conceptOffset); + } else { + d = declaration(option); + } + ICPPASTTemplateDeclaration templateDecl = getNodeFactory().newTemplateDeclaration(d); setRange(templateDecl, offset, calculateEndOffset(d)); templateDecl.setExported(exported); + if (requiresClause != null) { + // TODO: add to templateDecl + //templateDecl.addConstraintExpression(requiresClause); + } for (int i = 0; i < parms.size(); ++i) { ICPPASTTemplateParameter parm = parms.get(i); templateDecl.addTemplateParameter(parm); } + // TODO: C++20 13.5.3 Constrained declarations [temp.constr.decl] + // build and assign associated constraints for template declaration here return templateDecl; } @@ -2839,6 +2906,54 @@ private List templateParameterList(List typeConstraintEndOffset) { + // Non-type parameter is longer + return nonTypeParameter; + } else { + // Type-constraint is longer + backup(typeConstraintEnd); + return typeConstraint; + } + } + } + + IASTIdExpression synthesizeConstraintExpression(IASTName typeConstraintName, IASTName identifierName) + throws BacktrackException { + // synthesize requires clause: conceptName + IASTName templateParameterName = identifierName == null ? getNodeFactory().newName(CharArrayUtils.EMPTY) + : identifierName.copy(); + // place synthesized template parameter reference immediately after identifier name so it can be resolved by name lookup + ((ASTNode) templateParameterName).setOffsetAndLength(calculateEndOffset(identifierName), 0); + + IASTDeclSpecifier declSpecifier = buildNamedTypeSpecifier(templateParameterName, false, + IASTDeclSpecifier.sc_unspecified, 0, 0, 0); + ICPPASTDeclarator declarator = getNodeFactory().newDeclarator(null); + setDeclaratorID(declarator, false, getNodeFactory().newName(), null); + + IASTTypeId typeId = getNodeFactory().newTypeId(declSpecifier, declarator); + setRange(typeId, templateParameterName); + + ICPPASTNameSpecifier[] qualifier = null; + if (typeConstraintName instanceof ICPPASTQualifiedName qualifiedName) { + qualifier = qualifiedName.getQualifier(); + typeConstraintName = typeConstraintName.getLastName(); + } + + List constraintTemplateArgs = new ArrayList<>(2); + constraintTemplateArgs.add(typeId); + + if (typeConstraintName instanceof ICPPASTTemplateId templateId) { + typeConstraintName = templateId.getTemplateName(); + ArrayUtil.addAll(constraintTemplateArgs, templateId.getTemplateArguments()); + } + + // TODO: check if dedicated ICPPASTConceptId is better + ICPPASTName conceptId = buildTemplateID(typeConstraintName, calculateEndOffset(identifierName), + constraintTemplateArgs); + + if (qualifier != null) { + ICPPASTQualifiedName qname = getNodeFactory().newQualifiedName(null); + for (ICPPASTNameSpecifier specifier : qualifier) { + if (specifier instanceof ICPPASTName segment) { + qname.addName(segment.copy()); + } else { + // No decltype-specifiers in type-constraint + throwBacktrack(specifier); + } + } + qname.addName(conceptId); + conceptId = qname; + } + + setRange(conceptId, templateParameterName); + + IASTIdExpression constraintExpression = getNodeFactory().newIdExpression(conceptId); + setRange(constraintExpression, templateParameterName); + + return constraintExpression; } /** @@ -4860,7 +5084,7 @@ protected IASTDeclarator declarator(DtorStrategy strategy, IASTDeclSpecifier dec final IToken cand2End = LA(1); if (cand1End == cand2End) { CPPASTAmbiguousDeclarator result = new CPPASTAmbiguousDeclarator(cand1, cand2); - ((ASTNode) result).setOffsetAndLength((ASTNode) cand1); + result.setOffsetAndLength((ASTNode) cand1); return result; } // use the longer variant @@ -5123,6 +5347,42 @@ private ICPPASTFunctionDeclarator functionDeclarator(IASTName declaratorName, IA return fc; } + protected IASTExpression requiresExpression() throws EndOfFileException, BacktrackException { + final int offset = consume(IToken.t_requires).getOffset(); + + // TODO: dedicated ICPPASTConstraintExpression which looks like lambda but has no introducer and only used to check the constraint + ICPPASTLambdaExpression lambdaExpr = getNodeFactory().newLambdaExpression(); + + if (LT(1) == IToken.tLPAREN) { + ICPPASTFunctionDeclarator dtor = functionDeclarator((IASTName) null, (IASTDeclSpecifier) null, true); + lambdaExpr.setDeclarator(dtor); + if (LT(1) == IToken.tEOC) + return setRange(lambdaExpr, offset, calculateEndOffset(dtor)); + } + + IASTCompoundStatement body = functionBody(); + lambdaExpr.setBody(body); + return setRange(lambdaExpr, offset, calculateEndOffset(body)); + } + + protected IASTExpression constraintExpression() throws EndOfFileException, BacktrackException { + // TODO: add proper ICPPASTRequiresExpression + if (LTcatchEOF(1) == IToken.t_requires) { + return requiresExpression(); + } else { + return expression(ExprKind.eRequiresClauseExpression, BinaryExprCtx.eNotInTemplateID, null, null); + } + } + + protected IASTExpression requiresClause() throws EndOfFileException, BacktrackException { + if (LTcatchEOF(1) == IToken.t_requires) { + consume(); + return constraintExpression(); + } + + return null; + } + /** * Parse a function declarator starting with the left parenthesis. */ @@ -5270,6 +5530,14 @@ private void functionDeclarator(final ICPPASTFunctionDeclarator fc, boolean isLa fc.setNoexceptExpression((ICPPASTExpression) expression); } + // requires-clause goes last + // TODO: add to list of constraints + IASTExpression optionalRequiresClause = requiresClause(); + if (optionalRequiresClause != null) { + fc.addConstraintExpression(optionalRequiresClause); + endOffset = calculateEndOffset(optionalRequiresClause); + } + attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq()); addAttributeSpecifiers(attributes, fc); endOffset = attributesEndOffset(endOffset, attributes); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 5a136b53329..5495a2b4cfc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2023 IBM Corporation and others. + * Copyright (c) 2004, 2023, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -111,6 +111,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; 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.ICPPASTConceptDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; @@ -2219,7 +2220,9 @@ public static void populateCache(ICPPASTInternalScope scope, IASTNode node) { } } else if (node instanceof ICPPASTTemplateParameter) { IASTName name = CPPTemplates.getTemplateParameterName((ICPPASTTemplateParameter) node); - ASTInternal.addName(scope, name); + if (name != null) { // Could be null if node is ASTAmbiguousNode + ASTInternal.addName(scope, name); + } return; } if (declaration == null || declaration instanceof ASTAmbiguousNode) { @@ -2348,6 +2351,9 @@ public static void populateCache(ICPPASTInternalScope scope, IASTNode node) { default: break; } + } else if (declaration instanceof ICPPASTConceptDefinition constraintDecl) { + IASTName name = constraintDecl.getName(); + ASTInternal.addName(scope, name); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 24da67a469f..6f3c0cca4c3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2016 IBM Corporation and others. + * Copyright (c) 2004, 2016, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -112,6 +112,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; 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.ICPPASTConceptDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; @@ -211,6 +212,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPConcept; 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; @@ -357,6 +359,8 @@ public static IBinding createBinding(IASTName name) { return createBinding((ICPPASTElaboratedTypeSpecifier) parent); } else if (parent instanceof ICPPASTStructuredBindingDeclaration) { return new CPPVariable(name); + } else if (parent instanceof ICPPASTConceptDefinition decl) { + return new CPPConcept(decl); } else if (parent instanceof IASTDeclaration) { return createBinding((IASTDeclaration) parent); } else if (parent instanceof ICPPASTEnumerationSpecifier) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java index f76e5f14ca8..874eaa23bf9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexCPPBindingConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2016 Symbian Software Systems and others. + * Copyright (c) 2007, 2016, 2025 Symbian Software Systems and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -79,4 +79,5 @@ public interface IIndexCPPBindingConstants { 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; + int CPP_CONCEPT = IIndexBindingConstants.LAST_CONSTANT + 65; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java index 4d2c8677980..c8758536020 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2016 Symbian Software Systems and others. + * Copyright (c) 2007, 2016, 2025 Symbian Software Systems and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -35,6 +35,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.ICPPConcept; 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; @@ -766,6 +767,8 @@ public IIndexBinding getCompositeBinding(IIndexFragmentBinding binding) { } else if (binding instanceof ICPPVariableTemplate) { ICPPVariable def = (ICPPVariable) findOneBinding(binding); return new CompositeCPPVariableTemplate(this, def); + } else if (binding instanceof ICPPConcept concept) { + return new CompositeCPPConcept(this, concept); } else { throw new CompositingNotImplementedError( "Composite binding unavailable for " + binding + " " + binding.getClass()); //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPConcept.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPConcept.java new file mode 100644 index 00000000000..711ec6e6d73 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPConcept.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2025 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.ICPPASTConceptDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConcept; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory; + +public class CompositeCPPConcept extends CompositeCPPBinding implements ICPPConcept { + + public CompositeCPPConcept(ICompositesFactory cf, ICPPConcept concept) { + super(cf, concept); + } + + @Override + public ICPPTemplateParameter[] getTemplateParameters() { + return TemplateInstanceUtil.convert(cf, ((ICPPConcept) rbinding).getTemplateParameters()); + } + + @Override + public ICPPASTConceptDefinition getConceptDefinition() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java index dde7ed2e20c..63edb25df76 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2015 IBM Corporation and others. + * Copyright (c) 2004, 2015, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -101,6 +101,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { private static final char[] ONE = "1".toCharArray(); //$NON-NLS-1$ private static final char[] CPP_IMPL_THREE_WAY_COMPARISON = "__cpp_impl_three_way_comparison".toCharArray(); //$NON-NLS-1$ private static final char[] CPP_CHAR8_T = "__cpp_char8_t".toCharArray(); //$NON-NLS-1$ + private static final char[] CPP_CONCEPTS_T = "__cpp_concepts".toCharArray(); //$NON-NLS-1$ // Standard built-ins private static final ObjectStyleMacro __CDT_PARSER__ = new ObjectStyleMacro("__CDT_PARSER__".toCharArray(), //$NON-NLS-1$ @@ -360,6 +361,10 @@ public CPreprocessor(FileContent fileContent, IScannerInfo info, ParserLanguage if (fMacroDictionary.containsKey(CPP_IMPL_THREE_WAY_COMPARISON)) { fLexOptions.fSupportThreeWayComparisonOperator = true; } + if (fMacroDictionary.containsKey(CPP_CONCEPTS_T)) { + fKeywords.put(Keywords.cCONCEPT, IToken.t_concept); + fKeywords.put(Keywords.cREQUIRES, IToken.t_requires); + } ILocationCtx ctx = fLocationMap.pushTranslationUnit(fRootContent.getFileLocation(), fRootContent.getSource()); Lexer lexer = new Lexer(fRootContent.getSource(), fLexOptions, this, this); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java index 8fe672ed025..8b68d1b556a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/token/KeywordSets.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2015 IBM Corporation and others. + * Copyright (c) 2002, 2015, 2025 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -498,6 +498,7 @@ public static Set getKeywords(KeywordSetKey kind, ParserLanguage languag KEYWORDS_CPP.add(Keywords.CHAR32_T); KEYWORDS_CPP.add(Keywords.CLASS); KEYWORDS_CPP.add(Keywords.COMPL); + KEYWORDS_CPP.add(Keywords.CONCEPT); KEYWORDS_CPP.add(Keywords.CONST); KEYWORDS_CPP.add(Keywords.CONSTEXPR); KEYWORDS_CPP.add(Keywords.CONST_CAST); @@ -539,6 +540,7 @@ public static Set getKeywords(KeywordSetKey kind, ParserLanguage languag KEYWORDS_CPP.add(Keywords.PUBLIC); KEYWORDS_CPP.add(Keywords.REGISTER); KEYWORDS_CPP.add(Keywords.REINTERPRET_CAST); + KEYWORDS_CPP.add(Keywords.REQUIRES); KEYWORDS_CPP.add(Keywords.RESTRICT); KEYWORDS_CPP.add(Keywords.RETURN); KEYWORDS_CPP.add(Keywords.SHORT); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPConcept.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPConcept.java new file mode 100644 index 00000000000..28a7040f4f5 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPConcept.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2025 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.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConceptDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConcept; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; +import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants; +import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; +import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; +import org.eclipse.core.runtime.CoreException; + +class PDOMCPPConcept extends PDOMCPPBinding implements ICPPConcept, IPDOMCPPTemplateParameterOwner { + /** + * Offset of RecPtr to record holding template parameters (relative to the beginning of the record). + * Field size: PDOMCPPBinding.RECORD_SIZE + */ + private static final int TEMPLATE_PARAMS = PDOMCPPBinding.RECORD_SIZE + 0; + + /** + * The size in bytes of a PDOMCPPConcept record in the database. + */ + @SuppressWarnings("hiding") + protected static final int RECORD_SIZE = TEMPLATE_PARAMS + PDOMCPPBinding.RECORD_SIZE; + + private volatile IPDOMCPPTemplateParameter[] parameters; // Cached template parameters. + + public PDOMCPPConcept(PDOMCPPLinkage linkage, PDOMNode parent, ICPPConcept concept) + throws CoreException, DOMException { + super(linkage, parent, concept.getNameCharArray()); + + final ICPPTemplateParameter[] origParams = concept.getTemplateParameters(); + IPDOMCPPTemplateParameter[] params = PDOMTemplateParameterArray.createPDOMTemplateParameters(linkage, this, + origParams); + final Database db = getDB(); + long rec = PDOMTemplateParameterArray.putArray(db, params); + db.putRecPtr(record + TEMPLATE_PARAMS, rec); + linkage.new ConfigureTemplateParameters(origParams, params); + } + + public PDOMCPPConcept(PDOMCPPLinkage linkage, long record) { + super(linkage, record); + } + + @Override + public void update(PDOMLinkage linkage, IBinding newBinding) { + // no support for updating templates, yet. + } + + @Override + protected int getRecordSize() { + return RECORD_SIZE; + } + + @Override + public int getNodeType() { + return IIndexCPPBindingConstants.CPP_CONCEPT; + } + + @Override + public IPDOMCPPTemplateParameter[] getTemplateParameters() { + if (parameters == null) { + try { + long rec = getDB().getRecPtr(record + TEMPLATE_PARAMS); + if (rec == 0) { + parameters = IPDOMCPPTemplateParameter.EMPTY_ARRAY; + } else { + parameters = PDOMTemplateParameterArray.getArray(this, rec); + } + } catch (CoreException e) { + CCorePlugin.log(e); + parameters = IPDOMCPPTemplateParameter.EMPTY_ARRAY; + } + } + return parameters; + } + + @Override + public ICPPASTConceptDefinition getConceptDefinition() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ICPPTemplateParameter adaptTemplateParameter(ICPPTemplateParameter param) { + // Template parameters are identified by their position in the parameter list. + int pos = param.getParameterPosition(); + ICPPTemplateParameter[] pars = getTemplateParameters(); + + if (pars == null || pos >= pars.length) + return null; + + ICPPTemplateParameter result = pars[pos]; + if (param instanceof ICPPTemplateTypeParameter) { + if (result instanceof ICPPTemplateTypeParameter) + return result; + } else if (param instanceof ICPPTemplateNonTypeParameter) { + if (result instanceof ICPPTemplateNonTypeParameter) + return result; + } else if (param instanceof ICPPTemplateTemplateParameter) { + if (result instanceof ICPPTemplateTemplateParameter) + return result; + } + return null; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java index c8e44fcdd2f..abd5d4124e5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2016 QNX Software Systems and others. + * Copyright (c) 2005, 2016, 2025 QNX Software Systems and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -59,6 +59,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.ICPPConcept; 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; @@ -888,6 +889,8 @@ PDOMBinding createBinding(PDOMNode parent, IBinding binding, long fileLocalRec) (ICPPAliasTemplateInstance) binding); } else if (binding instanceof ITypedef) { pdomBinding = new PDOMCPPTypedef(this, parent, (ITypedef) binding); + } else if (binding instanceof ICPPConcept concept) { + pdomBinding = new PDOMCPPConcept(this, parent, concept); } if (pdomBinding != null) { @@ -1420,6 +1423,8 @@ public PDOMNode getNode(long record, int nodeType) throws CoreException { return new PDOMCPPDeductionGuide(this, record); case CPP_DEDUCTION_GUIDE_TEMPLATE: return new PDOMCPPDeductionGuideTemplate(this, record); + case CPP_CONCEPT: + return new PDOMCPPConcept(this, record); } assert false : "nodeid= " + nodeType; //$NON-NLS-1$ return null; diff --git a/core/org.eclipse.cdt.core/plugin.xml b/core/org.eclipse.cdt.core/plugin.xml index 37b683e9ebf..deef5999223 100644 --- a/core/org.eclipse.cdt.core/plugin.xml +++ b/core/org.eclipse.cdt.core/plugin.xml @@ -639,7 +639,7 @@ + file-names="ciso646,climits,clocale,cmath,codecvt,compare,complex,concepts,csetjmp,csignal,cstdarg,cstdbool,cstddef"/>