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

Bug 522216, 527427: [C++17] Support for constexpr if and init-statements

Change-Id: Ia8195c66334edb107848901619e85fbfb5c78b18
Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch>
This commit is contained in:
Hansruedi Patzen 2017-11-17 21:52:02 +01:00 committed by Nathan Ridge
parent cb5c699871
commit a51f7c0659
17 changed files with 688 additions and 63 deletions

View file

@ -10651,4 +10651,148 @@ public class AST2TemplateTests extends AST2CPPTestBase {
public void testLongDependentFunctionCallChain_530692() throws Exception {
parseAndCheckBindings();
}
// // A metafunction that loops infinitely on odd inputs.
// template <int N>
// struct meta {
// static constexpr int value = 1 + meta<N - 2>::value;
// };
// template <>
// struct meta<0> {
// static constexpr int value = 0;
// };
//
// // A constexpr function that calls 'meta' on an odd input
// // but only in the uninstantiated branch of a constexpr if.
// template <int N>
// constexpr int foo() {
// if constexpr (N % 2 != 0) {
// return meta<N - 1>::value;
// } else {
// return meta<N>::value;
// }
// }
//
// // Call the function
// constexpr int waldo = foo<7>();
public void testConditionalInstantiationOfConstexprIfTrueBranch_527427() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("waldo", 3);
}
// // A metafunction that loops infinitely on odd inputs.
// template <int N>
// struct meta {
// static constexpr int value = 1 + meta<N - 2>::value;
// };
// template <>
// struct meta<0> {
// static constexpr int value = 0;
// };
//
// // A constexpr function that calls 'meta' on an odd input
// // but only in the uninstantiated branch of a constexpr if.
// template <int N>
// constexpr int foo() {
// if constexpr (N % 2 == 0) {
// return meta<N>::value;
// } else {
// return meta<N - 1>::value;
// }
// }
//
// // Call the function
// constexpr int waldo = foo<7>();
public void testConditionalInstantiationOfConstexprIfFalseBranch_527427() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("waldo", 3);
}
// template <int N>
// constexpr int fib() {
// if constexpr (N == 0) {
// return 0;
// } else if constexpr (N == 1) {
// return 1;
// } else {
// return fib<N - 1>() + fib<N - 2>();
// }
// }
//
// // Call the function
// constexpr int waldo = fib<7>();
public void testConstexprFibonacciConstexprIf_527427() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("waldo", 13);
}
// constexpr int g(int x) {
// return x * 2;
// }
//
// template <int N>
// constexpr int foo() {
// if constexpr (constexpr auto x = g(N)) {
// return 14 / x;
// } else {
// return 0;
// }
// }
//
// // Call the function
// constexpr int waldo = foo<2>();
public void testConstexprIfDeclarationTrueBranch_527427() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("waldo", 3);
}
// constexpr int g(int x) {
// return x * 2;
// }
//
// template <int N>
// constexpr int foo() {
// if constexpr (constexpr auto x = g(N)) {
// return 14 / x;
// } else {
// return 42;
// }
// }
//
// // Call the function
// constexpr int waldo = foo<0>();
public void testConstexprIfDeclarationFalseBranch_527427() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("waldo", 42);
}
// constexpr auto foo() {
// if constexpr (false) {
// return "Error";
// } else {
// return 42;
// }
// }
//
// // Call the function
// constexpr auto waldo = foo();
public void testReturnAutoConstexprIfDeclarationFalseBranchValueExpression_527427() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("waldo", 42);
}
// constexpr auto foo() {
// if constexpr (true) {
// return 42;
// } else {
// return "Error";
// }
// }
//
// // Call the function
// constexpr auto waldo = foo();
public void testReturnAutoConstexprIfDeclarationTrueBranchValueExpression_527427() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("waldo", 42);
}
}

View file

