https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/78112
>From 92f8720e3d21521b589d5291f086a2f32b87bfe0 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sun, 14 Jan 2024 19:52:31 +0000 Subject: [PATCH 01/14] [clang] [SemaCXX] Implement CWG2627 Bit-fields and narrowing conversions --- clang/docs/ReleaseNotes.rst | 5 + .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/include/clang/Sema/Overload.h | 7 +- clang/lib/Sema/SemaExpr.cpp | 10 +- clang/lib/Sema/SemaInit.cpp | 20 ++- clang/lib/Sema/SemaOverload.cpp | 119 +++++++++------ .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp | 24 ++++ clang/test/CXX/drs/dr26xx.cpp | 136 ++++++++++++++++++ clang/www/cxx_dr_status.html | 2 +- 9 files changed, 278 insertions(+), 48 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 92563262cc6737..28202fc604e298 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -157,6 +157,11 @@ Resolutions to C++ Defect Reports - Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers. (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers <https://cplusplus.github.io/CWG/issues/2858.html>`_). +- Casts from a bit-field to an integral type is now not considered narrowing if the + width of the bit-field means that all potential values are in the range + of the target type, even if the type of the bit-field is larger. + (`CWG2627. Bit-fields and narrowing conversions <https://cplusplus.github.io/CWG/issues/2627.html>`_). + C Language Changes ------------------ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fdca82934cb4dc..6cdb439be30ae5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6253,6 +6253,9 @@ def ext_init_list_variable_narrowing_const_reference : ExtWarn< def ext_init_list_constant_narrowing : ExtWarn< "constant expression evaluates to %0 which cannot be narrowed to type %1">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; +def ext_bit_field_narrowing : Extension< + "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a C++23 extension">, + InGroup<CXX20CompatPedantic>, SFINAEFailure; def ext_init_list_constant_narrowing_const_reference : ExtWarn< ext_init_list_constant_narrowing.Summary>, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure; diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 76311b00d2fc58..0d94045cc13f79 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -244,7 +244,11 @@ class Sema; /// Not a narrowing conversion. NK_Not_Narrowing, - /// A narrowing conversion by virtue of the source and destination types. + /// Not a narrowing conversion in C++23 because the source is a bit-field + /// whose range can fit in the target type + NK_BitField_Not_Narrowing, + + /// A narrowing conversion by virtue of the source and target types. NK_Type_Narrowing, /// A narrowing conversion, because a constant expression got narrowed. @@ -387,6 +391,7 @@ class Sema; NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted, APValue &ConstantValue, QualType &ConstantType, + unsigned &BitFieldWidth, bool IgnoreFloatToIntegralConversion = false) const; bool isPointerConversionToBool() const; bool isPointerConversionToVoidPointer(ASTContext& Context) const; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 50f92c496a539a..4c16fcc60fc771 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12361,8 +12361,9 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E, APValue PreNarrowingValue; QualType PreNarrowingType; + unsigned BitFieldWidth; switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue, - PreNarrowingType, + PreNarrowingType, BitFieldWidth, /*IgnoreFloatToIntegralConversion*/ true)) { case NK_Dependent_Narrowing: // Implicit conversion to a narrower type, but the expression is @@ -12370,6 +12371,13 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E, case NK_Not_Narrowing: return false; + case NK_BitField_Not_Narrowing: + if (!S.getLangOpts().CPlusPlus23) { + return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing) + << FromType << ToType << BitFieldWidth; + } + return false; + case NK_Constant_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 003a157990d307..778fe53967bc54 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10509,13 +10509,27 @@ static void DiagnoseNarrowingInInitList(Sema &S, // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion. APValue ConstantValue; QualType ConstantType; + unsigned BitFieldWidth; switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue, - ConstantType)) { + ConstantType, BitFieldWidth)) { case NK_Not_Narrowing: case NK_Dependent_Narrowing: // No narrowing occurred. return; + case NK_BitField_Not_Narrowing: + // A bit-field was "narrowed" to an integer type which is wider than the + // bit-field but the declared type of the bit-field is wider than the target + // type. This is not considered narrowing in C++23. + if (S.getLangOpts().CPlusPlus23) + return; + if (!(S.Diag(PostInit->getBeginLoc(), diag::ext_bit_field_narrowing) + << PreNarrowingType + << EntityType.getNonReferenceType().getLocalUnqualifiedType() + << BitFieldWidth)) + return; + break; + case NK_Type_Narrowing: { // This was a floating-to-integer conversion, which is always considered a // narrowing conversion even if the value is a constant and can be @@ -10592,9 +10606,10 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType, APValue Value; QualType PreNarrowingType; + unsigned BitFieldWidth; // Reuse C++ narrowing check. switch (ICS.Standard.getNarrowingKind( - S.Context, Init, Value, PreNarrowingType, + S.Context, Init, Value, PreNarrowingType, BitFieldWidth, /*IgnoreFloatToIntegralConversion*/ false)) { // The value doesn't fit. case NK_Constant_Narrowing: @@ -10610,6 +10625,7 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType, // Since we only reuse narrowing check for C23 constexpr variables here, we're // not really interested in these cases. + case NK_BitField_Not_Narrowing: case NK_Dependent_Narrowing: case NK_Variable_Narrowing: case NK_Not_Narrowing: diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 04cd9e78739d20..8bf42a4b1dfa4b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -331,11 +331,14 @@ static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx, /// value of the expression prior to the narrowing conversion. /// \param ConstantType If this is an NK_Constant_Narrowing conversion, the /// type of the expression prior to the narrowing conversion. +/// \param BitFieldWidth If this is an NK_BitField_Not_Narrowing conversion, +/// the width of the source bit-field. /// \param IgnoreFloatToIntegralConversion If true type-narrowing conversions /// from floating point types to integral types should be ignored. NarrowingKind StandardConversionSequence::getNarrowingKind( ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue, - QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const { + QualType &ConstantType, unsigned &BitFieldWidth, + bool IgnoreFloatToIntegralConversion) const { assert((Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) && "narrowing check outside C++"); @@ -463,7 +466,12 @@ 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 + // (C++23) -- 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: @@ -475,49 +483,70 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( 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); - - // If it's value-dependent, we can't tell whether it's narrowing. - if (Initializer->isValueDependent()) - return NK_Dependent_Narrowing; + constexpr auto CanRepresentAll = [](bool FromSigned, unsigned FromWidth, + bool ToSigned, unsigned ToWidth) { + return (FromWidth < ToWidth + (FromSigned == ToSigned)) && + (FromSigned <= ToSigned); + }; - 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; + if (CanRepresentAll(FromSigned, FromWidth, ToSigned, ToWidth)) + return NK_Not_Narrowing; + + // Not all values of FromType can be represented in ToType. + const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); + + // If it's value-dependent, we can't tell whether it's narrowing. + if (Initializer->isValueDependent()) + return NK_Dependent_Narrowing; + + std::optional<llvm::APSInt> OptInitializerValue; + if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) { + // Check for bit-field whose width means that this would not be narrowing + // (This check is after checking for constant expressions because + // a constant expression that fits is never narrowing but a non-constant + // expression that comes from a bit-field is only not narrowing before + // C++23 as an extension) + if (const FieldDecl *BitField = Initializer->getSourceBitField()) { + if (BitField->getBitWidth()->isValueDependent()) { + return NK_Dependent_Narrowing; + } + BitFieldWidth = BitField->getBitWidthValue(Ctx); + if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) { + return NK_BitField_Not_Narrowing; + } } + + // Otherwise, such a conversion is 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; } + return NK_Not_Narrowing; } case ICK_Complex_Real: @@ -6232,14 +6261,18 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, // Check for a narrowing implicit conversion. bool ReturnPreNarrowingValue = false; QualType PreNarrowingType; + unsigned BitFieldWidth; switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, - PreNarrowingType)) { + PreNarrowingType, BitFieldWidth)) { case NK_Dependent_Narrowing: // Implicit conversion to a narrower type, but the expression is // value-dependent so we can't tell whether it's actually narrowing. case NK_Variable_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. We'll diagnose this in a moment. + case NK_BitField_Not_Narrowing: + // Implicit conversion where the source is a bit-field and not a constant + // expression. case NK_Not_Narrowing: break; diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp index 2bceb3e267790d..a3049dc57d9fac 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp @@ -203,6 +203,30 @@ void shrink_int() { unsigned short usc1 = { c }; // expected-error {{non-constant-expression cannot be narrowed from type 'signed char'}} expected-note {{silence}} unsigned short usc2 = { (signed char)'x' }; // OK unsigned short usc3 = { (signed char)-1 }; // expected-error {{ -1 which cannot be narrowed}} expected-note {{silence}} + +#if __BITINT_MAXWIDTH__ >= 3 + _BitInt(2) S2 = 0; + unsigned _BitInt(2) U2 = 0; + _BitInt(3) S3 = 0; + unsigned _BitInt(3) U3 = 0; + + _BitInt(2) bi0 = { S2 }; + _BitInt(2) bi1 = { U2 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(2)'}} + _BitInt(2) bi2 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}} + _BitInt(2) bi3 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}} + unsigned _BitInt(2) bi4 = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}} + unsigned _BitInt(2) bi5 = { U2 }; + unsigned _BitInt(2) bi6 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}} + unsigned _BitInt(2) bi7 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}} + _BitInt(3) bi8 = { S2 }; + _BitInt(3) bi9 = { U2 }; + _BitInt(3) bia = { S3 }; + _BitInt(3) bib = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}} + unsigned _BitInt(3) bic = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}} + unsigned _BitInt(3) bid = { U2 }; + unsigned _BitInt(3) bie = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}} + unsigned _BitInt(3) bif = { U3 }; +#endif } // Be sure that type- and value-dependent expressions in templates get the error diff --git a/clang/test/CXX/drs/dr26xx.cpp b/clang/test/CXX/drs/dr26xx.cpp index f7a05b9827a235..3834325d69c4b5 100644 --- a/clang/test/CXX/drs/dr26xx.cpp +++ b/clang/test/CXX/drs/dr26xx.cpp @@ -1,11 +1,37 @@ // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11 +// RUN: %clang_cc1 -std=c++11 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11 +// RUN: %clang_cc1 -std=c++14 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11 +// RUN: %clang_cc1 -std=c++17 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20 +// RUN: %clang_cc1 -std=c++20 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +// RUN: %clang_cc1 -std=c++23 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +// RUN: %clang_cc1 -std=c++2c -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +namespace std { +#if __cplusplus >= 202002L + struct strong_ordering { + int n; + constexpr operator int() const { return n; } + static const strong_ordering less, equal, greater; + }; + constexpr strong_ordering strong_ordering::less{-1}, + strong_ordering::equal{0}, strong_ordering::greater{1}; +#endif + + typedef __INT16_TYPE__ int16_t; + typedef __UINT16_TYPE__ uint16_t; + typedef __INT32_TYPE__ int32_t; + typedef __UINT32_TYPE__ uint32_t; + typedef __INT64_TYPE__ int64_t; + typedef __UINT64_TYPE__ uint64_t; + + template<typename T> T declval(); +} namespace cwg2621 { // cwg2621: 16 #if __cplusplus >= 202002L @@ -24,6 +50,116 @@ using enum E; #endif } +namespace cwg2627 { // cwg2627: 19 +#if __cplusplus >= 202002L +struct C { + long long i : 8; + friend auto operator<=>(C, C) = default; // #cwg2627-3way-def +}; + +void f() { + C x{1}, y{2}; + static_cast<void>(x <=> y); +// until-cxx23-pedantic-warning@#cwg2627-3way-def 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}} +// until-cxx23-pedantic-note@-2 {{in defaulted three-way comparison operator for 'C' first required here}} + static_cast<void>(x.i <=> y.i); +// until-cxx23-pedantic-warning@-1 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}} +} + +template<typename T> +struct CDependent { + T i : 8; + friend auto operator<=>(CDependent, CDependent) = default; +}; + +template<typename T> +concept three_way_comparable = requires(T t) { { t <=> t }; }; +template<typename T> +concept bf_three_way_comparable = requires(T t) { { t.i <=> t.i }; }; +static_assert(three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L)); +static_assert(bf_three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L)); +#endif + +#if __cplusplus >= 201103L +template<int W> +struct D { + __int128 i : W; +}; + +template<int W> +std::int64_t f(D<W> d) { + return std::int64_t{ d.i }; // #cwg2627-f +} + +template std::int64_t f(D<63>); +// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 63 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}} +// until-cxx23-pedantic-note@-2 {{in instantiation of function template specialization 'cwg2627::f<63>' requested here}} +// until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}} +template std::int64_t f(D<64>); +// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 64 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}} +// until-cxx23-pedantic-note@-2 {{in instantiation of function template specialization 'cwg2627::f<64>' requested here}} +// until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}} +template std::int64_t f(D<65>); +// since-cxx11-error-re@#cwg2627-f {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}} +// since-cxx11-note@-2 {{in instantiation of function template specialization 'cwg2627::f<65>' requested here}} +// since-cxx11-note@#cwg2627-f {{insert an explicit cast to silence this issue}} + +template<typename Target, typename Source> +Target g(Source x) { + return Target{ x.i }; // #cwg2627-g +} + +template<typename T, int N> +struct E { + T i : N; +}; + +template std::int16_t g(E<int, 16>); +// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'int' bit-field of width 16 to '{{.+}}' is a C++23 extension}} +// until-cxx23-pedantic-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 16>>' requested here}} +// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} +template std::int16_t g(E<unsigned, 15>); +// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 15 to '{{.+}}' is a C++23 extension}} +// until-cxx23-pedantic-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 15>>' requested here}} +// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} +template std::int16_t g(E<unsigned, 16>); +// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'unsigned int' to '{{.+}}' in initializer list}} +// since-cxx11-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}} +// since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} +template std::uint16_t g(E<unsigned, 16>); +// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 16 to '{{.+}}' is a C++23 extension}} +// until-cxx23-pedantic-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}} +// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} +template std::uint16_t g(E<int, 1>); +// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to '{{.+}}' in initializer list}} +// since-cxx11-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 1>>' requested here}} +// since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} + +template bool g(E<unsigned, 1>); +// until-cxx23-pedantic-warning@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 1 to 'bool' is a C++23 extension}} +// until-cxx23-pedantic-note@-2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<unsigned int, 1>>' requested here}} +// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} +template bool g(E<int, 1>); +// since-cxx11-error@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}} +// since-cxx11-note@-2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<int, 1>>' requested here}} +// since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} + +template<typename Target, typename Source> +constexpr decltype(Target{ std::declval<Source>().i }, false) is_narrowing(int) { return false; } +template<typename Target, typename Source> +constexpr bool is_narrowing(long) { return true; } + +constexpr bool is_cxx23 = __cplusplus >= 202302L; +static_assert(is_narrowing<std::int16_t, E<int, 16>>(0) == !is_cxx23, ""); +static_assert(is_narrowing<std::int16_t, E<unsigned, 15>>(0) == !is_cxx23, ""); +static_assert(is_narrowing<std::int16_t, E<unsigned, 16>>(0), ""); +static_assert(is_narrowing<std::uint16_t, E<unsigned, 16>>(0) == !is_cxx23, ""); +static_assert(is_narrowing<std::uint16_t, E<int, 1>>(0), ""); +static_assert(is_narrowing<bool, E<unsigned, 1>>(0) == !is_cxx23, ""); +static_assert(is_narrowing<bool, E<int, 1>>(0), ""); +#endif +} + namespace cwg2628 { // cwg2628: no // this was reverted for the 16.x release // due to regressions, see the issue for more details: diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index ea8872c91be604..d1f28bad642796 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -15570,7 +15570,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/2627.html">2627</a></td> <td>C++23</td> <td>Bit-fields and narrowing conversions</td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 19</td> </tr> <tr id="2628"> <td><a href="https://cplusplus.github.io/CWG/issues/2628.html">2628</a></td> >From 21ef4781616b8cc2d26db0d60c17c1835effd179 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Wed, 22 May 2024 19:31:00 +0100 Subject: [PATCH 02/14] [NFC] style changes --- clang/lib/Sema/SemaOverload.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 49ccbeb60b32c1..258bb43ccf3bf9 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -500,19 +500,23 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (Initializer->isValueDependent()) return NK_Dependent_Narrowing; - std::optional<llvm::APSInt> OptInitializerValue; - if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) { + std::optional<llvm::APSInt> OptInitializerValue = + Initializer->getIntegerConstantExpr(Ctx); + if (!OptInitializerValue) { // Check for bit-field whose width means that this would not be narrowing // (This check is after checking for constant expressions because // a constant expression that fits is never narrowing but a non-constant // expression that comes from a bit-field is only not narrowing before // C++23 as an extension) if (const FieldDecl *BitField = Initializer->getSourceBitField()) { - if (BitField->getBitWidth()->isValueDependent()) { + if (BitField->getBitWidth()->isValueDependent()) return NK_Dependent_Narrowing; - } + BitFieldWidth = BitField->getBitWidthValue(Ctx); if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) { + assert(BitFieldWidth < FromWidth && + "Oversized bit-field can represent all but smaller field type " + "couldn't?"); return NK_BitField_Not_Narrowing; } } >From 2f5ae05a55f5ff582846d45485388b105dc6f9ef Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 24 May 2024 09:22:05 +0100 Subject: [PATCH 03/14] Remove pedantic warning since this is a DR --- .../clang/Basic/DiagnosticSemaKinds.td | 3 - clang/include/clang/Sema/Overload.h | 7 +-- clang/lib/Sema/SemaExpr.cpp | 10 +--- clang/lib/Sema/SemaInit.cpp | 20 +------ clang/lib/Sema/SemaOverload.cpp | 57 +++++++++---------- clang/test/CXX/drs/cwg26xx.cpp | 51 ++++++----------- 6 files changed, 48 insertions(+), 100 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 2d6522cb483b9d..5a32463763aa67 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6279,9 +6279,6 @@ def ext_init_list_variable_narrowing_const_reference : ExtWarn< def ext_init_list_constant_narrowing : ExtWarn< "constant expression evaluates to %0 which cannot be narrowed to type %1">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; -def ext_bit_field_narrowing : Extension< - "narrowing non-constant-expression from %0 bit-field of width %2 to %1 is a C++23 extension">, - InGroup<CXX20CompatPedantic>, SFINAEFailure; def ext_init_list_constant_narrowing_const_reference : ExtWarn< ext_init_list_constant_narrowing.Summary>, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure; diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 0d94045cc13f79..76311b00d2fc58 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -244,11 +244,7 @@ class Sema; /// Not a narrowing conversion. NK_Not_Narrowing, - /// Not a narrowing conversion in C++23 because the source is a bit-field - /// whose range can fit in the target type - NK_BitField_Not_Narrowing, - - /// A narrowing conversion by virtue of the source and target types. + /// A narrowing conversion by virtue of the source and destination types. NK_Type_Narrowing, /// A narrowing conversion, because a constant expression got narrowed. @@ -391,7 +387,6 @@ class Sema; NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted, APValue &ConstantValue, QualType &ConstantType, - unsigned &BitFieldWidth, bool IgnoreFloatToIntegralConversion = false) const; bool isPointerConversionToBool() const; bool isPointerConversionToVoidPointer(ASTContext& Context) const; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 9339335cf38c8b..326879b0883fa1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11968,9 +11968,8 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E, APValue PreNarrowingValue; QualType PreNarrowingType; - unsigned BitFieldWidth; switch (SCS.getNarrowingKind(S.Context, E, PreNarrowingValue, - PreNarrowingType, BitFieldWidth, + PreNarrowingType, /*IgnoreFloatToIntegralConversion*/ true)) { case NK_Dependent_Narrowing: // Implicit conversion to a narrower type, but the expression is @@ -11978,13 +11977,6 @@ static bool checkThreeWayNarrowingConversion(Sema &S, QualType ToType, Expr *E, case NK_Not_Narrowing: return false; - case NK_BitField_Not_Narrowing: - if (!S.getLangOpts().CPlusPlus23) { - return S.Diag(E->getBeginLoc(), diag::ext_bit_field_narrowing) - << FromType << ToType << BitFieldWidth; - } - return false; - case NK_Constant_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index a87ee3049462ba..353e911c5cc337 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10531,27 +10531,13 @@ static void DiagnoseNarrowingInInitList(Sema &S, // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion. APValue ConstantValue; QualType ConstantType; - unsigned BitFieldWidth; switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue, - ConstantType, BitFieldWidth)) { + ConstantType)) { case NK_Not_Narrowing: case NK_Dependent_Narrowing: // No narrowing occurred. return; - case NK_BitField_Not_Narrowing: - // A bit-field was "narrowed" to an integer type which is wider than the - // bit-field but the declared type of the bit-field is wider than the target - // type. This is not considered narrowing in C++23. - if (S.getLangOpts().CPlusPlus23) - return; - if (!(S.Diag(PostInit->getBeginLoc(), diag::ext_bit_field_narrowing) - << PreNarrowingType - << EntityType.getNonReferenceType().getLocalUnqualifiedType() - << BitFieldWidth)) - return; - break; - case NK_Type_Narrowing: { // This was a floating-to-integer conversion, which is always considered a // narrowing conversion even if the value is a constant and can be @@ -10628,10 +10614,9 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType, APValue Value; QualType PreNarrowingType; - unsigned BitFieldWidth; // Reuse C++ narrowing check. switch (ICS.Standard.getNarrowingKind( - S.Context, Init, Value, PreNarrowingType, BitFieldWidth, + S.Context, Init, Value, PreNarrowingType, /*IgnoreFloatToIntegralConversion*/ false)) { // The value doesn't fit. case NK_Constant_Narrowing: @@ -10647,7 +10632,6 @@ static void CheckC23ConstexprInitConversion(Sema &S, QualType FromType, // Since we only reuse narrowing check for C23 constexpr variables here, we're // not really interested in these cases. - case NK_BitField_Not_Narrowing: case NK_Dependent_Narrowing: case NK_Variable_Narrowing: case NK_Not_Narrowing: diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 258bb43ccf3bf9..046442a34367f6 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -332,14 +332,11 @@ static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx, /// value of the expression prior to the narrowing conversion. /// \param ConstantType If this is an NK_Constant_Narrowing conversion, the /// type of the expression prior to the narrowing conversion. -/// \param BitFieldWidth If this is an NK_BitField_Not_Narrowing conversion, -/// the width of the source bit-field. /// \param IgnoreFloatToIntegralConversion If true type-narrowing conversions /// from floating point types to integral types should be ignored. NarrowingKind StandardConversionSequence::getNarrowingKind( ASTContext &Ctx, const Expr *Converted, APValue &ConstantValue, - QualType &ConstantType, unsigned &BitFieldWidth, - bool IgnoreFloatToIntegralConversion) const { + QualType &ConstantType, bool IgnoreFloatToIntegralConversion) const { assert((Ctx.getLangOpts().CPlusPlus || Ctx.getLangOpts().C23) && "narrowing check outside C++"); @@ -467,8 +464,8 @@ 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 - // (C++23) -- 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 + // (CWG2627) -- 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 @@ -480,7 +477,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( 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); @@ -496,6 +493,24 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( // Not all values of FromType can be represented in ToType. const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); + bool DependentBitField = false; + if (const FieldDecl *BitField = Initializer->getSourceBitField()) { + if (BitField->getBitWidth()->isValueDependent()) + DependentBitField = true; + else { + unsigned BitFieldWidth = BitField->getBitWidthValue(Ctx); + if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) { + assert(BitFieldWidth < FromWidth && + "Oversized bit-field can fit in target type but smaller field " + "type couldn't?"); + return NK_Not_Narrowing; + } + + // The initializer will be truncated to the bit-field width + FromWidth = BitFieldWidth; + } + } + // If it's value-dependent, we can't tell whether it's narrowing. if (Initializer->isValueDependent()) return NK_Dependent_Narrowing; @@ -503,23 +518,11 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( std::optional<llvm::APSInt> OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx); if (!OptInitializerValue) { - // Check for bit-field whose width means that this would not be narrowing - // (This check is after checking for constant expressions because - // a constant expression that fits is never narrowing but a non-constant - // expression that comes from a bit-field is only not narrowing before - // C++23 as an extension) - if (const FieldDecl *BitField = Initializer->getSourceBitField()) { - if (BitField->getBitWidth()->isValueDependent()) - return NK_Dependent_Narrowing; - - BitFieldWidth = BitField->getBitWidthValue(Ctx); - if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) { - assert(BitFieldWidth < FromWidth && - "Oversized bit-field can represent all but smaller field type " - "couldn't?"); - return NK_BitField_Not_Narrowing; - } - } + // If the bit-field width was dependent, it might end up being small + // enough to fit in the target type (unless the target type is unsigned + // and the source type is signed, in which case it will never fit) + if (DependentBitField && (FromSigned <= ToSigned)) + return NK_Dependent_Narrowing; // Otherwise, such a conversion is always narrowing return NK_Variable_Narrowing; @@ -6245,18 +6248,14 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, // Check for a narrowing implicit conversion. bool ReturnPreNarrowingValue = false; QualType PreNarrowingType; - unsigned BitFieldWidth; switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, - PreNarrowingType, BitFieldWidth)) { + PreNarrowingType)) { case NK_Dependent_Narrowing: // Implicit conversion to a narrower type, but the expression is // value-dependent so we can't tell whether it's actually narrowing. case NK_Variable_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. We'll diagnose this in a moment. - case NK_BitField_Not_Narrowing: - // Implicit conversion where the source is a bit-field and not a constant - // expression. case NK_Not_Narrowing: break; diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 9a9c33616ea8a0..21776f0093e0d7 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -1,16 +1,10 @@ // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11 -// RUN: %clang_cc1 -std=c++11 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++14 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++17 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20 -// RUN: %clang_cc1 -std=c++20 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,until-cxx23-pedantic // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 -// RUN: %clang_cc1 -std=c++23 -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 -// RUN: %clang_cc1 -std=c++2c -pedantic -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 namespace std { #if __cplusplus >= 202002L @@ -54,16 +48,13 @@ namespace cwg2627 { // cwg2627: 19 #if __cplusplus >= 202002L struct C { long long i : 8; - friend auto operator<=>(C, C) = default; // #cwg2627-3way-def + friend auto operator<=>(C, C) = default; }; void f() { C x{1}, y{2}; static_cast<void>(x <=> y); -// until-cxx23-pedantic-warning@#cwg2627-3way-def 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}} -// until-cxx23-pedantic-note@-2 {{in defaulted three-way comparison operator for 'C' first required here}} static_cast<void>(x.i <=> y.i); -// until-cxx23-pedantic-warning@-1 2 {{narrowing non-constant-expression from 'long long' bit-field of width 8 to 'int' is a C++23 extension}} } template<typename T> @@ -76,8 +67,8 @@ template<typename T> concept three_way_comparable = requires(T t) { { t <=> t }; }; template<typename T> concept bf_three_way_comparable = requires(T t) { { t.i <=> t.i }; }; -static_assert(three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L)); -static_assert(bf_three_way_comparable<CDependent<long long>> == (__cplusplus >= 202302L)); +static_assert(three_way_comparable<CDependent<long long>>); +static_assert(bf_three_way_comparable<CDependent<long long>>); #endif #if __cplusplus >= 201103L @@ -92,13 +83,7 @@ std::int64_t f(D<W> d) { } template std::int64_t f(D<63>); -// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 63 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}} -// until-cxx23-pedantic-note@-2 {{in instantiation of function template specialization 'cwg2627::f<63>' requested here}} -// until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}} template std::int64_t f(D<64>); -// until-cxx23-pedantic-warning-re@#cwg2627-f {{narrowing non-constant-expression from '__int128' bit-field of width 64 to 'std::int64_t' (aka '{{.+}}') is a C++23 extension}} -// until-cxx23-pedantic-note@-2 {{in instantiation of function template specialization 'cwg2627::f<64>' requested here}} -// until-cxx23-pedantic-note@#cwg2627-f {{insert an explicit cast to silence this issue}} template std::int64_t f(D<65>); // since-cxx11-error-re@#cwg2627-f {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}} // since-cxx11-note@-2 {{in instantiation of function template specialization 'cwg2627::f<65>' requested here}} @@ -115,30 +100,18 @@ struct E { }; template std::int16_t g(E<int, 16>); -// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'int' bit-field of width 16 to '{{.+}}' is a C++23 extension}} -// until-cxx23-pedantic-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 16>>' requested here}} -// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} template std::int16_t g(E<unsigned, 15>); -// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 15 to '{{.+}}' is a C++23 extension}} -// until-cxx23-pedantic-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 15>>' requested here}} -// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} template std::int16_t g(E<unsigned, 16>); // since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'unsigned int' to '{{.+}}' in initializer list}} // since-cxx11-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}} // since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} template std::uint16_t g(E<unsigned, 16>); -// until-cxx23-pedantic-warning-re@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 16 to '{{.+}}' is a C++23 extension}} -// until-cxx23-pedantic-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}} -// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} template std::uint16_t g(E<int, 1>); // since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to '{{.+}}' in initializer list}} // since-cxx11-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 1>>' requested here}} // since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} template bool g(E<unsigned, 1>); -// until-cxx23-pedantic-warning@#cwg2627-g {{narrowing non-constant-expression from 'unsigned int' bit-field of width 1 to 'bool' is a C++23 extension}} -// until-cxx23-pedantic-note@-2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<unsigned int, 1>>' requested here}} -// until-cxx23-pedantic-note@#cwg2627-g {{insert an explicit cast to silence this issue}} template bool g(E<int, 1>); // since-cxx11-error@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}} // since-cxx11-note@-2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<int, 1>>' requested here}} @@ -149,14 +122,22 @@ constexpr decltype(Target{ std::declval<Source>().i }, false) is_narrowing(int) template<typename Target, typename Source> constexpr bool is_narrowing(long) { return true; } -constexpr bool is_cxx23 = __cplusplus >= 202302L; -static_assert(is_narrowing<std::int16_t, E<int, 16>>(0) == !is_cxx23, ""); -static_assert(is_narrowing<std::int16_t, E<unsigned, 15>>(0) == !is_cxx23, ""); +static_assert(!is_narrowing<std::int16_t, E<int, 16>>(0), ""); +static_assert(!is_narrowing<std::int16_t, E<unsigned, 15>>(0), ""); static_assert(is_narrowing<std::int16_t, E<unsigned, 16>>(0), ""); -static_assert(is_narrowing<std::uint16_t, E<unsigned, 16>>(0) == !is_cxx23, ""); +static_assert(!is_narrowing<std::uint16_t, E<unsigned, 16>>(0), ""); static_assert(is_narrowing<std::uint16_t, E<int, 1>>(0), ""); -static_assert(is_narrowing<bool, E<unsigned, 1>>(0) == !is_cxx23, ""); +static_assert(!is_narrowing<bool, E<unsigned, 1>>(0), ""); static_assert(is_narrowing<bool, E<int, 1>>(0), ""); + +template<int N> +struct F { + signed int x : N; + decltype(std::int16_t{ x }) dependent_narrowing; + decltype(unsigned{ x }) always_narrowing; +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list}} +// since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} +}; #endif } >From 7801e324a5ab3ed49c571e9880137e6a0e7e3528 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Thu, 30 May 2024 18:08:17 +0100 Subject: [PATCH 04/14] Incorporate suggestions --- clang/test/CXX/drs/cwg26xx.cpp | 85 ++++++++++++++++------------------ 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 21776f0093e0d7..483b8bf895b8c5 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -72,66 +72,59 @@ static_assert(bf_three_way_comparable<CDependent<long long>>); #endif #if __cplusplus >= 201103L -template<int W> +template<typename T, int N> struct D { - __int128 i : W; + T i : N; }; -template<int W> -std::int64_t f(D<W> d) { - return std::int64_t{ d.i }; // #cwg2627-f -} +template<typename T, int N> +D<T, N> d(); -template std::int64_t f(D<63>); -template std::int64_t f(D<64>); -template std::int64_t f(D<65>); -// since-cxx11-error-re@#cwg2627-f {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}} -// since-cxx11-note@-2 {{in instantiation of function template specialization 'cwg2627::f<65>' requested here}} -// since-cxx11-note@#cwg2627-f {{insert an explicit cast to silence this issue}} +#ifdef __SIZEOF_INT128__ +std::int64_t d1{ d<__int128, 63>().i }; +std::int64_t d2{ d<__int128, 64>().i }; +std::int64_t d3{ d<__int128, 65>().i }; +// since-cxx11-error-re@-1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}} +// since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} +#endif -template<typename Target, typename Source> -Target g(Source x) { - return Target{ x.i }; // #cwg2627-g -} +#if __BITINT_MAXWIDTH__ >= 34 +__extension__ _BitInt(33) d4{ d<_BitInt(34), 33>().i }; +__extension__ _BitInt(33) d5{ d<_BitInt(34), 34>().i }; +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type '_BitInt(34)' to '_BitInt(33)' in initializer list}} +// FIXME-since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} +#endif -template<typename T, int N> -struct E { - T i : N; -}; +std::int16_t d6{ d<int, 16>().i }; +std::int16_t d7{ d<unsigned, 15>().i }; +std::int16_t d8{ d<unsigned, 16>().i }; +// since-cxx11-error-re@-1 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'std::int16_t' (aka '{{.+}}') in initializer list}} +// since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} +std::uint16_t d9{ d<unsigned, 16>().i }; +std::uint16_t da{ d<int, 1>().i }; +// since-cxx11-error-re@-1 {{non-constant-expression cannot be narrowed from type 'int' to 'std::uint16_t' (aka '{{.+}}') in initializer list}} +// since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} -template std::int16_t g(E<int, 16>); -template std::int16_t g(E<unsigned, 15>); -template std::int16_t g(E<unsigned, 16>); -// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'unsigned int' to '{{.+}}' in initializer list}} -// since-cxx11-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<unsigned int, 16>>' requested here}} -// since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} -template std::uint16_t g(E<unsigned, 16>); -template std::uint16_t g(E<int, 1>); -// since-cxx11-error-re@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to '{{.+}}' in initializer list}} -// since-cxx11-note-re@-2 {{in instantiation of function template specialization 'cwg2627::g<{{.+}}, cwg2627::E<int, 1>>' requested here}} -// since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} - -template bool g(E<unsigned, 1>); -template bool g(E<int, 1>); -// since-cxx11-error@#cwg2627-g {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}} -// since-cxx11-note@-2 {{in instantiation of function template specialization 'cwg2627::g<bool, cwg2627::E<int, 1>>' requested here}} -// since-cxx11-note@#cwg2627-g {{insert an explicit cast to silence this issue}} +bool db{ d<unsigned, 1>().i }; +bool dc{ d<int, 1>().i }; +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type 'int' to 'bool' in initializer list}} +// since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} template<typename Target, typename Source> constexpr decltype(Target{ std::declval<Source>().i }, false) is_narrowing(int) { return false; } template<typename Target, typename Source> constexpr bool is_narrowing(long) { return true; } -static_assert(!is_narrowing<std::int16_t, E<int, 16>>(0), ""); -static_assert(!is_narrowing<std::int16_t, E<unsigned, 15>>(0), ""); -static_assert(is_narrowing<std::int16_t, E<unsigned, 16>>(0), ""); -static_assert(!is_narrowing<std::uint16_t, E<unsigned, 16>>(0), ""); -static_assert(is_narrowing<std::uint16_t, E<int, 1>>(0), ""); -static_assert(!is_narrowing<bool, E<unsigned, 1>>(0), ""); -static_assert(is_narrowing<bool, E<int, 1>>(0), ""); +static_assert(!is_narrowing<std::int16_t, D<int, 16>>(0), ""); +static_assert(!is_narrowing<std::int16_t, D<unsigned, 15>>(0), ""); +static_assert(is_narrowing<std::int16_t, D<unsigned, 16>>(0), ""); +static_assert(!is_narrowing<std::uint16_t, D<unsigned, 16>>(0), ""); +static_assert(is_narrowing<std::uint16_t, D<int, 1>>(0), ""); +static_assert(!is_narrowing<bool, D<unsigned, 1>>(0), ""); +static_assert(is_narrowing<bool, D<int, 1>>(0), ""); template<int N> -struct F { +struct E { signed int x : N; decltype(std::int16_t{ x }) dependent_narrowing; decltype(unsigned{ x }) always_narrowing; @@ -139,7 +132,7 @@ struct F { // since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} }; #endif -} +} // namespace cwg2627 namespace cwg2628 { // cwg2628: no // this was reverted for the 16.x release >From bc886bce37cfcf6c7be829b4b2ad2401023e0c5a Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Thu, 30 May 2024 18:11:58 +0100 Subject: [PATCH 05/14] Get rid of regex directives --- clang/test/CXX/drs/cwg26xx.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 483b8bf895b8c5..80af56e55b056d 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected -// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,cxx11 -// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20 -// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 -// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +// RUN: %clang_cc1 -std=c++98 -triple %itanium_abi_triple %s -verify=expected +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,cxx11 +// RUN: %clang_cc1 -std=c++14 -triple %itanium_abi_triple %s -verify=expected,since-cxx11 +// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple %s -verify=expected,since-cxx11 +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20 +// RUN: %clang_cc1 -std=c++23 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +// RUN: %clang_cc1 -std=c++2c -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 namespace std { #if __cplusplus >= 202002L @@ -84,7 +84,7 @@ D<T, N> d(); std::int64_t d1{ d<__int128, 63>().i }; std::int64_t d2{ d<__int128, 64>().i }; std::int64_t d3{ d<__int128, 65>().i }; -// since-cxx11-error-re@-1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka '{{.+}}') in initializer list}} +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka 'long') in initializer list}} // since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} #endif @@ -98,11 +98,11 @@ __extension__ _BitInt(33) d5{ d<_BitInt(34), 34>().i }; std::int16_t d6{ d<int, 16>().i }; std::int16_t d7{ d<unsigned, 15>().i }; std::int16_t d8{ d<unsigned, 16>().i }; -// since-cxx11-error-re@-1 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'std::int16_t' (aka '{{.+}}') in initializer list}} +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type 'unsigned int' to 'std::int16_t' (aka 'short') in initializer list}} // since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} std::uint16_t d9{ d<unsigned, 16>().i }; std::uint16_t da{ d<int, 1>().i }; -// since-cxx11-error-re@-1 {{non-constant-expression cannot be narrowed from type 'int' to 'std::uint16_t' (aka '{{.+}}') in initializer list}} +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type 'int' to 'std::uint16_t' (aka 'unsigned short') in initializer list}} // since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} bool db{ d<unsigned, 1>().i }; >From 516f66494633ab8f094f9f34c84ce52d2ee6845f Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Thu, 30 May 2024 19:16:14 +0100 Subject: [PATCH 06/14] Make sure FromWidth doesn't increase with oversized bit-fields --- clang/lib/Sema/SemaOverload.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 046442a34367f6..86dae0f7a0f0e2 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -497,14 +497,10 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (const FieldDecl *BitField = Initializer->getSourceBitField()) { if (BitField->getBitWidth()->isValueDependent()) DependentBitField = true; - else { - unsigned BitFieldWidth = BitField->getBitWidthValue(Ctx); - if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) { - assert(BitFieldWidth < FromWidth && - "Oversized bit-field can fit in target type but smaller field " - "type couldn't?"); + else if (unsigned BitFieldWidth = BitField->getBitWidthValue(Ctx); + BitFieldWidth < FromWidth) { + if (CanRepresentAll(FromSigned, BitFieldWidth, ToSigned, ToWidth)) return NK_Not_Narrowing; - } // The initializer will be truncated to the bit-field width FromWidth = BitFieldWidth; >From 6b46fc9794216e0a4c6bb0278b5fc07aa40ef91d Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Thu, 30 May 2024 19:30:28 +0100 Subject: [PATCH 07/14] Fix windows test failure --- clang/test/CXX/drs/cwg26xx.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 80af56e55b056d..dbad0133095346 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -std=c++98 -triple %itanium_abi_triple %s -verify=expected -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,cxx11 -// RUN: %clang_cc1 -std=c++14 -triple %itanium_abi_triple %s -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++17 -triple %itanium_abi_triple %s -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20 -// RUN: %clang_cc1 -std=c++23 -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 -// RUN: %clang_cc1 -std=c++2c -triple %itanium_abi_triple %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +// RUN: %clang_cc1 -std=c++98 %s -verify=expected +// RUN: %clang_cc1 -std=c++11 %s -verify=expected,since-cxx11,cxx11 +// RUN: %clang_cc1 -std=c++14 %s -verify=expected,since-cxx11 +// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx11 +// RUN: %clang_cc1 -std=c++20 %s -verify=expected,since-cxx11,since-cxx20 +// RUN: %clang_cc1 -std=c++23 %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +// RUN: %clang_cc1 -std=c++2c %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 namespace std { #if __cplusplus >= 202002L @@ -19,10 +19,6 @@ namespace std { typedef __INT16_TYPE__ int16_t; typedef __UINT16_TYPE__ uint16_t; - typedef __INT32_TYPE__ int32_t; - typedef __UINT32_TYPE__ uint32_t; - typedef __INT64_TYPE__ int64_t; - typedef __UINT64_TYPE__ uint64_t; template<typename T> T declval(); } @@ -81,10 +77,13 @@ template<typename T, int N> D<T, N> d(); #ifdef __SIZEOF_INT128__ -std::int64_t d1{ d<__int128, 63>().i }; -std::int64_t d2{ d<__int128, 64>().i }; -std::int64_t d3{ d<__int128, 65>().i }; -// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type '__int128' to 'std::int64_t' (aka 'long') in initializer list}} +using int64_t = long long; +static_assert(sizeof(long long) == 8, "long long needs to be 64 bit for this test to work"); + +int64_t d1{ d<__int128, 63>().i }; +int64_t d2{ d<__int128, 64>().i }; +int64_t d3{ d<__int128, 65>().i }; +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type '__int128' to 'int64_t' (aka 'long long') in initializer list}} // since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} #endif >From aa038d01094e916bd8ed52ad03b21d66852b94ac Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Thu, 30 May 2024 20:16:03 +0100 Subject: [PATCH 08/14] Moved bitint tests to SemaCXX tests and removed __int128 from dr tests --- .../dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp | 24 ---------- clang/test/CXX/drs/cwg26xx.cpp | 33 ++++++-------- clang/test/SemaCXX/bitint-narrowing.cpp | 44 +++++++++++++++++++ 3 files changed, 57 insertions(+), 44 deletions(-) create mode 100644 clang/test/SemaCXX/bitint-narrowing.cpp diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp index a3049dc57d9fac..2bceb3e267790d 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp @@ -203,30 +203,6 @@ void shrink_int() { unsigned short usc1 = { c }; // expected-error {{non-constant-expression cannot be narrowed from type 'signed char'}} expected-note {{silence}} unsigned short usc2 = { (signed char)'x' }; // OK unsigned short usc3 = { (signed char)-1 }; // expected-error {{ -1 which cannot be narrowed}} expected-note {{silence}} - -#if __BITINT_MAXWIDTH__ >= 3 - _BitInt(2) S2 = 0; - unsigned _BitInt(2) U2 = 0; - _BitInt(3) S3 = 0; - unsigned _BitInt(3) U3 = 0; - - _BitInt(2) bi0 = { S2 }; - _BitInt(2) bi1 = { U2 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(2)'}} - _BitInt(2) bi2 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}} - _BitInt(2) bi3 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}} - unsigned _BitInt(2) bi4 = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}} - unsigned _BitInt(2) bi5 = { U2 }; - unsigned _BitInt(2) bi6 = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}} - unsigned _BitInt(2) bi7 = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}} - _BitInt(3) bi8 = { S2 }; - _BitInt(3) bi9 = { U2 }; - _BitInt(3) bia = { S3 }; - _BitInt(3) bib = { U3 }; // expected-error {{cannot be narrowed from type 'unsigned _BitInt(3)'}} - unsigned _BitInt(3) bic = { S2 }; // expected-error {{cannot be narrowed from type '_BitInt(2)'}} - unsigned _BitInt(3) bid = { U2 }; - unsigned _BitInt(3) bie = { S3 }; // expected-error {{cannot be narrowed from type '_BitInt(3)'}} - unsigned _BitInt(3) bif = { U3 }; -#endif } // Be sure that type- and value-dependent expressions in templates get the error diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index dbad0133095346..ec2ce1868c41e1 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -17,8 +17,13 @@ namespace std { strong_ordering::equal{0}, strong_ordering::greater{1}; #endif - typedef __INT16_TYPE__ int16_t; - typedef __UINT16_TYPE__ uint16_t; + typedef short int16_t; + typedef unsigned short uint16_t; + typedef int int32_t; + typedef unsigned uint32_t; + typedef long long int64_t; + typedef unsigned long long uint64_t; + __extension__ _Static_assert(sizeof(int16_t) == 2 && sizeof(int32_t) == 4 && sizeof(int64_t) == 8, "Some tests rely on these sizes"); template<typename T> T declval(); } @@ -76,23 +81,11 @@ struct D { template<typename T, int N> D<T, N> d(); -#ifdef __SIZEOF_INT128__ -using int64_t = long long; -static_assert(sizeof(long long) == 8, "long long needs to be 64 bit for this test to work"); - -int64_t d1{ d<__int128, 63>().i }; -int64_t d2{ d<__int128, 64>().i }; -int64_t d3{ d<__int128, 65>().i }; -// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type '__int128' to 'int64_t' (aka 'long long') in initializer list}} +std::int32_t d1{ d<std::int64_t, 63>().i }; +std::int32_t d2{ d<std::int64_t, 64>().i }; +std::int32_t d3{ d<std::int64_t, 65>().i }; +// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type 'std::int32_t' (aka 'int') to 'std::int64_t' (aka 'long long') in initializer list}} // since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} -#endif - -#if __BITINT_MAXWIDTH__ >= 34 -__extension__ _BitInt(33) d4{ d<_BitInt(34), 33>().i }; -__extension__ _BitInt(33) d5{ d<_BitInt(34), 34>().i }; -// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type '_BitInt(34)' to '_BitInt(33)' in initializer list}} -// FIXME-since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} -#endif std::int16_t d6{ d<int, 16>().i }; std::int16_t d7{ d<unsigned, 15>().i }; @@ -127,8 +120,8 @@ struct E { signed int x : N; decltype(std::int16_t{ x }) dependent_narrowing; decltype(unsigned{ x }) always_narrowing; -// since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list}} -// since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} + // since-cxx11-error@-1 {{non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list}} + // since-cxx11-note@-2 {{insert an explicit cast to silence this issue}} }; #endif } // namespace cwg2627 diff --git a/clang/test/SemaCXX/bitint-narrowing.cpp b/clang/test/SemaCXX/bitint-narrowing.cpp new file mode 100644 index 00000000000000..cf0baefdc62580 --- /dev/null +++ b/clang/test/SemaCXX/bitint-narrowing.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple x86_64-linux-pc -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple x86_64-windows-pc -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple i386-linux-pc -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple i386-windows-pc -fsyntax-only -verify -std=c++11 %s + +#if __BITINT_MAXWIDTH__ >= 35 +struct { + _BitInt(35) i : 33; +} x; +struct { + _BitInt(35) i : 34; +} y; +_BitInt(33) xx{ x.i }; +_BitInt(33) yy{ y.i }; +// expected-error@-1 {{non-constant-expression cannot be narrowed from type '_BitInt(35)' to '_BitInt(33)' in initializer list}} +// FIXME-expected-note@-2 {{insert an explicit cast to silence this issue}} +#endif + +#if __BITINT_MAXWIDTH__ >= 3 + _BitInt(2) S2 = 0; +unsigned _BitInt(2) U2 = 0; + _BitInt(3) S3 = 0; +unsigned _BitInt(3) U3 = 0; + + _BitInt(2) bi0{ S2 }; + _BitInt(2) bi1{ U2 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(2)' to '_BitInt(2)' in initializer list}} + _BitInt(2) bi2{ S3 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(3)' to '_BitInt(2)' in initializer list}} + _BitInt(2) bi3{ U3 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(3)' to '_BitInt(2)' in initializer list}} +unsigned _BitInt(2) bi4{ S2 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(2)' to 'unsigned _BitInt(2)' in initializer list}} +unsigned _BitInt(2) bi5{ U2 }; +unsigned _BitInt(2) bi6{ S3 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(3)' to 'unsigned _BitInt(2)' in initializer list}} +unsigned _BitInt(2) bi7{ U3 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(3)' to 'unsigned _BitInt(2)' in initializer list}} + _BitInt(3) bi8{ S2 }; + _BitInt(3) bi9{ U2 }; + _BitInt(3) bia{ S3 }; + _BitInt(3) bib{ U3 }; // expected-error {{non-constant-expression cannot be narrowed from type 'unsigned _BitInt(3)' to '_BitInt(3)' in initializer list}} +unsigned _BitInt(3) bic{ S2 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(2)' to 'unsigned _BitInt(3)' in initializer list}} +unsigned _BitInt(3) bid{ U2 }; +unsigned _BitInt(3) bie{ S3 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(3)' to 'unsigned _BitInt(3)' in initializer list}} +unsigned _BitInt(3) bif{ U3 }; +#else +// expected-no-diagnostics +#endif >From 362e4342a13d2147494771019b2d1ebb1e30263f Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Mon, 10 Jun 2024 16:45:45 +0100 Subject: [PATCH 09/14] _Static_assert -> static_assert --- clang/test/CXX/drs/cwg26xx.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 751ae71bc26f6b..ba9f7757b74dd3 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++98 -pedantic-errors %s -verify=expected +// RUN: %clang_cc1 -std=c++98 -pedantic-errors %s -verify=expected,cxx98 // RUN: %clang_cc1 -std=c++11 -pedantic-errors %s -verify=expected,since-cxx11,cxx11 // RUN: %clang_cc1 -std=c++14 -pedantic-errors %s -verify=expected,since-cxx11 // RUN: %clang_cc1 -std=c++17 -pedantic-errors %s -verify=expected,since-cxx11 @@ -6,6 +6,11 @@ // RUN: %clang_cc1 -std=c++23 -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 // RUN: %clang_cc1 -std=c++2c -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23 +#if __cplusplus == 199711L +#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__) +// cxx98-error@-1 {{variadic macros are a C99 feature}} +#endif + namespace std { #if __cplusplus >= 202002L struct strong_ordering { @@ -22,8 +27,10 @@ namespace std { typedef int int32_t; typedef unsigned uint32_t; typedef long long int64_t; + // cxx98-error@-1 {{'long long' is a C++11 extension}} typedef unsigned long long uint64_t; - __extension__ _Static_assert(sizeof(int16_t) == 2 && sizeof(int32_t) == 4 && sizeof(int64_t) == 8, "Some tests rely on these sizes"); + // cxx98-error@-1 {{'long long' is a C++11 extension}} + static_assert(sizeof(int16_t) == 2 && sizeof(int32_t) == 4 && sizeof(int64_t) == 8, "Some tests rely on these sizes"); template<typename T> T declval(); } >From 0eb6dffaa108b469c1c087a4fffb1a6792923cc3 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 26 Jul 2024 08:25:07 +0100 Subject: [PATCH 10/14] Retarget clang 20 --- clang/test/CXX/drs/cwg26xx.cpp | 2 +- clang/www/cxx_dr_status.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 54fd7b2c5b1cf8..ede1f86309846e 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -51,7 +51,7 @@ using enum E; #endif } -namespace cwg2627 { // cwg2627: 19 +namespace cwg2627 { // cwg2627: 20 #if __cplusplus >= 202002L struct C { long long i : 8; diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 78bf76d6171159..de2700eb855f2d 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -15577,7 +15577,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/2627.html">2627</a></td> <td>C++23</td> <td>Bit-fields and narrowing conversions</td> - <td class="unreleased" align="center">Clang 19</td> + <td class="unreleased" align="center">Clang 20</td> </tr> <tr id="2628"> <td><a href="https://cplusplus.github.io/CWG/issues/2628.html">2628</a></td> >From a2b5d5295aff7ecb23c9a5aff2638023985d8c72 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Wed, 31 Jul 2024 08:54:24 +0100 Subject: [PATCH 11/14] Add test for C --- clang/test/Sema/constexpr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/Sema/constexpr.c b/clang/test/Sema/constexpr.c index 8286cd2107d2f2..ce95af38cb3af2 100644 --- a/clang/test/Sema/constexpr.c +++ b/clang/test/Sema/constexpr.c @@ -217,6 +217,13 @@ struct S8 { constexpr struct S8 DesigInit = {.b = {299, 7, 8}, .a = {-1, 7, 8}}; // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'unsigned char'}} +struct S9 { + signed long long i : 8; +}; +constexpr struct S9 c = { 255 }; +// FIXME-expected-error@-1 {{constexpr initializer evaluates to 255 which is not exactly representable in 'long long' bit-field with width 8}} +// See: GH#101299 + void f5() { constexpr char V50 = 300; // expected-error@-1 {{constexpr initializer evaluates to 300 which is not exactly representable in type 'const char'}} >From b766ee285e54a3972269fd9f89215f086ebb8a9f Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Wed, 31 Jul 2024 18:07:35 +0100 Subject: [PATCH 12/14] __BITINT_MAXWIDTH__ >= 64 --- clang/test/SemaCXX/bitint-narrowing.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/clang/test/SemaCXX/bitint-narrowing.cpp b/clang/test/SemaCXX/bitint-narrowing.cpp index cf0baefdc62580..6ce544512f529c 100644 --- a/clang/test/SemaCXX/bitint-narrowing.cpp +++ b/clang/test/SemaCXX/bitint-narrowing.cpp @@ -4,7 +4,6 @@ // RUN: %clang_cc1 -triple i386-linux-pc -fsyntax-only -verify -std=c++11 %s // RUN: %clang_cc1 -triple i386-windows-pc -fsyntax-only -verify -std=c++11 %s -#if __BITINT_MAXWIDTH__ >= 35 struct { _BitInt(35) i : 33; } x; @@ -15,9 +14,7 @@ _BitInt(33) xx{ x.i }; _BitInt(33) yy{ y.i }; // expected-error@-1 {{non-constant-expression cannot be narrowed from type '_BitInt(35)' to '_BitInt(33)' in initializer list}} // FIXME-expected-note@-2 {{insert an explicit cast to silence this issue}} -#endif -#if __BITINT_MAXWIDTH__ >= 3 _BitInt(2) S2 = 0; unsigned _BitInt(2) U2 = 0; _BitInt(3) S3 = 0; @@ -39,6 +36,3 @@ unsigned _BitInt(3) bic{ S2 }; // expected-error {{non-constant-expression canno unsigned _BitInt(3) bid{ U2 }; unsigned _BitInt(3) bie{ S3 }; // expected-error {{non-constant-expression cannot be narrowed from type '_BitInt(3)' to 'unsigned _BitInt(3)' in initializer list}} unsigned _BitInt(3) bif{ U3 }; -#else -// expected-no-diagnostics -#endif >From e15dc9b4edf8ea9d0a8c8a6e4a2d1de19aa6e011 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Wed, 31 Jul 2024 18:09:26 +0100 Subject: [PATCH 13/14] No need to test cross os compile --- clang/test/SemaCXX/bitint-narrowing.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/test/SemaCXX/bitint-narrowing.cpp b/clang/test/SemaCXX/bitint-narrowing.cpp index 6ce544512f529c..81ca27fa856217 100644 --- a/clang/test/SemaCXX/bitint-narrowing.cpp +++ b/clang/test/SemaCXX/bitint-narrowing.cpp @@ -1,8 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -// RUN: %clang_cc1 -triple x86_64-linux-pc -fsyntax-only -verify -std=c++11 %s -// RUN: %clang_cc1 -triple x86_64-windows-pc -fsyntax-only -verify -std=c++11 %s -// RUN: %clang_cc1 -triple i386-linux-pc -fsyntax-only -verify -std=c++11 %s -// RUN: %clang_cc1 -triple i386-windows-pc -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple i386 -fsyntax-only -verify -std=c++11 %s struct { _BitInt(35) i : 33; >From 6406a74d6b548707f52f91162ae7501a73400483 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Thu, 8 Aug 2024 20:40:51 +0100 Subject: [PATCH 14/14] Fix test failure --- clang/test/Sema/constexpr.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/clang/test/Sema/constexpr.c b/clang/test/Sema/constexpr.c index 97519d1d2f203e..0cf9491c4a42bf 100644 --- a/clang/test/Sema/constexpr.c +++ b/clang/test/Sema/constexpr.c @@ -217,13 +217,6 @@ struct S8 { constexpr struct S8 DesigInit = {.b = {299, 7, 8}, .a = {-1, 7, 8}}; // expected-error@-1 {{constexpr initializer evaluates to -1 which is not exactly representable in type 'unsigned char'}} -struct S9 { - signed long long i : 8; -}; -constexpr struct S9 c = { 255 }; -// FIXME-expected-error@-1 {{constexpr initializer evaluates to 255 which is not exactly representable in 'long long' bit-field with width 8}} -// See: GH#101299 - void f5() { constexpr char V50 = 300; // expected-error@-1 {{constexpr initializer evaluates to 300 which is not exactly representable in type 'const char'}} @@ -367,3 +360,10 @@ void infsNaNs() { constexpr struct S9 s9 = { }; // expected-error {{variable has incomplete type 'const struct S9'}} \ // expected-note {{forward declaration of 'struct S9'}} + +struct S10 { + signed long long i : 8; +}; +constexpr struct S10 c = { 255 }; +// FIXME-expected-error@-1 {{constexpr initializer evaluates to 255 which is not exactly representable in 'long long' bit-field with width 8}} +// See: GH#101299 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits