1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 17:35:35 +02:00

Fix assertion evaluating binary shifts of comparison op results

Currently CDT evaluates result type of comparison ops to the converted type of
their operands. When floating point values are compared and then the result is
binary shifted this trips an assertion trying to promote floating point value.

Fix this by limiting operand types of binary shifts to integral or unscoped
enumerations. Additionally fix return type of comparison op to be boolean value.
This commit is contained in:
Igor V. Kovalenko 2023-03-11 22:43:47 +03:00 committed by Jonah Graham
parent c69eed48e3
commit f1c15e3a3d
3 changed files with 61 additions and 15 deletions

View file

@ -96,6 +96,7 @@ import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
@ -147,6 +148,7 @@ import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.AttributeUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance;
@ -13845,4 +13847,29 @@ public class AST2CPPTests extends AST2CPPTestBase {
helper.assertVariableValue("test_32", 1);
helper.assertVariableValue("test_64", 1);
}
// constexpr auto shiftdouble = (1. << 1);
public void testArithmeticEvaluationWithDoubleShiftOp() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
IVariable shiftdouble = helper.assertNonProblem("shiftdouble = ", 11);
IValue value = shiftdouble.getInitialValue();
assertTrue(IntegralValue.ERROR.equals(value) || IntegralValue.UNKNOWN.equals(value));
}
// constexpr auto shiftdouble = (1. <<= 1);
public void testArithmeticEvaluationWithDoubleShiftAssignOp() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
IVariable shiftdouble = helper.assertNonProblem("shiftdouble = ", 11);
IValue value = shiftdouble.getInitialValue();
assertTrue(IntegralValue.ERROR.equals(value) || IntegralValue.UNKNOWN.equals(value));
}
// enum Shift { Horizontal, Vertical };
// constexpr double zero = 0.;
// constexpr double x = 1., y = 1.;
// constexpr int shiftpack = ((x > zero) << Horizontal) | ((y > zero) << Vertical);
public void testArithmeticEvaluationOfRelationalOps() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("shiftpack", 3);
}
}

View file

@ -87,7 +87,12 @@ public abstract class ArithmeticConversion {
return convert(op1, op2);
case IASTBinaryExpression.op_shiftLeft:
case IASTBinaryExpression.op_shiftLeftAssign:
case IASTBinaryExpression.op_shiftRight:
case IASTBinaryExpression.op_shiftRightAssign:
if (!isIntegralOrUnscopedEnum(op1) || !isIntegralOrUnscopedEnum(op2)) {
return null;
}
return promote(op1, getDomain(op1));
default:

View file

@ -101,6 +101,7 @@ public class EvalBinary extends CPPDependentEvaluation {
private ICPPFunction fOverload = CPPFunction.UNINITIALIZED_FUNCTION;
private ICPPEvaluation fOverloadCall;
private IType fType;
private IType fCommonType;
private boolean fCheckedIsConstantExpression;
private boolean fIsConstantExpression;
@ -160,6 +161,13 @@ public class EvalBinary extends CPPDependentEvaluation {
return fType;
}
private IType getCommonType() {
if (fCommonType == null) {
fCommonType = computeCommonType();
}
return fCommonType;
}
private ICPPEvaluation createOperatorOverloadEvaluation(ICPPFunction overload, ICPPEvaluation arg1,
ICPPEvaluation arg2) {
EvalFunctionCall operatorCall;
@ -240,7 +248,7 @@ public class EvalBinary extends CPPDependentEvaluation {
Number num2 = v2.numberValue();
if (num2 != null) {
return ValueFactory.evaluateBinaryExpression(fOperator, v1, v2, getType());
return ValueFactory.evaluateBinaryExpression(fOperator, v1, v2, getCommonType());
}
}
return DependentValue.create(this);
@ -352,6 +360,26 @@ public class EvalBinary extends CPPDependentEvaluation {
if (o != null)
return typeFromFunctionCall(o);
switch (fOperator) {
case op_lessEqual:
case op_lessThan:
case op_greaterEqual:
case op_greaterThan:
case op_logicalAnd:
case op_logicalOr:
case op_equals:
case op_notequals:
return CPPBasicType.BOOLEAN;
case op_threewaycomparison:
// TODO: implement for <=>
return ProblemType.UNKNOWN_FOR_EXPRESSION;
}
return getCommonType();
}
private IType computeCommonType() {
final IType originalType1 = fArg1.getType();
final IType type1 = prvalueTypeWithResolvedTypedefs(originalType1);
if (type1 instanceof ISemanticProblem) {
@ -379,20 +407,6 @@ public class EvalBinary extends CPPDependentEvaluation {
}
return ProblemType.UNKNOWN_FOR_EXPRESSION;
case op_lessEqual:
case op_lessThan:
case op_greaterEqual:
case op_greaterThan:
case op_logicalAnd:
case op_logicalOr:
case op_equals:
case op_notequals:
return CPPBasicType.BOOLEAN;
case op_threewaycomparison:
// TODO: implement for <=>
return ProblemType.UNKNOWN_FOR_EXPRESSION;
case op_plus:
if (type1 instanceof IPointerType) {
return ExpressionTypes.restoreTypedefs(type1, originalType1);