From b25f204b90ff50f7814820653a4bacebe010030f Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Fri, 9 Dec 2022 21:07:58 +0300 Subject: [PATCH] Add c++17 fold expression --- .../tests/ast2/cxx17/FoldExpressionTests.java | 125 +++++++ .../dom/ast/cpp/ICPPASTFoldExpression.java | 26 ++ .../cdt/core/dom/ast/cpp/ICPPNodeFactory.java | 11 + .../parser/AbstractGNUSourceCodeParser.java | 6 +- .../core/dom/parser/ITypeMarshalBuffer.java | 2 +- .../dom/parser/cpp/CPPASTFoldExpression.java | 232 +++++++++++++ .../parser/cpp/CPPASTFoldExpressionToken.java | 49 +++ .../core/dom/parser/cpp/CPPNodeFactory.java | 12 + .../dom/parser/cpp/GNUCPPSourceParser.java | 319 +++++++++++++++++- .../cpp/semantics/EvalFoldExpression.java | 318 +++++++++++++++++ .../core/pdom/dom/cpp/PDOMCPPLinkage.java | 3 + 11 files changed, 1096 insertions(+), 7 deletions(-) create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/FoldExpressionTests.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFoldExpression.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpression.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpressionToken.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFoldExpression.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/FoldExpressionTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/FoldExpressionTests.java new file mode 100644 index 00000000000..92640328fa8 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx17/FoldExpressionTests.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * 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.parser.tests.ast2.cxx17; + +import static org.eclipse.cdt.core.parser.ParserLanguage.CPP; + +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTProblemStatement; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase; + +/** + * AST tests for C++17 fold expressions. + */ +public class FoldExpressionTests extends AST2CPPTestBase { + // using size_t = decltype(sizeof(int)); + // + // template struct X { + // static constexpr size_t g(const T& arg) noexcept { return sizeof(arg); } + // }; + // + // template + // constexpr size_t f1(const Pack&... pack) { return (... + X::g(pack)); } + // template + // constexpr size_t f2(const Pack&... pack) { return (0 + ... + X::g(pack)); } + // template + // constexpr size_t f3(const Pack&... pack) { return (X::g(pack) + ...); } + // template + // constexpr size_t f4(const Pack&... pack) { return (X::g(pack) + ... + 0); } + // + // static constexpr auto val1 = f1(1, 2., "1"); + // static constexpr auto val2 = f2(1, 2., "12"); + // static constexpr auto val3 = f3(1, 2., "123"); + // static constexpr auto val4 = f4(1, 2., "1234"); + public void testFoldExpression1() throws Exception { + parseAndCheckBindings(); + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableValue("val1", 14); + helper.assertVariableValue("val2", 15); + helper.assertVariableValue("val3", 16); + helper.assertVariableValue("val4", 17); + } + + // template + // constexpr bool f1(const Pack&... pack) { return (... && pack); } + // template + // constexpr bool f2(const Pack&... pack) { return (pack && ...); } + // template + // constexpr bool f3(const Pack&... pack) { return (... || pack); } + // template + // constexpr bool f4(const Pack&... pack) { return (pack || ...); } + // + // static constexpr auto val1 = f1(); + // static constexpr auto val21 = f2(false); + // static constexpr auto val22 = f2(true); + // static constexpr auto val3 = f3(); + // static constexpr auto val41 = f4(false); + // static constexpr auto val42 = f4(true); + public void testFoldExpression2() throws Exception { + parseAndCheckBindings(); + BindingAssertionHelper helper = getAssertionHelper(); + helper.assertVariableValue("val1", 1); + helper.assertVariableValue("val21", 0); + helper.assertVariableValue("val22", 1); + helper.assertVariableValue("val3", 0); + helper.assertVariableValue("val41", 0); + helper.assertVariableValue("val42", 1); + } + + // template + // struct ostream { + // template + // ostream& operator<<(T); + // + // ostream& operator<<(ostream&(*)(ostream&)); + // }; + // + // template + // ostream& endl(ostream&); + // + // template + // void sum(T... vals) { + // ostream out; + // out << (... + vals) << endl; + // } + public void testFoldExpressionInBinaryExpression() throws Exception { + parseAndCheckBindings(); + } + + // template + // void sum(T... vals) { + // bar(... + vals); + // } + public void testFoldExpressionRecognition1() throws Exception { + final String code = getAboveComment(); + IASTTranslationUnit tu = parse(code, CPP, ScannerKind.STD, false); + ICPPASTTemplateDeclaration tdef = getDeclaration(tu, 0); + IASTFunctionDefinition fdef = (IASTFunctionDefinition) tdef.getDeclaration(); + IASTProblemStatement p1 = getStatement(fdef, 0); + } + + // template + // void sum(T... vals) { + // ... + vals; + // } + public void testFoldExpressionRecognition2() throws Exception { + final String code = getAboveComment(); + IASTTranslationUnit tu = parse(code, CPP, ScannerKind.STD, false); + ICPPASTTemplateDeclaration tdef = getDeclaration(tu, 0); + IASTFunctionDefinition fdef = (IASTFunctionDefinition) tdef.getDeclaration(); + IASTProblemStatement p1 = getStatement(fdef, 0); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFoldExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFoldExpression.java new file mode 100644 index 00000000000..a295fdfd42c --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTFoldExpression.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2022 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; + +/** + * Fold expression, introduced in C++17. + * + * @since 8.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ + +public interface ICPPASTFoldExpression extends ICPPASTExpression { + +} 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 49fecf38bf6..34d0cf13c97 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 @@ -242,6 +242,17 @@ public ICPPASTFunctionWithTryBlock newFunctionTryBlock(IASTDeclSpecifier declSpe */ public ICPPASTLambdaExpression newLambdaExpression(); + /** + * @since 8.0 + */ + public IASTExpression newFoldExpressionToken(); + + /** + * @since 8.0 + */ + public ICPPASTFoldExpression newFoldExpression(int opToken, boolean isComma, IASTExpression lhs, + IASTExpression rhs); + public ICPPASTLinkageSpecification newLinkageSpecification(String literal); @Override 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 9b7b8232643..4ed2f60df8a 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 @@ -1010,9 +1010,13 @@ public BinaryOperator getNext() { public void setNext(BinaryOperator next) { fNext = next; } + + public int getOperatorToken() { + return fOperatorToken; + } } - public final IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) { + public IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) { BinaryOperator rightChain = null; for (;;) { if (leftChain == null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java index b7e352d7bf1..edf791a93bd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ITypeMarshalBuffer.java @@ -45,7 +45,7 @@ public interface ITypeMarshalBuffer { EVAL_FUNCTION_SET = 0x09, EVAL_ID = 0x0A, EVAL_INIT_LIST = 0x0B, EVAL_MEMBER_ACCESS = 0x0C, EVAL_PACK_EXPANSION = 0x0D, EVAL_TYPE_ID = 0x0E, EVAL_UNARY = 0x0F, EVAL_UNARY_TYPE_ID = 0x10, EVAL_CONSTRUCTOR = 0x11, EVAL_REFERENCE = 0x12, EVAL_POINTER = 0x13, EVAL_COMPOSITE_ACCESS = 0x14, - EVAL_NARY_TYPE_ID = 0x15; + EVAL_NARY_TYPE_ID = 0x15, EVAL_FOLD_EXPRESSION = 0x16; // Can add more evaluations up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE. final static byte EXEC_COMPOUND_STATEMENT = 0x01, EXEC_BREAK = 0x02, EXEC_CASE = 0x03, EXEC_CONTINUE = 0x04, diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpression.java new file mode 100644 index 00000000000..4a88b91491f --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpression.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2022 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 static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFoldExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPackExpansionExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; +import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPEvaluation; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.DestructorCallCollector; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFoldExpression; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalPackExpansion; + +/** + * Implementation for fold expressions. + */ +public class CPPASTFoldExpression extends ASTNode implements ICPPASTFoldExpression, IASTAmbiguityParent { + private final int fOperator; + private final boolean fIsComma; + private ICPPASTExpression fLhs; + private ICPPASTExpression fRhs; + private ICPPEvaluation fEvaluation; + + private IASTImplicitDestructorName[] fImplicitDestructorNames; + + public CPPASTFoldExpression(int operator, boolean isComma, IASTExpression lhs, IASTExpression rhs) { + fOperator = operator; + fIsComma = isComma; + setOperand1(lhs); + setOperand2(rhs); + } + + private void setOperand1(IASTExpression expression) { + assertNotFrozen(); + if (expression != null) { + if (!(expression instanceof ICPPASTExpression)) { + throw new IllegalArgumentException(expression.getClass().getName()); + } + + expression.setParent(this); + } + fLhs = (ICPPASTExpression) expression; + } + + public void setOperand2(IASTExpression operand) { + assertNotFrozen(); + if (operand != null) { + if (!(operand instanceof ICPPASTExpression)) { + throw new IllegalArgumentException(operand.getClass().getName()); + } + operand.setParent(this); + } + fRhs = (ICPPASTExpression) operand; + } + + @Override + public IASTExpression copy() { + return copy(CopyStyle.withoutLocations); + } + + @Override + public IASTExpression copy(CopyStyle style) { + IASTExpression fLhsCopy = fLhs == null ? null : fLhs.copy(style); + IASTExpression fRhsCopy = fRhs == null ? null : fRhs.copy(style); + + CPPASTFoldExpression copy = new CPPASTFoldExpression(fOperator, fIsComma, fLhsCopy, fRhsCopy); + return copy(copy, style); + } + + @Override + public ICPPEvaluation getEvaluation() { + if (fEvaluation == null) { + fEvaluation = computeEvaluation(); + } + + return fEvaluation; + } + + private final class UnexpandedParameterPackCounter extends ASTVisitor { + int count; + + public UnexpandedParameterPackCounter() { + super(false); + shouldVisitExpressions = true; + count = 0; + } + + public int getCount() { + return count; + } + + @Override + public int visit(IASTExpression expression) { + if (expression instanceof ICPPASTPackExpansionExpression) { + return PROCESS_SKIP; + } + + IType type = expression.getExpressionType(); + if (type instanceof ICPPParameterPackType) { + ++count; + } + return PROCESS_CONTINUE; + } + } + + private int countUnexpandedParameterPacks(IASTExpression e) { + if (e == null) { + return 0; + } + UnexpandedParameterPackCounter counter = new UnexpandedParameterPackCounter(); + e.accept(counter); + return counter.getCount(); + } + + private ICPPEvaluation computeEvaluation() { + int lhsParameterPackCount = countUnexpandedParameterPacks(fLhs); + int rhsParameterPackCount = countUnexpandedParameterPacks(fRhs); + + // Either left or right hand side expression shall contain an unexpanded parameter pack, + // but not both. + if (!((lhsParameterPackCount != 0) ^ (rhsParameterPackCount != 0))) { + return EvalFixed.INCOMPLETE; + } + + ICPPEvaluation packEval; + ICPPEvaluation initEval; + boolean isLeftFold; + + ICPPEvaluation evalL = fLhs == null ? null : fLhs.getEvaluation(); + ICPPEvaluation evalR = fRhs == null ? null : fRhs.getEvaluation(); + + if (lhsParameterPackCount == 0) { + isLeftFold = true; + initEval = evalL; + packEval = evalR; + } else { + isLeftFold = false; + initEval = evalR; + packEval = evalL; + } + + ICPPEvaluation[] foldPattern = new ICPPEvaluation[] { new EvalPackExpansion(packEval, this) }; + return new EvalFoldExpression(fOperator, fIsComma, isLeftFold, foldPattern, initEval, this); + } + + @Override + public IType getExpressionType() { + return CPPEvaluation.getType(this); + } + + @Override + public boolean isLValue() { + return getValueCategory() == LVALUE; + } + + @Override + public ValueCategory getValueCategory() { + return CPPEvaluation.getValueCategory(this); + } + + @Override + public IASTImplicitDestructorName[] getImplicitDestructorNames() { + if (fImplicitDestructorNames == null) { + fImplicitDestructorNames = DestructorCallCollector.getTemporariesDestructorCalls(this); + } + + return fImplicitDestructorNames; + } + + @Override + public boolean accept(ASTVisitor action) { + if (action.shouldVisitExpressions) { + switch (action.visit(this)) { + case ASTVisitor.PROCESS_ABORT: + return false; + case ASTVisitor.PROCESS_SKIP: + return true; + default: + break; + } + } + + if (fLhs != null && !fLhs.accept(action)) { + return false; + } + + if (fRhs != null && !fRhs.accept(action)) { + return false; + } + + if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT) { + return false; + } + + return true; + } + + @Override + public void replace(IASTNode child, IASTNode other) { + if (child == fLhs) { + other.setPropertyInParent(child.getPropertyInParent()); + other.setParent(child.getParent()); + fLhs = (ICPPASTExpression) other; + } + if (child == fRhs) { + other.setPropertyInParent(child.getPropertyInParent()); + other.setParent(child.getParent()); + fRhs = (ICPPASTExpression) other; + } + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpressionToken.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpressionToken.java new file mode 100644 index 00000000000..4126ec17de6 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFoldExpressionToken.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; + +/** + * Represents ... token in fold expression. + */ +public class CPPASTFoldExpressionToken extends ASTNode implements IASTExpression { + + @Override + public IType getExpressionType() { + return null; + } + + @Override + public boolean isLValue() { + return false; + } + + @Override + public ValueCategory getValueCategory() { + return null; + } + + @Override + public IASTExpression copy() { + return null; + } + + @Override + public IASTExpression copy(CopyStyle style) { + return null; + } +} 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 b659a58cc17..1a2ed030d54 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 @@ -88,6 +88,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFoldExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; @@ -565,6 +566,17 @@ public ICPPASTLambdaExpression newLambdaExpression() { return new CPPASTLambdaExpression(); } + @Override + public IASTExpression newFoldExpressionToken() { + return new CPPASTFoldExpressionToken(); + } + + @Override + public ICPPASTFoldExpression newFoldExpression(int operator, boolean fIsComma, IASTExpression lhs, + IASTExpression rhs) { + return new CPPASTFoldExpression(operator, fIsComma, lhs, rhs); + } + @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/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index 4709d51a4e7..13e5a301f65 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 @@ -64,6 +64,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTProblemExpression; import org.eclipse.cdt.core.dom.ast.IASTProblemTypeId; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; @@ -104,6 +105,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldDesignator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFoldExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator.RefQualifier; @@ -206,6 +208,7 @@ protected static enum DtorStrategy { private final boolean supportAutoTypeSpecifier; private final boolean supportUserDefinedLiterals; private final boolean supportGCCStyleDesignators; + private final boolean supportFoldExpression; private final IIndex index; protected ICPPASTTranslationUnit translationUnit; @@ -243,6 +246,7 @@ public GNUCPPSourceParser(IScanner scanner, ParserMode mode, IParserLogService l scanner.setSplitShiftROperator(true); fContextSensitiveTokens = createContextSensitiveTokenMap(config); additionalNumericalSuffixes = scanner.getAdditionalNumericLiteralSuffixes(); + supportFoldExpression = true; } @Override @@ -984,7 +988,7 @@ private IASTName operatorId() throws BacktrackException, EndOfFileException { * else where. */ private enum BinaryExprCtx { - eInTemplateID, eNotInTemplateID + eInTemplateID, eNotInTemplateID, eInPrimaryExpression } @Override @@ -1014,6 +1018,14 @@ private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ct IToken variantMark = mark(); if (expr == null) { + // Could be ellipsis of unary left fold expression + IASTExpression foldExpression = foldStartingExpression(ctx, strat); + if (foldExpression != null) { + lt1 = LT(1); + lastOperator = new BinaryOperator(lastOperator, foldExpression, lt1, 0, 0); + consume(); // consume operator token + } + Object e = castExpressionForBinaryExpression(strat); if (e instanceof IASTExpression) { expr = (IASTExpression) e; @@ -1022,7 +1034,7 @@ private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ct final Variant variant = (Variant) e; expr = variant.getExpression(); - variants.addBranchPoint(variant.getNext(), null, allowAssignment, conditionCount); + variants.addBranchPoint(variant.getNext(), lastOperator, allowAssignment, conditionCount); } } @@ -1196,7 +1208,12 @@ private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ct if (lt1 != IToken.tCOLON && lt1 != IToken.tCOMMA) stopWithNextOperator = true; } else { - Object e = castExpressionForBinaryExpression(strat); + // Could be ellipsis of any right fold expression or ellipsis of binary left fold expression + Object e = foldInsideExpression(ctx, strat, lt1); + if (e == null) { + e = castExpressionForBinaryExpression(strat); + } + if (e instanceof IASTExpression) { expr = (IASTExpression) e; } else { @@ -1256,6 +1273,134 @@ private ICPPASTExpression expression(final ExprKind kind, final BinaryExprCtx ct return (ICPPASTExpression) buildExpression(lastOperator, expr); } + private int calculateFirstOffset(BinaryOperator leftChain, IASTInitializerClause expr) { + int firstOffset = ((ASTNode) expr).getOffset(); + + while (leftChain != null) { + expr = leftChain.getExpression(); + if (expr != null) { + int exprOffset = ((ASTNode) expr).getOffset(); + if (firstOffset > exprOffset) { + firstOffset = exprOffset; + } + } + leftChain = leftChain.getNext(); + } + + return firstOffset; + } + + @Override + public final IASTExpression buildExpression(BinaryOperator leftChain, IASTInitializerClause expr) { + if (supportFoldExpression && leftChain != null && expr != null) { + int foldCount = 0; + int foldOpToken = 0; + + int firstOffset = calculateFirstOffset(leftChain, expr); + int endOffset = calculateEndOffset(expr); + + if (expr instanceof CPPASTFoldExpressionToken) { + // unary right fold: (pack op ...) + ++foldCount; + } + + BinaryOperator prev = null; + BinaryOperator foldOp = null; + BinaryOperator foldOpPrev = null; + + scanFoldExpressions: for (BinaryOperator op = leftChain; op != null; op = op.getNext()) { + if (op.getExpression() instanceof CPPASTFoldExpressionToken) { + if (++foldCount == 1) { + foldOp = op; + foldOpPrev = prev; + } else { + // only single fold token allowed + foldOp = null; + foldOpPrev = null; + break scanFoldExpressions; + } + } else { + prev = op; + } + } + + if (foldCount == 1) { + BinaryOperator rightChain; + if (foldOp == null) { + // unary right fold, remove expression and use left chain as is + foldOpToken = leftChain.getOperatorToken(); + expr = null; + rightChain = null; + } else { + foldOpToken = foldOp.getOperatorToken(); + + if (foldOpPrev != null) { + // if fold token is not the rightmost one in original chain, + // break the chain and move front part to the right + foldOpPrev.setNext(null); + rightChain = leftChain; + } else { + rightChain = null; + } + // move tail part to the left + leftChain = foldOp.getNext(); + } + + IASTExpression lhs = leftChain == null ? null + : super.buildExpression(leftChain.getNext(), leftChain.getExpression()); + IASTExpression rhs = super.buildExpression(rightChain, expr); + + return buildFoldExpression(foldOpToken, lhs, rhs, firstOffset, endOffset); + } else if (foldCount > 1) { + IASTProblem problem = createProblem(IProblem.SYNTAX_ERROR, firstOffset, endOffset - firstOffset); + IASTProblemExpression pexpr = getNodeFactory().newProblemExpression(problem); + ((ASTNode) pexpr).setOffsetAndLength(((ASTNode) problem)); + return pexpr; + } + } + + return super.buildExpression(leftChain, expr); + } + + private IASTExpression foldStartingExpression(final BinaryExprCtx ctx, ITemplateIdStrategy strat) + throws EndOfFileException, BacktrackException { + + if (supportFoldExpression && ctx == BinaryExprCtx.eInPrimaryExpression) { + if (LTcatchEOF(1) == IToken.tELLIPSIS) { + int rightOpToken = LTcatchEOF(2); + if (allowedFoldExpressionOpToken(rightOpToken)) { + // unary left fold expression: (... op pack) + IToken foldToken = consume(); + return buildFoldExpressionToken(foldToken.getOffset(), foldToken.getEndOffset()); + } + } + } + + return null; + } + + private IASTExpression foldInsideExpression(final BinaryExprCtx ctx, ITemplateIdStrategy strat, int leftOpToken) + throws EndOfFileException, BacktrackException { + + if (supportFoldExpression && ctx == BinaryExprCtx.eInPrimaryExpression) { + if (LTcatchEOF(1) == IToken.tELLIPSIS) { + if (allowedFoldExpressionOpToken(leftOpToken)) { + int rightOpToken = LTcatchEOF(2); + if (rightOpToken == 0 || rightOpToken == IToken.tRPAREN || rightOpToken == leftOpToken) { + // unary right fold: (... op pack) + // or + // binary right fold: (pack op ... op init) + // binary left fold: (init op ... op pack) + IToken foldToken = consume(); + return buildFoldExpressionToken(foldToken.getOffset(), foldToken.getEndOffset()); + } + } + } + } + + return null; + } + public Object castExpressionForBinaryExpression(ITemplateIdStrategy s) throws EndOfFileException, BacktrackException { if (s != null) { @@ -1312,6 +1457,124 @@ protected IASTExpression buildBinaryExpression(int operator, IASTExpression expr return result; } + private IASTExpression buildFoldExpressionToken(int firstOffset, int lastOffset) { + IASTExpression result = getNodeFactory().newFoldExpressionToken(); + ((ASTNode) result).setOffsetAndLength(firstOffset, lastOffset - firstOffset); + return result; + } + + private ICPPASTFoldExpression buildFoldExpression(int opToken, IASTExpression expr1, IASTExpression expr2, + int firstOffset, int lastOffset) { + int op = 0; + boolean isComma = false; + + switch (opToken) { + case IToken.tPLUS: + op = IASTBinaryExpression.op_plus; + break; + case IToken.tMINUS: + op = IASTBinaryExpression.op_minus; + break; + case IToken.tSTAR: + op = IASTBinaryExpression.op_multiply; + break; + case IToken.tDIV: + op = IASTBinaryExpression.op_divide; + break; + case IToken.tMOD: + op = IASTBinaryExpression.op_modulo; + break; + case IToken.tXOR: + op = IASTBinaryExpression.op_binaryXor; + break; + case IToken.tAMPER: + op = IASTBinaryExpression.op_binaryAnd; + break; + case IToken.tBITOR: + op = IASTBinaryExpression.op_binaryOr; + break; + case IToken.tASSIGN: + op = IASTBinaryExpression.op_assign; + break; + case IToken.tLT: + op = IASTBinaryExpression.op_lessThan; + break; + case IToken.tGT: + op = IASTBinaryExpression.op_greaterThan; + break; + case IToken.tSHIFTL: + op = IASTBinaryExpression.op_shiftLeft; + break; + case IToken.tSHIFTR: + op = IASTBinaryExpression.op_shiftRight; + break; + case IToken.tPLUSASSIGN: + op = IASTBinaryExpression.op_plusAssign; + break; + case IToken.tMINUSASSIGN: + op = IASTBinaryExpression.op_minusAssign; + break; + case IToken.tSTARASSIGN: + op = IASTBinaryExpression.op_multiplyAssign; + break; + case IToken.tDIVASSIGN: + op = IASTBinaryExpression.op_divideAssign; + break; + case IToken.tMODASSIGN: + op = IASTBinaryExpression.op_moduloAssign; + break; + case IToken.tXORASSIGN: + op = IASTBinaryExpression.op_binaryXorAssign; + break; + case IToken.tAMPERASSIGN: + op = IASTBinaryExpression.op_binaryAndAssign; + break; + case IToken.tBITORASSIGN: + op = IASTBinaryExpression.op_binaryOrAssign; + break; + case IToken.tSHIFTLASSIGN: + op = IASTBinaryExpression.op_shiftLeftAssign; + break; + case IToken.tSHIFTRASSIGN: + op = IASTBinaryExpression.op_shiftRightAssign; + break; + case IToken.tEQUAL: + op = IASTBinaryExpression.op_equals; + break; + case IToken.tNOTEQUAL: + op = IASTBinaryExpression.op_notequals; + break; + case IToken.tLTEQUAL: + op = IASTBinaryExpression.op_lessEqual; + break; + case IToken.tGTEQUAL: + op = IASTBinaryExpression.op_greaterEqual; + break; + case IToken.tAND: + op = IASTBinaryExpression.op_logicalAnd; + break; + case IToken.tOR: + op = IASTBinaryExpression.op_logicalOr; + break; + case IToken.tCOMMA: + isComma = true; + break; + case IToken.tDOTSTAR: + op = IASTBinaryExpression.op_pmdot; + break; + case IToken.tARROWSTAR: + op = IASTBinaryExpression.op_pmarrow; + break; + + default: + return null; + } + + ICPPASTFoldExpression result = getNodeFactory().newFoldExpression(op, isComma, expr1, expr2); + ((ASTNode) result).setOffsetAndLength(firstOffset, lastOffset - firstOffset); + return result; + } + private ICPPASTExpression throwExpression() throws EndOfFileException, BacktrackException { IToken throwToken = consume(); IASTExpression throwExpression = null; @@ -2013,12 +2276,13 @@ protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy literalExpr = getNodeFactory().newLiteralExpression(IASTLiteralExpression.lk_this, t.getImage()); return setRange(literalExpr, t.getOffset(), t.getEndOffset()); case IToken.tLPAREN: + // ( expression ) or fold-expression if (supportStatementsInExpressions && LT(2) == IToken.tLBRACE) { return compoundStatementExpression(); } t = consume(); int finalOffset = 0; - IASTExpression lhs = expression(ExprKind.eExpression, BinaryExprCtx.eNotInTemplateID, null, null); // instead of expression(), to keep the stack smaller + IASTExpression lhs = expression(ExprKind.eExpression, BinaryExprCtx.eInPrimaryExpression, null, null); // instead of expression(), to keep the stack smaller switch (LT(1)) { case IToken.tRPAREN: case IToken.tEOC: @@ -2027,7 +2291,11 @@ protected IASTExpression primaryExpression(CastExprCtx ctx, ITemplateIdStrategy default: throwBacktrack(LA(1)); } - return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset); + if (lhs instanceof ICPPASTFoldExpression) { + return setRange(lhs, t.getOffset(), finalOffset); + } else { + return buildUnaryExpression(IASTUnaryExpression.op_bracketedPrimary, lhs, t.getOffset(), finalOffset); + } case IToken.tIDENTIFIER: case IToken.tCOLONCOLON: case IToken.t_operator: @@ -2087,6 +2355,47 @@ private ICPPASTLiteralExpression stringLiteral() throws EndOfFileException, Back return setRange(r, t.getOffset(), t.getEndOffset()); } + private boolean allowedFoldExpressionOpToken(int opToken) { + switch (opToken) { + case IToken.tPLUS: + case IToken.tMINUS: + case IToken.tSTAR: + case IToken.tDIV: + case IToken.tMOD: + case IToken.tXOR: + case IToken.tAMPER: + case IToken.tBITOR: + case IToken.tASSIGN: + case IToken.tLT: + case IToken.tGT: + case IToken.tSHIFTL: + case IToken.tSHIFTR: + case IToken.tPLUSASSIGN: + case IToken.tMINUSASSIGN: + case IToken.tSTARASSIGN: + case IToken.tDIVASSIGN: + case IToken.tMODASSIGN: + case IToken.tXORASSIGN: + case IToken.tAMPERASSIGN: + case IToken.tBITORASSIGN: + case IToken.tSHIFTLASSIGN: + case IToken.tSHIFTRASSIGN: + case IToken.tEQUAL: + case IToken.tNOTEQUAL: + case IToken.tLTEQUAL: + case IToken.tGTEQUAL: + case IToken.tAND: + case IToken.tOR: + case IToken.tCOMMA: + case IToken.tDOTSTAR: + case IToken.tARROWSTAR: + return true; + + default: + return false; + } + } + private IASTExpression lambdaExpression() throws EndOfFileException, BacktrackException { final int offset = LA().getOffset(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFoldExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFoldExpression.java new file mode 100644 index 00000000000..5eb13634ab4 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFoldExpression.java @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 2022 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.semantics; + +import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE; + +import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; +import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.IValue; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; +import org.eclipse.cdt.core.parser.util.ArrayUtil; +import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; +import org.eclipse.cdt.internal.core.dom.parser.IntegralValue; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; +import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext; +import org.eclipse.core.runtime.CoreException; + +public class EvalFoldExpression extends CPPDependentEvaluation { + private static final EvalFixed EVAL_TRUE = new EvalFixed(CPPBasicType.BOOLEAN, PRVALUE, IntegralValue.create(true)); + private static final EvalFixed EVAL_FALSE = new EvalFixed(CPPBasicType.BOOLEAN, PRVALUE, + IntegralValue.create(false)); + /*private static final EvalFixed EVAL_VOID = new EvalFixed(CPPBasicType.VOID, PRVALUE, + IntegralValue.create(0));*/ + + private final int fOperator; + private final boolean fIsComma; + private final boolean fIsLeftFold; + private ICPPEvaluation[] fPackEvals; + private ICPPEvaluation fInitEval; + + private IType fType; + + private boolean fCheckedIsConstantExpression; + private boolean fIsConstantExpression; + private ICPPEvaluation fEvaluation; + + public EvalFoldExpression(int operator, boolean isComma, boolean isLeftFold, ICPPEvaluation[] packEvals, + ICPPEvaluation initEval, IASTNode pointOfDefinition) { + this(operator, isComma, isLeftFold, packEvals, initEval, findEnclosingTemplate(pointOfDefinition)); + } + + public EvalFoldExpression(int operator, boolean isComma, boolean isLeftFold, ICPPEvaluation[] packEvals, + ICPPEvaluation initEval, IBinding templateDefinition) { + super(templateDefinition); + fOperator = operator; + fIsComma = isComma; + fIsLeftFold = isLeftFold; + fPackEvals = packEvals; + fInitEval = initEval; + } + + public int getOperator() { + return fOperator; + } + + public ICPPEvaluation getInitExpression() { + return fInitEval; + } + + @Override + public boolean isInitializerList() { + return false; + } + + @Override + public boolean isFunctionSet() { + return false; + } + + @Override + public boolean isTypeDependent() { + if (fType != null) { + return fType instanceof TypeOfDependentExpression; + } + return containsDependentType(fPackEvals) || (fInitEval != null && fInitEval.isTypeDependent()); + } + + @Override + public boolean isValueDependent() { + return containsDependentValue(fPackEvals) || (fInitEval != null && fInitEval.isValueDependent()); + } + + @Override + public boolean isConstantExpression() { + if (!fCheckedIsConstantExpression) { + fCheckedIsConstantExpression = true; + fIsConstantExpression = computeIsConstantExpression(); + } + return fIsConstantExpression; + } + + @Override + public boolean isEquivalentTo(ICPPEvaluation other) { + if (!(other instanceof EvalFoldExpression)) { + return false; + } + EvalFoldExpression o = (EvalFoldExpression) other; + return fOperator == o.fOperator && fIsComma == o.fIsComma && fIsLeftFold == o.fIsLeftFold + && fPackEvals == o.fPackEvals + && (fInitEval == null ? o.fInitEval == null : fInitEval.isEquivalentTo(o.fInitEval)); + } + + private boolean computeIsConstantExpression() { + return areAllConstantExpressions(fPackEvals) && (fInitEval == null || fInitEval.isConstantExpression()); + } + + @Override + public IType getType() { + if (fType == null) { + if (isTypeDependent()) { + fType = new TypeOfDependentExpression(this); + } else { + fType = computeEvaluation().getType(); + } + } + return fType; + } + + @Override + public IValue getValue() { + ICPPEvaluation evaluation = computeEvaluation(); + return evaluation.getValue(); + } + + private ICPPEvaluation computeEvaluation() { + if (fEvaluation == null) { + if (fInitEval == null && fPackEvals.length == 0) { + // unary fold with empty pack + if (fIsComma) { + // expression: void(), cannot evaluate + fEvaluation = EvalFixed.INCOMPLETE; + } else if (fOperator == IASTBinaryExpression.op_logicalAnd) { + // expression: true + fEvaluation = EVAL_TRUE; + } else if (fOperator == IASTBinaryExpression.op_logicalOr) { + // expression: false + fEvaluation = EVAL_FALSE; + } else { + // error, cannot evaluate + fEvaluation = EvalFixed.INCOMPLETE; + } + } else { + // For right fold the expanded pack array is already reversed by instantiate() + if (fIsComma) { + int offset = 0; + ICPPEvaluation[] evals; + + if (fInitEval != null) { + evals = new ICPPEvaluation[fPackEvals.length + 1]; + if (fIsLeftFold) { + evals[0] = fInitEval; + offset = 1; + } else { + evals[fPackEvals.length] = fInitEval; + offset = 0; + } + } else { + evals = new ICPPEvaluation[fPackEvals.length]; + offset = 0; + } + + for (ICPPEvaluation packElement : fPackEvals) { + evals[offset++] = packElement; + } + + fEvaluation = new EvalComma(evals, getTemplateDefinition()); + } else { + + ICPPEvaluation folded = fInitEval; + + for (ICPPEvaluation packElement : fPackEvals) { + if (folded == null) { + folded = packElement; + } else { + if (fIsLeftFold) { + folded = new EvalBinary(fOperator, folded, packElement, getTemplateDefinition()); + } else { + folded = new EvalBinary(fOperator, packElement, folded, getTemplateDefinition()); + } + } + } + + fEvaluation = folded; + } + } + } + + return fEvaluation; + } + + @Override + public ValueCategory getValueCategory() { + return ValueCategory.PRVALUE; + } + + @Override + public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { + short firstBytes = ITypeMarshalBuffer.EVAL_FOLD_EXPRESSION; + if (fIsComma) { + firstBytes |= ITypeMarshalBuffer.FLAG1; + } + if (fIsLeftFold) { + firstBytes |= ITypeMarshalBuffer.FLAG2; + } + buffer.putShort((byte) firstBytes); + buffer.putInt(fOperator); + buffer.putInt(fPackEvals.length); + for (ICPPEvaluation arg : fPackEvals) { + buffer.marshalEvaluation(arg, includeValue); + } + buffer.marshalEvaluation(fInitEval, includeValue); + marshalTemplateDefinition(buffer); + } + + public static ICPPEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException { + boolean isComma = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0; + boolean isLeftFold = (firstBytes & ITypeMarshalBuffer.FLAG2) != 0; + int operator = buffer.getInt(); + int len = buffer.getInt(); + ICPPEvaluation[] packEvals = new ICPPEvaluation[len]; + for (int i = 0; i < packEvals.length; i++) { + packEvals[i] = buffer.unmarshalEvaluation(); + } + ICPPEvaluation initEval = buffer.unmarshalEvaluation(); + IBinding templateDefinition = buffer.unmarshalBinding(); + + return new EvalFoldExpression(operator, isComma, isLeftFold, packEvals, initEval, templateDefinition); + } + + @Override + public ICPPEvaluation instantiate(InstantiationContext context, int maxDepth) { + ICPPEvaluation[] packEvals = instantiateExpressions(fPackEvals, context, maxDepth); + ICPPEvaluation initEval = fInitEval == null ? null : fInitEval.instantiate(context, maxDepth); + + if (packEvals == fPackEvals && initEval == fInitEval) { + return this; + } + + if (!fIsLeftFold) { + ArrayUtil.reverse(packEvals); + } + + return new EvalFoldExpression(fOperator, fIsComma, fIsLeftFold, packEvals, initEval, getTemplateDefinition()); + } + + @Override + public ICPPEvaluation computeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) { + if (context.getStepsPerformed() >= ConstexprEvaluationContext.MAX_CONSTEXPR_EVALUATION_STEPS) { + return EvalFixed.INCOMPLETE; + } + + ICPPEvaluation[] packEvals = new ICPPEvaluation[fPackEvals.length]; + + for (int i = 0; i < fPackEvals.length; i++) { + ICPPEvaluation arg = fPackEvals[i].computeForFunctionCall(record, context.recordStep()); + packEvals[i] = arg; + } + + ICPPEvaluation initEval = fInitEval == null ? null + : fInitEval.computeForFunctionCall(record, context.recordStep()); + + if (packEvals == fPackEvals && initEval == fInitEval) { + return this; + } + + return new EvalFoldExpression(fOperator, fIsComma, fIsLeftFold, packEvals, initEval, getTemplateDefinition()); + } + + @Override + public int determinePackSize(ICPPTemplateParameterMap tpMap) { + int r = CPPTemplates.PACK_SIZE_NOT_FOUND; + for (ICPPEvaluation packElement : fPackEvals) { + r = CPPTemplates.combinePackSize(r, packElement.determinePackSize(tpMap)); + } + return r; + } + + @Override + public boolean referencesTemplateParameter() { + for (ICPPEvaluation arg : fPackEvals) { + if (arg.referencesTemplateParameter()) { + return true; + } + } + return fInitEval != null && fInitEval.referencesTemplateParameter(); + } + + @Override + public boolean isNoexcept() { + for (int i = 0; i < fPackEvals.length; i++) { + ICPPEvaluation eval = fPackEvals[i]; + if (!eval.isNoexcept()) { + return false; + } + } + + if (fInitEval != null) { + return fInitEval.isNoexcept(); + } + + return true; + } +} 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 991f3ef73eb..91e1d03d4af 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 @@ -130,6 +130,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConditional; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalConstructor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFoldExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionCall; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFunctionSet; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalID; @@ -1726,6 +1727,8 @@ public ICPPEvaluation unmarshalEvaluation(ITypeMarshalBuffer buffer) throws Core return EvalCompositeAccess.unmarshal(firstBytes, buffer); case ITypeMarshalBuffer.EVAL_NARY_TYPE_ID: return EvalNaryTypeId.unmarshal(firstBytes, buffer); + case ITypeMarshalBuffer.EVAL_FOLD_EXPRESSION: + return EvalFoldExpression.unmarshal(firstBytes, buffer); } throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal an evaluation, first bytes=" + firstBytes)); //$NON-NLS-1$ }