@ -703,6 +703,56 @@ public class DOMLocationTests extends AST2TestBase {
assertSoleLocation(declarator, code.indexOf(rawDeclarator), rawDeclarator.length());
}
public void testIfInitStatement_1() throws Exception {
String code = "void foo() { if (int i = 1; i == 1) {} }"; //$NON-NLS-1$
IASTTranslationUnit tu = parse(code, ParserLanguage.CPP);
ICPPASTFunctionDefinition definition = (ICPPASTFunctionDefinition) tu.getDeclarations()[0];
IASTCompoundStatement body = (IASTCompoundStatement) definition.getBody();
IASTIfStatement statement = (IASTIfStatement) body.getStatements()[0];
String rawDeclarator = "if (int i = 1; i == 1) {}"; //$NON-NLS-1$
assertSoleLocation(statement, code.indexOf(rawDeclarator), rawDeclarator.length());
}
public void testIfInitStatement_2() throws Exception {
String code = "void foo() { if (; bool b = true) {} }"; //$NON-NLS-1$
IASTTranslationUnit tu = parse(code, ParserLanguage.CPP);
ICPPASTFunctionDefinition definition = (ICPPASTFunctionDefinition) tu.getDeclarations()[0];
IASTCompoundStatement body = (IASTCompoundStatement) definition.getBody();
IASTIfStatement statement = (IASTIfStatement) body.getStatements()[0];
String rawDeclarator = "if (; bool b = true) {}"; //$NON-NLS-1$
assertSoleLocation(statement, code.indexOf(rawDeclarator), rawDeclarator.length());
}
public void testConstexprIf_1() throws Exception {
String code = "void foo() { if constexpr (true) {} }"; //$NON-NLS-1$
IASTTranslationUnit tu = parse(code, ParserLanguage.CPP);
ICPPASTFunctionDefinition definition = (ICPPASTFunctionDefinition) tu.getDeclarations()[0];
IASTCompoundStatement body = (IASTCompoundStatement) definition.getBody();
IASTIfStatement statement = (IASTIfStatement) body.getStatements()[0];
String rawDeclarator = "if constexpr (true) {}"; //$NON-NLS-1$
assertSoleLocation(statement, code.indexOf(rawDeclarator), rawDeclarator.length());
}
public void testConstexprIf_2() throws Exception {
String code = "void foo() { if constexpr (constexpr int i = 1; i == 1) {} }"; //$NON-NLS-1$
IASTTranslationUnit tu = parse(code, ParserLanguage.CPP);
ICPPASTFunctionDefinition definition = (ICPPASTFunctionDefinition) tu.getDeclarations()[0];
IASTCompoundStatement body = (IASTCompoundStatement) definition.getBody();
IASTIfStatement statement = (IASTIfStatement) body.getStatements()[0];
String rawDeclarator = "if constexpr (constexpr int i = 1; i == 1) {}"; //$NON-NLS-1$
assertSoleLocation(statement, code.indexOf(rawDeclarator), rawDeclarator.length());
}
public void testConstexprIf_3() throws Exception {
String code = "void foo() { if constexpr (; constexpr bool b = true) {} }"; //$NON-NLS-1$
IASTTranslationUnit tu = parse(code, ParserLanguage.CPP);
ICPPASTFunctionDefinition definition = (ICPPASTFunctionDefinition) tu.getDeclarations()[0];
IASTCompoundStatement body = (IASTCompoundStatement) definition.getBody();
IASTIfStatement statement = (IASTIfStatement) body.getStatements()[0];
String rawDeclarator = "if constexpr (; constexpr bool b = true) {}"; //$NON-NLS-1$
assertSoleLocation(statement, code.indexOf(rawDeclarator), rawDeclarator.length());
}
// int main(void){
// #define one 1
// int integer = one;

View file

@ -194,4 +194,69 @@ public class IfStatementTests extends TestBase {
public void testDeclarationInIfStatementCondition3() throws Exception {
assertEvaluationEquals(7);
}
// constexpr int g(int x) {
// return x * 2;
// }
// constexpr int f(int y) {
// if(int x = g(y); x == 2) {
// return 14 / x;
// } else {
// return 0;
// }
// }
// constexpr int x = f(1);
public void testInitStatementInIfStatementCondition1() throws Exception {
assertEvaluationEquals(7);
}
// constexpr int g(int x) {
// return x * 2;
// }
// constexpr int f(int y) {
// if(int x = g(y); x != 2) {
// return 14 / x;
// } else {
// return 0;
// }
// }
// constexpr int x = f(1);
public void testInitStatementInIfStatementCondition2() throws Exception {
assertEvaluationEquals(0);
}
// constexpr int g(int x) {
// return x * 2;
// }
// constexpr int f() {
// if constexpr (constexpr int x = g(1); x != 2) {
// return 14 / x;
// } else {
// return 0;
// }
// }
// constexpr int x = f();
public void testInitStatementInIfStatementCondition3() throws Exception {
assertEvaluationEquals(0);
}
// constexpr int g(int x) {
// return x * 2;
// }
// constexpr int f(int y) {
// int x = g(y);
// if(; x == 2) {
// return 14 / x;
// } else {
// return 0;
// }
// }
// constexpr int x = f(1);
public void testEmptyInitStatementInIfStatementCondition1() throws Exception {
assertEvaluationEquals(7);
}
}

View file

