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

Apply truncation and sign-extension to result of initializer evaluation

This commit is contained in:
Igor V. Kovalenko 2023-02-12 12:05:49 +03:00 committed by Jonah Graham
parent 8dd97763a3
commit beb201e082
3 changed files with 138 additions and 55 deletions

View file

@ -12793,6 +12793,66 @@ public class AST2CPPTests extends AST2CPPTestBase {
helper.assertVariableValue("waldo", 0);
}
// constexpr int int_from_positive_long = (1L << 32) + 1;
// constexpr short short_from_positive_long = (1L << 32) + 1;
// constexpr unsigned int uint_from_positive_long = (1L << 32) + 1;
// constexpr unsigned short ushort_from_positive_long = (1L << 32) + 1;
//
// constexpr int int_from_negative_long = -((1L << 32) + 1);
// constexpr short short_from_negative_long = -((1L << 32) + 1);
// constexpr unsigned int uint_from_negative_long = -((1L << 32) + 1);
// constexpr unsigned short ushort_from_negative_long = -((1L << 32) + 1);
public void testIntegerImplicitConversions() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("int_from_positive_long", 1);
helper.assertVariableValue("short_from_positive_long", 1);
helper.assertVariableValue("uint_from_positive_long", 1);
helper.assertVariableValue("ushort_from_positive_long", 1);
helper.assertVariableValue("int_from_negative_long", -1);
helper.assertVariableValue("short_from_negative_long", -1);
helper.assertVariableValue("uint_from_negative_long", (1L << 32) - 1);
helper.assertVariableValue("ushort_from_negative_long", (1L << 16) - 1);
}
// constexpr bool bool_from_int_positive = 2;
// constexpr bool bool_from_int_negative = -2;
// constexpr bool bool_from_int_0 = 0;
// constexpr bool bool_from_int_expr = int(0x100000001L) < 2;
// constexpr bool bool_from_short_expr = short(0x100010001L) < 2;
// constexpr int int_from_cast_to_int = (int)((1L << 32) + 1);
public void testIntegerTrunctatingConversions() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("bool_from_int_positive", 1);
helper.assertVariableValue("bool_from_int_negative", 1);
helper.assertVariableValue("bool_from_int_0", 0);
helper.assertVariableValue("bool_from_int_expr", 1);
helper.assertVariableValue("bool_from_short_expr", 1);
helper.assertVariableValue("int_from_cast_to_int", 1);
}
// constexpr unsigned int uint_from_ulong_literal = -1UL;
// constexpr unsigned int uint_from_ulong_negation = -(1UL);
// constexpr unsigned short ushort_from_ulong_literal = -1UL;
// constexpr unsigned short ushort_from_ulong_negation = -(1UL);
//
// constexpr unsigned int uint_from_uint_literal_negation = -(1U);
// constexpr unsigned int uint_from_uint_cast_negation = -(1U);
// constexpr unsigned short ushort_from_ushort_cast_negation = -((unsigned short)1);
public void testUnsignedIntegerUnaryMinus() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableValue("uint_from_ulong_literal", (1L << 32) - 1);
helper.assertVariableValue("uint_from_ulong_negation", (1L << 32) - 1);
helper.assertVariableValue("ushort_from_ulong_literal", (1L << 16) - 1);
helper.assertVariableValue("ushort_from_ulong_negation", (1L << 16) - 1);
helper.assertVariableValue("uint_from_uint_literal_negation", (1L << 32) - 1);
helper.assertVariableValue("uint_from_uint_cast_negation", (1L << 32) - 1);
helper.assertVariableValue("ushort_from_ushort_cast_negation", (1L << 16) - 1);
}
// namespace x {
// void foo();
// }

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2012, 2014 Wind River Systems, Inc. and others.
* Copyright (c) 2012, 2014, 2023 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
@ -11,6 +11,7 @@
* Contributors:
* Markus Schorn - initial API and implementation
* Sergey Prigogin (Google)
* Igor V. Kovalenko
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
@ -41,8 +42,6 @@ import org.eclipse.cdt.internal.core.dom.parser.CompositeValue;
import org.eclipse.cdt.internal.core.dom.parser.DependentValue;
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.SizeofCalculator;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
@ -192,25 +191,7 @@ public class EvalTypeId extends CPPDependentEvaluation {
}
if (fArguments.length == 1) {
IValue argVal = fArguments[0].getValue();
if (argVal instanceof IntegralValue && argVal.numberValue() != null) {
// Cast signed integer to unsigned.
Long val = argVal.numberValue().longValue();
if (val < 0 && inputType instanceof ICPPBasicType && ((ICPPBasicType) inputType).isUnsigned()) {
SizeAndAlignment sizeAndAlignment = SizeofCalculator.getSizeAndAlignment(inputType);
if (sizeAndAlignment != null) {
long sizeof = sizeAndAlignment.size;
if (sizeof > 4) {
// Java's "long" can't represent the full range of an 64-bit unsigned integer
// in C++.
sizeof = 4;
}
long range = (1L << (sizeof * 8 - 1));
val += range;
return IntegralValue.create(val);
}
}
}
return argVal;
return SemanticUtil.applyIntegerConversion(argVal, inputType);
}
return IntegralValue.UNKNOWN;
}
@ -253,6 +234,11 @@ public class EvalTypeId extends CPPDependentEvaluation {
if (getConstructor() == null && fArguments.length == 1) {
// maybe EvalTypeID represents a conversion
ICPPEvaluation conversionEval = maybeApplyConversion(fArguments[0], fInputType, false, false);
if (isEquivalentTo(conversionEval)) {
// still the same conversion, no need to recurse into isConstantExpression()
conversionEval = fArguments[0];
}
if (!conversionEval.isConstantExpression())
return false;
}
@ -504,6 +490,10 @@ public class EvalTypeId extends CPPDependentEvaluation {
} else if (fArguments.length == 1) {
// maybe EvalTypeID represents a conversion
ICPPEvaluation conversionEval = maybeApplyConversion(fArguments[0], fInputType, false, false);
if (isEquivalentTo(conversionEval)) {
// still the same conversion, no need to recurse into isConstantExpression()
conversionEval = fArguments[0];
}
return conversionEval.isNoexcept();
}
for (ICPPEvaluation arg : fArguments) {

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2015 IBM Corporation and others.
* Copyright (c) 2004, 2015, 2023 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -15,6 +15,7 @@
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
* Nathan Ridge
* Igor V. Kovalenko
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
@ -78,6 +79,8 @@ import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment;
import org.eclipse.cdt.internal.core.dom.parser.ValueFactory;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType;
@ -860,45 +863,75 @@ public class SemanticUtil {
* @param type the type of the variable
*/
public static IValue getValueOfInitializer(IASTInitializer init, IType type) {
IASTInitializerClause clause = null;
// applyIntegerConversion() uses SizeofCalculator, make sure AST is available via lookup point
CPPSemantics.pushLookupPoint(init);
try {
if (init instanceof IASTEqualsInitializer) {
clause = ((IASTEqualsInitializer) init).getInitializerClause();
} else if (init instanceof ICPPASTConstructorInitializer) {
IASTInitializerClause[] args = ((ICPPASTConstructorInitializer) init).getArguments();
if (args.length == 1 && args[0] instanceof IASTExpression) {
IType typeUpToPointers = SemanticUtil.getUltimateTypeUptoPointers(type);
if (typeUpToPointers instanceof IPointerType || typeUpToPointers instanceof IBasicType) {
clause = args[0];
}
}
} else if (init instanceof ICPPASTInitializerList) {
ICPPASTInitializerList list = (ICPPASTInitializerList) init;
switch (list.getSize()) {
case 0:
return IntegralValue.create(0);
case 1:
clause = list.getClauses()[0];
break;
default:
return ((ICPPASTInitializerList) init).getEvaluation().getValue();
}
}
if (clause instanceof IASTExpression) {
return ValueFactory.create((IASTExpression) clause);
}
if (clause instanceof ICPPASTInitializerList) {
return ((ICPPASTInitializerList) clause).getEvaluation().getValue();
}
return IntegralValue.UNKNOWN;
return SemanticUtil.applyIntegerConversion(getValueOfInitializerImpl(init, type), type);
} finally {
CPPSemantics.popLookupPoint();
}
}
private static IValue getValueOfInitializerImpl(IASTInitializer init, IType type) {
IASTInitializerClause clause = null;
if (init instanceof IASTEqualsInitializer) {
clause = ((IASTEqualsInitializer) init).getInitializerClause();
} else if (init instanceof ICPPASTConstructorInitializer) {
IASTInitializerClause[] args = ((ICPPASTConstructorInitializer) init).getArguments();
if (args.length == 1 && args[0] instanceof IASTExpression) {
IType typeUpToPointers = SemanticUtil.getUltimateTypeUptoPointers(type);
if (typeUpToPointers instanceof IPointerType || typeUpToPointers instanceof IBasicType) {
clause = args[0];
}
}
} else if (init instanceof ICPPASTInitializerList) {
ICPPASTInitializerList list = (ICPPASTInitializerList) init;
switch (list.getSize()) {
case 0:
return IntegralValue.create(0);
case 1:
clause = list.getClauses()[0];
break;
default:
return ((ICPPASTInitializerList) init).getEvaluation().getValue();
}
}
if (clause instanceof IASTExpression) {
return ValueFactory.create((IASTExpression) clause);
}
if (clause instanceof ICPPASTInitializerList) {
return ((ICPPASTInitializerList) clause).getEvaluation().getValue();
}
return IntegralValue.UNKNOWN;
}
public static IValue applyIntegerConversion(IValue value, IType targetType) {
if (value instanceof IntegralValue && value.numberValue() != null
&& SemanticUtil.getUltimateTypeUptoPointers(targetType) instanceof IBasicType basicType) {
if (basicType.getKind() == Kind.eBoolean) {
return IntegralValue.create(value.numberValue().longValue() == 0 ? 0 : 1);
}
// Cast to different size and signedness
SizeAndAlignment sizeAndAlignment = SizeofCalculator.getSizeAndAlignment(basicType);
if (sizeAndAlignment != null && sizeAndAlignment.size < 8) {
long val = value.numberValue().longValue();
boolean doSignExtend = val < 0 && !basicType.isUnsigned();
long mask = (1L << (sizeAndAlignment.size * 8)) - 1;
// truncate
val &= mask;
if (doSignExtend) {
//sign-extend
val |= ~mask;
}
return IntegralValue.create(val);
}
}
return value;
}
/**
* Returns whether a type is const or a reference to a const type.
*