diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index e60b1e376a9..b22af681248 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -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(); // } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java index 291a175a599..09ad6fdf5a8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java @@ -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) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java index ebf6c6d1b86..43701973383 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java @@ -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. *