@ -146,7 +146,7 @@ int f()
}
//!IfStatementTest
//!BasicNoBraceIfStatementTest
//%CPP
int g()
{
@ -210,7 +210,7 @@ int foo()
}
//!SwitchStatementTest
//!CSwitchStatementTest
//%C
void foo()
{
@ -240,7 +240,7 @@ int foo(int a)
}
//!GNUSwitchStatementTest
//!GNUCSwitchStatementTest
//%C
int foo(int a)
{
@ -323,8 +323,81 @@ int foo()
}
}
//!ArrayDeclarationStatementTest
//%CPP
string* newElements = new string[m_capacity];
//!Basic Constexpr If
//%CPP
void f()
{
constexpr bool b{false};
if constexpr (b){
}
}
//!Constexpr If with init-statement
//%CPP
void f()
{
if constexpr (constexpr bool b{false};b){
}
}
//!Constexpr If with init-statement and declaration
//%CPP
void f()
{
if constexpr (constexpr bool b{false};int k = 42){
}
}
//!If with init-statement
//%CPP
void f()
{
if (bool b{false};b == true){
}
}
//!If with init-statement and declaration
//%CPP
void f()
{
if (bool b{false};int k = 42){
}
}
//!If with constexpr init-statement and declaration
//%CPP
void f()
{
if (constexpr bool b{false};int k = 42){
}
}
//!If with empty init-statement and declaration
//%CPP
void f()
{
if (;int k = 42){
}
}
//!If with empty init-statement and expression
//%CPP
void f()
{
int k{42};
if (;k == 42){
}
}
//!Constexpr If with empty init-statement and expression
//%CPP
void f()
{
constexpr int k{42};
if constexpr (;k == 42){
}
}

View file

