@@ -331,11 +331,14 @@ static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
331331/// value of the expression prior to the narrowing conversion.
332332/// \param ConstantType If this is an NK_Constant_Narrowing conversion, the
333333/// type of the expression prior to the narrowing conversion.
334+ /// \param BitFieldWidth If this is an NK_BitField_Not_Narrowing conversion,
335+ /// the width of the source bit-field.
334336/// \param IgnoreFloatToIntegralConversion If true type-narrowing conversions
335337/// from floating point types to integral types should be ignored.
336338NarrowingKind StandardConversionSequence::getNarrowingKind(
337339 ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue,
338- QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const {
340+ QualType &ConstantType, unsigned &BitFieldWidth,
341+ bool IgnoreFloatToIntegralConversion) const {
339342 assert((Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) &&
340343 "narrowing check outside C++");
341344
@@ -463,7 +466,12 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
463466
464467 // -- from an integer type or unscoped enumeration type to an integer type
465468 // that cannot represent all the values of the original type, except where
466- // the source is a constant expression and the actual value after
469+ // (C++23) -- the source is a bit-field whose width w is less than that of
470+ // its type (or, for an enumeration type, its underlying type) and the
471+ // target type can represent all the values of a hypothetical extended
472+ // integer type with width w and with the same signedness as the original
473+ // type or
474+ // -- the source is a constant expression and the actual value after
467475 // conversion will fit into the target type and will produce the original
468476 // value when converted back to the original type.
469477 case ICK_Integral_Conversion:
@@ -475,49 +483,70 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
475483 const bool ToSigned = ToType->isSignedIntegerOrEnumerationType();
476484 const unsigned ToWidth = Ctx.getIntWidth(ToType);
477485
478- if (FromWidth > ToWidth ||
479- (FromWidth == ToWidth && FromSigned != ToSigned) ||
480- (FromSigned && !ToSigned)) {
481- // Not all values of FromType can be represented in ToType.
482- const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
483-
484- // If it's value-dependent, we can't tell whether it's narrowing.
485- if (Initializer->isValueDependent())
486- return NK_Dependent_Narrowing;
486+ constexpr auto CanRepresentAll = [](bool FromSigned, unsigned FromWidth,
487+ bool ToSigned, unsigned ToWidth) {
488+ return (FromWidth < ToWidth + (FromSigned == ToSigned)) &&
489+ (FromSigned <= ToSigned);
490+ };
487491
488- std::optional<llvm::APSInt> OptInitializerValue;
489- if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
490- // Such conversions on variables are always narrowing.
491- return NK_Variable_Narrowing;
492- }
493- llvm::APSInt &InitializerValue = *OptInitializerValue;
494- bool Narrowing = false;
495- if (FromWidth < ToWidth) {
496- // Negative -> unsigned is narrowing. Otherwise, more bits is never
497- // narrowing.
498- if (InitializerValue.isSigned() && InitializerValue.isNegative())
499- Narrowing = true;
500- } else {
501- // Add a bit to the InitializerValue so we don't have to worry about
502- // signed vs. unsigned comparisons.
503- InitializerValue = InitializerValue.extend(
504- InitializerValue.getBitWidth() + 1);
505- // Convert the initializer to and from the target width and signed-ness.
506- llvm::APSInt ConvertedValue = InitializerValue;
507- ConvertedValue = ConvertedValue.trunc(ToWidth);
508- ConvertedValue.setIsSigned(ToSigned);
509- ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
510- ConvertedValue.setIsSigned(InitializerValue.isSigned());
511- // If the result is different, this was a narrowing conversion.
512- if (ConvertedValue != InitializerValue)
513- Narrowing = true;
514- }
515- if (Narrowing) {
516- ConstantType = Initializer->getType();
517- ConstantValue = APValue(InitializerValue);
518- return NK_Constant_Narrowing;
492+ if (CanRepresentAll(FromSigned, FromWidth, ToSigned, ToWidth))
493+ return NK_Not_Narrowing;
494+
495+ // Not all values of FromType can be represented in ToType.
496+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
497+
498+ // If it's value-dependent, we can't tell whether it's narrowing.
499+ if (Initializer->isValueDependent())
500+ return NK_Dependent_Narrowing;
501+
502+ std::optional<llvm::APSInt> OptInitializerValue;
503+ if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
504+ // Check for bit-field whose width means that this would not be narrowing
505+ // (This check is after checking for constant expressions because
506+ // a constant expression that fits is never narrowing but a non-constant
507+ // expression that comes from a bit-field is only not narrowing before
508+ // C++23 as an extension)
509+ if (const FieldDecl *BitField = Initializer->getSourceBitField()) {
510+ if (BitField->getBitWidth()->isValueDependent()) {
511+ return NK_Dependent_Narrowing;
512+ }
513+ BitFieldWidth = BitField->getBitWidthValue(Ctx);
514+ if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) {
515+ return NK_BitField_Not_Narrowing;
516+ }
519517 }
518+
519+ // Otherwise, such a conversion is always narrowing
520+ return NK_Variable_Narrowing;
521+ }
522+ llvm::APSInt &InitializerValue = *OptInitializerValue;
523+ bool Narrowing = false;
524+ if (FromWidth < ToWidth) {
525+ // Negative -> unsigned is narrowing. Otherwise, more bits is never
526+ // narrowing.
527+ if (InitializerValue.isSigned() && InitializerValue.isNegative())
528+ Narrowing = true;
529+ } else {
530+ // Add a bit to the InitializerValue so we don't have to worry about
531+ // signed vs. unsigned comparisons.
532+ InitializerValue =
533+ InitializerValue.extend(InitializerValue.getBitWidth() + 1);
534+ // Convert the initializer to and from the target width and signed-ness.
535+ llvm::APSInt ConvertedValue = InitializerValue;
536+ ConvertedValue = ConvertedValue.trunc(ToWidth);
537+ ConvertedValue.setIsSigned(ToSigned);
538+ ConvertedValue = ConvertedValue.extend(InitializerValue.getBitWidth());
539+ ConvertedValue.setIsSigned(InitializerValue.isSigned());
540+ // If the result is different, this was a narrowing conversion.
541+ if (ConvertedValue != InitializerValue)
542+ Narrowing = true;
543+ }
544+ if (Narrowing) {
545+ ConstantType = Initializer->getType();
546+ ConstantValue = APValue(InitializerValue);
547+ return NK_Constant_Narrowing;
520548 }
549+
521550 return NK_Not_Narrowing;
522551 }
523552 case ICK_Complex_Real:
@@ -6232,14 +6261,18 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
62326261 // Check for a narrowing implicit conversion.
62336262 bool ReturnPreNarrowingValue = false;
62346263 QualType PreNarrowingType;
6264+ unsigned BitFieldWidth;
62356265 switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
6236- PreNarrowingType)) {
6266+ PreNarrowingType, BitFieldWidth )) {
62376267 case NK_Dependent_Narrowing:
62386268 // Implicit conversion to a narrower type, but the expression is
62396269 // value-dependent so we can't tell whether it's actually narrowing.
62406270 case NK_Variable_Narrowing:
62416271 // Implicit conversion to a narrower type, and the value is not a constant
62426272 // expression. We'll diagnose this in a moment.
6273+ case NK_BitField_Not_Narrowing:
6274+ // Implicit conversion where the source is a bit-field and not a constant
6275+ // expression.
62436276 case NK_Not_Narrowing:
62446277 break;
62456278
0 commit comments