[clang] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions (PR #78112)
Mariya Podchishchaeva via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 15 06:02:02 PST 2024
================
@@ -433,61 +433,86 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
// -- from an integer type or unscoped enumeration type to an integer type
// that cannot represent all the values of the original type, except where
- // the source is a constant expression and the actual value after
+ // -- the source is a bit-field whose width w is less than that of its type
+ // (or, for an enumeration type, its underlying type) and the target type
+ // can represent all the values of a hypothetical extended integer type
+ // with width w and with the same signedness as the original type or
+ // -- the source is a constant expression and the actual value after
// conversion will fit into the target type and will produce the original
// value when converted back to the original type.
case ICK_Integral_Conversion:
IntegralConversion: {
assert(FromType->isIntegralOrUnscopedEnumerationType());
assert(ToType->isIntegralOrUnscopedEnumerationType());
const bool FromSigned = FromType->isSignedIntegerOrEnumerationType();
- const unsigned FromWidth = Ctx.getIntWidth(FromType);
+ unsigned FromWidth = Ctx.getIntWidth(FromType);
const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
const unsigned ToWidth = Ctx.getIntWidth(ToType);
- if (FromWidth > ToWidth ||
- (FromWidth == ToWidth && FromSigned != ToSigned) ||
- (FromSigned && !ToSigned)) {
- // Not all values of FromType can be represented in ToType.
- const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
+ constexpr auto CanRepresentAll = [](bool FromSigned, unsigned FromWidth,
+ bool ToSigned, unsigned ToWidth) {
+ return (FromWidth < ToWidth + (FromSigned == ToSigned)) &&
+ (FromSigned <= ToSigned);
+ };
- // If it's value-dependent, we can't tell whether it's narrowing.
- if (Initializer->isValueDependent())
- return NK_Dependent_Narrowing;
+ if (CanRepresentAll(FromSigned, FromWidth, ToSigned, ToWidth))
+ return NK_Not_Narrowing;
- std::optional<llvm::APSInt> OptInitializerValue;
- if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
- // Such conversions on variables are always narrowing.
- return NK_Variable_Narrowing;
- }
- llvm::APSInt &InitializerValue = *OptInitializerValue;
- bool Narrowing = false;
- if (FromWidth < ToWidth) {
- // Negative -> unsigned is narrowing. Otherwise, more bits is never
- // narrowing.
- if (InitializerValue.isSigned() && InitializerValue.isNegative())
- Narrowing = true;
- } else {
- // Add a bit to the InitializerValue so we don't have to worry about
- // signed vs. unsigned comparisons.
- InitializerValue = InitializerValue.extend(
- InitializerValue.getBitWidth() + 1);
- // Convert the initializer to and from the target width and signed-ness.
- llvm::APSInt ConvertedValue = InitializerValue;
- ConvertedValue = ConvertedValue.trunc(ToWidth);
- ConvertedValue.setIsSigned(ToSigned);
- ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
- ConvertedValue.setIsSigned(InitializerValue.isSigned());
- // If the result is different, this was a narrowing conversion.
- if (ConvertedValue != InitializerValue)
- Narrowing = true;
- }
- if (Narrowing) {
- ConstantType = Initializer->getType();
- ConstantValue = APValue(InitializerValue);
- return NK_Constant_Narrowing;
+ // Not all values of FromType can be represented in ToType.
+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
+
+ bool DependentBitField = false;
+ if (auto *BF = Initializer->getSourceBitField()) {
+ auto *Width = BF->getBitWidth();
----------------
Fznamznon wrote:
Could you please spell out the type? It is unclear without looking into the documentation which type `BF` and `Width` have.
https://github.com/llvm/llvm-project/pull/78112
More information about the cfe-commits
mailing list