@ -10,8 +10,10 @@
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IScope;
/**
@ -21,6 +23,15 @@ import org.eclipse.cdt.core.dom.ast.IScope;
* @noimplement This interface is not intended to be implemented by clients.
*/
public interface ICPPASTIfStatement extends IASTIfStatement {
/**
* {@code INIT_STATEMENT} represents the relationship between an
* {@code ICPPASTIfStatement} and its nested {@code IASTStatement}.
*
* @since 6.5
*/
public static final ASTNodeProperty INIT_STATEMENT = new ASTNodeProperty(
"ICPPASTIfStatement.INIT_STATEMENT - IASTStatement init-statement for ICPPASTIfStatement"); //$NON-NLS-1$
/**
* Returns the condition declaration. The condition declaration and the condition expression are
* mutually exclusive.
@ -34,7 +45,43 @@ public interface ICPPASTIfStatement extends IASTIfStatement {
* Sets the condition declaration.
*/
public void setConditionDeclaration(IASTDeclaration d);
/**
* Sets the isConstxpr member variable.
*
* @since 6.5
*/
public void setIsConstexpr(boolean isConstexpr);
/**
* Checks whether this if statement is a constexpr if statement.
*
* @return true iff this if statement is a constexpr if.
*
* @since 6.5
*/
public boolean isConstexpr();
/**
* Returns the init-statement for an if.
*
* @return the init-statement, or <code>null</code> if the 'if' statement doesn't
* have one.
*
* @since 6.5
*/
public IASTStatement getInitializerStatement();
/**
* Sets the optional init-statement of an if.
*
* @param statement this statement should either be a <code>IASTSimpleDeclaration</code> or a
* <code>IASTExpressionStatement</code>.
*
* @since 6.5
*/
public void setInitializerStatement(IASTStatement statement);
/**
* Returns the implicit <code>IScope</code> represented by this if statement
*

View file

@ -2379,13 +2379,13 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
protected abstract IASTAmbiguousExpression createAmbiguousBinaryVsCastExpression(IASTBinaryExpression binary, IASTCastExpression castExpr);
protected abstract IASTAmbiguousExpression createAmbiguousCastVsFunctionCallExpression(IASTCastExpression castExpr, IASTFunctionCallExpression funcCall);
protected IASTStatement forInitStatement() throws BacktrackException, EndOfFileException {
protected IASTStatement initStatement() throws BacktrackException, EndOfFileException {
if (LT(1) == IToken.tSEMI)
return parseNullStatement();
try {
return parseDeclarationOrExpressionStatement();
} catch (BacktrackException e) {
// Missing semicolon within for loop does not make a complete for-statement
// A init statement always terminates with a semicolon
IASTNode before = e.getNodeBeforeProblem();
if (before != null) {
e.initialize(e.getProblem());

View file

@ -2144,7 +2144,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
int startOffset;
startOffset = consume().getOffset();
consume(IToken.tLPAREN);
IASTStatement init = forInitStatement();
IASTStatement init = initStatement();
IASTExpression for_condition = null;
switch (LT(1)) {
case IToken.tSEMI:

View file

@ -29,6 +29,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecSimpleDeclarat
* If statement in C++
*/
public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIfStatement, ICPPExecutionOwner {
private boolean isConstexpr;
private IASTStatement initStatement;
private IASTExpression condition;
private IASTStatement thenClause;
private IASTStatement elseClause;
@ -44,7 +46,7 @@ public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIf
setElseClause(elseClause);
}
public CPPASTIfStatement(IASTExpression condition, IASTStatement thenClause, IASTStatement elseClause) {
public CPPASTIfStatement(IASTExpression condition, IASTStatement thenClause, IASTStatement elseClause) {
setConditionExpression(condition);
setThenClause(thenClause);
setElseClause(elseClause);
@ -58,6 +60,8 @@ public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIf
@Override
public CPPASTIfStatement copy(CopyStyle style) {
CPPASTIfStatement copy = new CPPASTIfStatement();
copy.setIsConstexpr(isConstexpr);
copy.setInitializerStatement(initStatement == null ? null : initStatement.copy(style));
copy.setConditionDeclaration(condDecl == null ? null : condDecl.copy(style));
copy.setConditionExpression(condition == null ? null : condition.copy(style));
copy.setThenClause(thenClause == null ? null : thenClause.copy(style));
@ -137,7 +141,10 @@ public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIf
if (!((CPPASTIfStatement) stmt).acceptByAttributeSpecifiers(action)) return false;
IASTNode child = stmt.getConditionExpression();
IASTNode child = stmt.getInitializerStatement();
if (child != null && !child.accept(action))
return false;
child = stmt.getConditionExpression();
if (child != null && !child.accept(action))
return false;
child= stmt.getConditionDeclaration();
@ -175,17 +182,28 @@ public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIf
@Override
public void replace(IASTNode child, IASTNode other) {
if (initStatement == child) {
other.setParent(child.getParent());
other.setPropertyInParent(child.getPropertyInParent());
initStatement = (IASTStatement) other;
return;
}
if (thenClause == child) {
other.setParent(child.getParent());
other.setPropertyInParent(child.getPropertyInParent());
thenClause = (IASTStatement) other;
return;
} else if (elseClause == child) {
}
if (elseClause == child) {
other.setParent(child.getParent());
other.setPropertyInParent(child.getPropertyInParent());
elseClause = (IASTStatement) other;
return;
} else if (condition == child || condDecl == child) {
}
if (condition == child || condDecl == child) {
if (other instanceof IASTExpression) {
setConditionExpression((IASTExpression) other);
} else if (other instanceof IASTDeclaration) {
@ -193,6 +211,7 @@ public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIf
}
return;
}
super.replace(child, other);
}
@ -212,6 +231,33 @@ public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIf
}
}
@Override
public boolean isConstexpr() {
return isConstexpr;
}
@Override
public void setIsConstexpr(boolean isConstexpr) {
assertNotFrozen();
this.isConstexpr = isConstexpr;
}
@Override
public IASTStatement getInitializerStatement() {
return initStatement;
}
@Override
public void setInitializerStatement(IASTStatement statement) {
assertNotFrozen();
this.initStatement = statement;
if (statement != null) {
statement.setParent(this);
statement.setPropertyInParent(INIT_STATEMENT);
statement = null;
}
}
@Override
public IScope getScope() {
if (scope == null)
@ -221,12 +267,13 @@ public class CPPASTIfStatement extends CPPASTAttributeOwner implements ICPPASTIf
@Override
public ICPPExecution getExecution() {
ICPPExecution initStmtExec = EvalUtil.getExecutionFromStatement(getInitializerStatement());
ICPPASTExpression conditionExpr = (ICPPASTExpression) getConditionExpression();
ICPPExecutionOwner conditionDecl = (ICPPExecutionOwner) getConditionDeclaration();
ICPPEvaluation conditionExprEval = conditionExpr != null ? conditionExpr.getEvaluation() : null;
ExecSimpleDeclaration conditionDeclExec = conditionDecl != null ? (ExecSimpleDeclaration) conditionDecl.getExecution() : null;
ICPPExecution thenClauseExec = EvalUtil.getExecutionFromStatement(getThenClause());
ICPPExecution elseClauseExec = getElseClause() != null ? EvalUtil.getExecutionFromStatement(getElseClause()) : null;
return new ExecIf(conditionExprEval, conditionDeclExec, thenClauseExec, elseClauseExec);
ICPPExecution elseClauseExec = EvalUtil.getExecutionFromStatement(getElseClause());
return new ExecIf(isConstexpr, initStmtExec, conditionExprEval, conditionDeclExec, thenClauseExec, elseClauseExec);
}
}

View file

@ -5270,26 +5270,38 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
int start = LA(1).getOffset();
if_loop: while (true) {
int so = consume(IToken.t_if).getOffset();
ICPPASTIfStatement new_if_statement = getNodeFactory().newIfStatement();
// constexpr if
if (LT(1) == IToken.t_constexpr) {
consume();
new_if_statement.setIsConstexpr(true);
}
consume(IToken.tLPAREN);
// init-statement
IToken mark= mark();
try {
IASTStatement statement = initStatement();
new_if_statement.setInitializerStatement(statement);
} catch (BacktrackException e) {
backup(mark);
}
// condition
IASTNode condition= cppStyleCondition(IToken.tRPAREN);
if (LT(1) == IToken.tEOC) {
// Completing in the condition
ICPPASTIfStatement new_if = getNodeFactory().newIfStatement();
if (condition instanceof IASTExpression)
new_if.setConditionExpression((IASTExpression) condition);
new_if_statement.setConditionExpression((IASTExpression) condition);
else if (condition instanceof IASTDeclaration)
new_if.setConditionDeclaration((IASTDeclaration) condition);
new_if_statement.setConditionDeclaration((IASTDeclaration) condition);
if (if_statement != null) {
if_statement.setElseClause(new_if);
if_statement.setElseClause(new_if_statement);
}
return result != null ? result : new_if;
return result != null ? result : new_if_statement;
}
consume(IToken.tRPAREN);
IASTStatement thenClause = statement();
ICPPASTIfStatement new_if_statement = getNodeFactory().newIfStatement();
((ASTNode) new_if_statement).setOffset(so);
if (condition != null && (condition instanceof IASTExpression || condition instanceof IASTDeclaration))
// shouldn't be possible but failure in condition() makes it so
@ -5447,7 +5459,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
}
private IASTForStatement startTraditionalForLoop() throws BacktrackException, EndOfFileException {
final IASTStatement initStmt = forInitStatement();
final IASTStatement initStmt = initStatement();
IASTNode condition= null;
IASTExpression iterExpr= null;

View file

@ -1624,7 +1624,14 @@ public class CPPSemantics {
} else if (parent instanceof ICPPASTSwitchStatement) {
nodes = new IASTNode[] { ((ICPPASTSwitchStatement) parent).getControllerDeclaration() };
} else if (parent instanceof ICPPASTIfStatement) {
nodes = new IASTNode[] { ((ICPPASTIfStatement) parent).getConditionDeclaration() };
ICPPASTIfStatement ifStatement = (ICPPASTIfStatement) parent;
final IASTStatement initStatement = ifStatement.getInitializerStatement();
final IASTDeclaration conditionDeclaration = ifStatement.getConditionDeclaration();
if (initStatement != null) {
nodes = new IASTNode[] {initStatement, conditionDeclaration};
} else {
nodes = new IASTNode[] {conditionDeclaration};
}
} else if (parent instanceof ICPPASTWhileStatement) {
nodes = new IASTNode[] { ((ICPPASTWhileStatement) parent).getConditionDeclaration() };
} else if (parent instanceof ICPPASTRangeBasedForStatement) {

View file

@ -16,28 +16,41 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext;
import org.eclipse.core.runtime.CoreException;
public class ExecIf implements ICPPExecution {
private final boolean isConstexpr;
private final ICPPExecution initStmtExec;
private final ICPPEvaluation conditionExprEval;
private final ExecSimpleDeclaration conditionDeclExec;
private final ICPPExecution thenClauseExec;
private final ICPPExecution elseClauseExec;
public ExecIf(ICPPEvaluation conditionExprEval, ExecSimpleDeclaration conditionDeclExec, ICPPExecution thenClauseExec, ICPPExecution elseClauseExec) {
public ExecIf(boolean isConstexpr, ICPPExecution initStmtExec, ICPPEvaluation conditionExprEval, ExecSimpleDeclaration conditionDeclExec, ICPPExecution thenClauseExec, ICPPExecution elseClauseExec) {
this.isConstexpr = isConstexpr;
this.initStmtExec = initStmtExec;
this.conditionExprEval = conditionExprEval;
this.conditionDeclExec = conditionDeclExec;
this.thenClauseExec = thenClauseExec;
this.elseClauseExec = elseClauseExec;
}
private void executeInitStatement(ActivationRecord record, ConstexprEvaluationContext context) {
if (initStmtExec != null) {
EvalUtil.executeStatement(initStmtExec, record, context);
}
}
private boolean conditionSatisfied(ActivationRecord record, ConstexprEvaluationContext context) {
if (conditionExprEval != null) {
return EvalUtil.conditionExprSatisfied(conditionExprEval, record, context);
} else if (conditionDeclExec != null) {
return EvalUtil.conditionDeclSatisfied(conditionDeclExec, record, context);
}
return false;
}
@Override
public ICPPExecution executeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) {
boolean conditionSatisfied = false;
if (conditionExprEval != null) {
conditionSatisfied = EvalUtil.conditionExprSatisfied(conditionExprEval, record, context);
} else if (conditionDeclExec != null) {
conditionSatisfied = EvalUtil.conditionDeclSatisfied(conditionDeclExec, record, context);
}
if (conditionSatisfied) {
executeInitStatement(record, context);
if (conditionSatisfied(record, context)) {
return EvalUtil.executeStatement(thenClauseExec, record, context);
} else if (elseClauseExec != null) {
return EvalUtil.executeStatement(elseClauseExec, record, context);
@ -47,19 +60,44 @@ public class ExecIf implements ICPPExecution {
@Override
public ICPPExecution instantiate(InstantiationContext context, int maxDepth) {
ICPPExecution newInitStmtExec = initStmtExec != null ? initStmtExec.instantiate(context, maxDepth) : null;
ICPPEvaluation newConditionExprEval = conditionExprEval != null ? conditionExprEval.instantiate(context, maxDepth) : null;
ExecSimpleDeclaration newConditionDeclExec = conditionDeclExec != null ? (ExecSimpleDeclaration) conditionDeclExec.instantiate(context, maxDepth) : null;
ICPPExecution newThenClauseExec = thenClauseExec.instantiate(context, maxDepth);
ICPPExecution newElseClauseExec = elseClauseExec != null ? elseClauseExec.instantiate(context, maxDepth) : null;
if (newConditionExprEval == conditionExprEval && newConditionDeclExec == conditionDeclExec && newThenClauseExec == thenClauseExec && newElseClauseExec == elseClauseExec) {
ICPPExecution newThenClauseExec = null;
ICPPExecution newElseClauseExec = null;
if (isConstexpr && newConditionExprEval != null && newConditionExprEval.getValue().numberValue() != null) {
if (newConditionExprEval.getValue().numberValue().intValue() != 0) {
/*
* We can't just "return newThenClauseExec" here, because the condition
* might have side effects so it needs to be preserved in the instantiated
* execution even if one of its branch has become null
*/
newThenClauseExec = thenClauseExec.instantiate(context, maxDepth);
} else {
newElseClauseExec = elseClauseExec != null ? elseClauseExec.instantiate(context, maxDepth) : null;
}
} else {
newThenClauseExec = thenClauseExec.instantiate(context, maxDepth);
newElseClauseExec = elseClauseExec != null ? elseClauseExec.instantiate(context, maxDepth) : null;
}
if (newInitStmtExec == initStmtExec && newConditionExprEval == conditionExprEval && newConditionDeclExec == conditionDeclExec
&& newThenClauseExec == thenClauseExec && newElseClauseExec == elseClauseExec) {
return this;
}
return new ExecIf(newConditionExprEval, newConditionDeclExec, newThenClauseExec, newElseClauseExec);
return new ExecIf(isConstexpr, newInitStmtExec, newConditionExprEval, newConditionDeclExec, newThenClauseExec, newElseClauseExec);
}
@Override
public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException {
buffer.putShort(ITypeMarshalBuffer.EXEC_IF);
short firstBytes = ITypeMarshalBuffer.EXEC_IF;
if (isConstexpr) {
firstBytes |= ITypeMarshalBuffer.FLAG1;
}
buffer.putShort(firstBytes);
buffer.marshalExecution(initStmtExec, includeValue);
buffer.marshalEvaluation(conditionExprEval, includeValue);
buffer.marshalExecution(conditionDeclExec, includeValue);
buffer.marshalExecution(thenClauseExec, includeValue);
@ -67,10 +105,12 @@ public class ExecIf implements ICPPExecution {
}
public static ICPPExecution unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
boolean isConstexpr = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0;
ICPPExecution initStmtExec = buffer.unmarshalExecution();
ICPPEvaluation conditionExprEval = buffer.unmarshalEvaluation();
ExecSimpleDeclaration conditionDeclExec = (ExecSimpleDeclaration) buffer.unmarshalExecution();
ICPPExecution thenClauseExec = buffer.unmarshalExecution();
ICPPExecution elseClauseExec = buffer.unmarshalExecution();
return new ExecIf(conditionExprEval, conditionDeclExec, thenClauseExec, elseClauseExec);
return new ExecIf(isConstexpr, initStmtExec, conditionExprEval, conditionDeclExec, thenClauseExec, elseClauseExec);
}
}

View file

@ -65,7 +65,8 @@ public class StatementWriter extends NodeWriter {
private static final String CONTINUE = "continue"; //$NON-NLS-1$
private static final String BREAK = "break"; //$NON-NLS-1$
private static final String ELSE = "else"; //$NON-NLS-1$
private static final String IF = "if ("; //$NON-NLS-1$
private static final String IF = "if "; //$NON-NLS-1$
private static final String CONSTEXPR = "constexpr "; //$NON-NLS-1$
private static final String FOR = "for ("; //$NON-NLS-1$
private static final String DO_WHILE = " while ("; //$NON-NLS-1$
private static final String DO = "do"; //$NON-NLS-1$
@ -216,10 +217,18 @@ public class StatementWriter extends NodeWriter {
private void writeIfStatement(IASTIfStatement ifStatement) {
scribe.print(IF);
final boolean isCPPIfStatement = ifStatement instanceof ICPPASTIfStatement;
if (isCPPIfStatement && ((ICPPASTIfStatement) ifStatement).isConstexpr()) {
scribe.print(CONSTEXPR);
}
scribe.print('(');
scribe.noNewLines();
if (ifStatement instanceof ICPPASTIfStatement) {
if (isCPPIfStatement) {
ICPPASTIfStatement cppIfStatment = (ICPPASTIfStatement) ifStatement;
IASTStatement initStatement = cppIfStatment.getInitializerStatement();
if (initStatement != null) {
writeStatement(initStatement, false);
}
if (cppIfStatment.getConditionDeclaration() == null) {
cppIfStatment.getConditionExpression().accept(visitor);
} else {

View file

@ -289,10 +289,13 @@ public class PDOM extends PlatformObject implements IPDOM {
* 209.0 - Alias templates and their instances take up more space than required, bug 516385.
* 210.0 - Return type deduction, bug 408470.
* 211.0 - Change representation of alias template instances, bug 516338.
*
* CDT 9.5 development (version not supported on the 9.4.x branch)
* 212.0 - C++ constexpr if and if init-statement evaluation
*/
private static final int MIN_SUPPORTED_VERSION= version(211, 0);
private static final int MAX_SUPPORTED_VERSION= version(211, Short.MAX_VALUE);
private static final int DEFAULT_VERSION = version(211, 0);
private static final int MIN_SUPPORTED_VERSION= version(212, 0);
private static final int MAX_SUPPORTED_VERSION= version(212, Short.MAX_VALUE);
private static final int DEFAULT_VERSION = version(212, 0);
private static int version(int major, int minor) {
return (major << 16) + minor;

View file

@ -268,7 +268,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
private class TrailingSemicolonFormatter extends TrailingTokenFormatter {
TrailingSemicolonFormatter(IASTNode node) {
super(Token.tSEMI, getLastNodeCharacterPosition(node),
fInsideFor ? preferences.insert_space_before_semicolon_in_for :
fHasClauseInitStatement ? preferences.insert_space_before_semicolon_in_for :
preferences.insert_space_before_semicolon,
false);
}
@ -396,7 +396,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
final DefaultCodeFormatterOptions preferences;
private final Scribe scribe;
private boolean fInsideFor;
private boolean fHasClauseInitStatement;
private boolean fInsideMacroArguments;
private boolean fExpectSemicolonAfterDeclaration= true;
@ -3134,7 +3134,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
}
private int visit(IASTNullStatement node) {
if (!fInsideFor && nodeOffset(node) == getCurrentPosition()) {
if (!fHasClauseInitStatement && nodeOffset(node) == getCurrentPosition()) {
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
scribe.printTrailingComment();
}
@ -3143,7 +3143,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
private int visit(IASTDeclarationStatement node) {
node.getDeclaration().accept(this);
if (!fInsideFor) {
if (!fHasClauseInitStatement) {
scribe.startNewLine();
}
return PROCESS_SKIP;
@ -3151,7 +3151,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
private int visit(IASTExpressionStatement node) {
Runnable semicolonFormatter = null;
if (!fInsideFor) {
if (!fHasClauseInitStatement) {
semicolonFormatter = new TrailingSemicolonFormatter(node);
scribe.setTailFormatter(semicolonFormatter);
}
@ -3160,7 +3160,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
semicolonFormatter.run();
scribe.setTailFormatter(null);
}
if (!fInsideFor) {
if (!fHasClauseInitStatement) {
scribe.startNewLine();
}
return PROCESS_SKIP;
@ -3176,7 +3176,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
Runnable tailFormatter = null;
if (!doNodesHaveSameOffset(node, initializerStmt)) {
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_for);
fInsideFor= true;
fHasClauseInitStatement = true;
if (preferences.insert_space_after_opening_paren_in_for) {
scribe.space();
}
@ -3240,7 +3240,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
scribe.setTailFormatter(null);
}
} finally {
fInsideFor= false;
fHasClauseInitStatement= false;
}
ok = true;
} catch (AlignmentException e) {
@ -3271,7 +3271,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
scribe.printNextToken(Token.t_for);
final int line = scribe.line;
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_for);
fInsideFor= true;
fHasClauseInitStatement= true;
try {
if (preferences.insert_space_after_opening_paren_in_for) {
scribe.space();
@ -3285,7 +3285,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
}
initializer.accept(this);
} finally {
fInsideFor= false;
fHasClauseInitStatement= false;
}
if (peekNextToken() == Token.tRPAREN) {
scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_for);
@ -3295,24 +3295,46 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
return PROCESS_SKIP;
}
private void beginIfClause() {
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_if);
if (preferences.insert_space_after_opening_paren_in_if) {
scribe.space();
}
}
private int visit(IASTIfStatement node) {
if (!startsWithMacroExpansion(node)) {
scribe.printNextToken(Token.t_if);
}
final int line = scribe.line;
IASTNode condition = node.getConditionExpression();
if (condition == null && node instanceof ICPPASTIfStatement) {
condition = ((ICPPASTIfStatement) node).getConditionDeclaration();
}
final IASTStatement thenStatement = node.getThenClause();
final IASTStatement elseStatement = node.getElseClause();
fExpectSemicolonAfterDeclaration= false;
fExpectSemicolonAfterDeclaration = false;
try {
if (condition == null || !doNodesHaveSameOffset(node, condition)) {
scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_if);
if (preferences.insert_space_after_opening_paren_in_if) {
if (node instanceof ICPPASTIfStatement) {
ICPPASTIfStatement cppIfStatment = (ICPPASTIfStatement) node;
if (cppIfStatment.isConstexpr()) {
scribe.space();
scribe.printNextToken(Token.t_constexpr);
scribe.space();
}
IASTStatement initStatement = cppIfStatment.getInitializerStatement();
if (initStatement != null) {
beginIfClause();
fHasClauseInitStatement = true;
initStatement.accept(this);
if (preferences.insert_space_after_semicolon_in_for) {
scribe.space();
}
}
if (condition == null) {
condition = ((ICPPASTIfStatement) node).getConditionDeclaration();
}
}
if (condition == null || !doNodesHaveSameOffset(node, condition)) {
if (!fHasClauseInitStatement) {
beginIfClause();
}
Runnable tailFormatter = null;
if (DefaultCodeFormatterConstants.END_OF_LINE.equals(preferences.brace_position_for_block) &&
@ -3334,7 +3356,8 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
condition.accept(this);
}
} finally {
fExpectSemicolonAfterDeclaration= true;
fHasClauseInitStatement = false;
fExpectSemicolonAfterDeclaration = true;
}
boolean thenStatementIsBlock = false;
@ -3357,7 +3380,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
scribe.printTrailingComment();
} else {
if (getCurrentPosition() <= nodeOffset(thenStatement)) {
formatLeftCurlyBrace(line, preferences.brace_position_for_block);
formatLeftCurlyBrace(scribe.line, preferences.brace_position_for_block);
}
thenStatement.accept(this);
if (elseStatement != null && preferences.insert_new_line_before_else_in_if_statement) {

View file

@ -888,6 +888,7 @@ public class SimpleScanner {
fgKeywords.put("compl", Integer.valueOf(Token.t_compl)); //$NON-NLS-1$
fgKeywords.put("const", Integer.valueOf(Token.t_const)); //$NON-NLS-1$
fgKeywords.put("const_cast", Integer.valueOf(Token.t_const_cast)); //$NON-NLS-1$
fgKeywords.put("constexpr", Integer.valueOf(Token.t_constexpr)); //$NON-NLS-1$
fgKeywords.put("continue", Integer.valueOf(Token.t_continue)); //$NON-NLS-1$
fgKeywords.put("default", Integer.valueOf(Token.t_default)); //$NON-NLS-1$
fgKeywords.put("delete", Integer.valueOf(Token.t_delete)); //$NON-NLS-1$

View file

@ -505,4 +505,5 @@ public class Token {
static public final int t_byte = 214;
static public final int t_transient = 215;
static public final int t_native = 216;
static public final int t_constexpr = 5400;
}

View file

@ -3209,4 +3209,107 @@ public class CodeFormatterTest extends BaseUITestCase {
public void testSizeofParameterPackFormat_464498() throws Exception {
assertFormatterResult();
}
//void foo() {
// if constexpr (constexpr bool k = true) {
// }
//}
//void foo() {
// if constexpr (constexpr bool k = true) {
// }
//}
public void testConstexprIfFormat_1() throws Exception {
assertFormatterResult();
}
//void foo() {
// if
// constexpr (constexpr bool k = true) {
// }
//}
//void foo() {
// if constexpr (constexpr bool k = true) {
// }
//}
public void testConstexprIfFormat_2() throws Exception {
assertFormatterResult();
}
//void foo() {
// if
//
// constexpr
// (constexpr bool k = true) {
// }
//}
//void foo() {
// if
//
// constexpr (constexpr bool k = true) {
// }
//}
public void testConstexprIfFormat_3() throws Exception {
assertFormatterResult();
}
//void foo() {
// if constexpr (constexpr bool k = true; k) {
// }
//}
//void foo() {
// if constexpr (constexpr bool k = true; k) {
// }
//}
public void testIfInitStatementFormat_1() throws Exception {
assertFormatterResult();
}
//void foo() {
// if
// constexpr (constexpr bool k = true; k) {
// }
//}
//void foo() {
// if constexpr (constexpr bool k = true; k) {
// }
//}
public void testIfInitStatementFormat_2() throws Exception {
assertFormatterResult();
}
//void foo() {
// if
//
// constexpr
// (constexpr bool k = true; k) {
// }
//}
//void foo() {
// if
//
// constexpr (constexpr bool k = true; k) {
// }
//}
public void testIfInitStatementFormat_3() throws Exception {
assertFormatterResult();
}
//void foo() {
// if (constexpr bool k = true;k) {
// }
//}
//void foo() {
// if (constexpr bool k = true; k) {
// }
//}
public void testIfInitStatementFormat_4() throws Exception {
assertFormatterResult();
}
}