https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/90387
>From 77cb28e6faf95f5beb3fadc225cb5f0525b3dfe6 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sun, 28 Apr 2024 09:48:47 +0100 Subject: [PATCH 1/3] [clang] Implement CWG2851: floating-point conversions in converted constant expressions --- clang/docs/ReleaseNotes.rst | 3 + .../clang/Basic/DiagnosticSemaKinds.td | 4 ++ clang/lib/Sema/SemaOverload.cpp | 38 ++++++++++- clang/test/CXX/drs/dr28xx.cpp | 64 +++++++++++++++++++ clang/www/cxx_dr_status.html | 2 +- 5 files changed, 107 insertions(+), 4 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 604782ca43dd5..6fb0b2d1030be 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -166,6 +166,9 @@ 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>`_). +- Allow floating-point promotions and conversions in converted constant expressions. + (`CWG2851 Allow floating-point conversions in converted constant expressions <https://cplusplus.github.io/CWG/issues/2851.html>`_). + C Language Changes ------------------ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fdca82934cb4d..cb248f2ea6374 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -85,6 +85,10 @@ def err_expr_not_cce : Error< "%select{case value|enumerator value|non-type template argument|" "array size|explicit specifier argument|noexcept specifier argument|" "call to 'size()'|call to 'data()'}0 is not a constant expression">; +def err_float_conv_cant_represent : Error< + "non-type template argument evaluates to %0 which cannot be " + "exactly represented in type %1" +>; def ext_cce_narrowing : ExtWarn< "%select{case value|enumerator value|non-type template argument|" "array size|explicit specifier argument|noexcept specifier argument|" diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 04cd9e78739d2..40d65638e3afc 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6072,6 +6072,10 @@ static bool CheckConvertedConstantConversions(Sema &S, case ICK_Integral_Promotion: case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere. case ICK_Zero_Queue_Conversion: + // Per CWG2851, floating-point promotions and conversions are allowed. + // The value of a conversion is checked afterwards. + case ICK_Floating_Promotion: + case ICK_Floating_Conversion: return true; case ICK_Boolean_Conversion: @@ -6091,9 +6095,7 @@ static bool CheckConvertedConstantConversions(Sema &S, // only permitted if the source type is std::nullptr_t. return SCS.getFromType()->isNullPtrType(); - case ICK_Floating_Promotion: case ICK_Complex_Promotion: - case ICK_Floating_Conversion: case ICK_Complex_Conversion: case ICK_Floating_Integral: case ICK_Compatible_Conversion: @@ -6229,7 +6231,37 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From, if (Result.isInvalid()) return Result; - // Check for a narrowing implicit conversion. + if (SCS->Second == ICK_Floating_Conversion) { + // Unlike with narrowing conversions, the value must fit + // exactly even if it is in range + assert(CCE == Sema::CCEKind::CCEK_TemplateArg && + "Only non-type template args should use floating-point conversions"); + + // Initializer is From, except it is a full-expression + const Expr *Initializer = + IgnoreNarrowingConversion(S.Context, Result.get()); + + // If it's value-dependent, we can't tell whether it will fit + if (Initializer->isValueDependent()) + return Result; + + // Not-constant diagnosed afterwards + if (!Initializer->isCXX11ConstantExpr(S.Context, &PreNarrowingValue)) + return Result; + + llvm::APFloat PostNarrowingValue = PreNarrowingValue.getFloat(); + bool LosesInfo = true; + PostNarrowingValue.convert(S.Context.getFloatTypeSemantics(T), + llvm::APFloat::rmNearestTiesToEven, &LosesInfo); + + if (LosesInfo) + S.Diag(From->getBeginLoc(), diag::err_float_conv_cant_represent) + << PreNarrowingValue.getAsString(S.Context, From->getType()) << T; + + return Result; + } + + // Check for a narrowing integer conversion. bool ReturnPreNarrowingValue = false; QualType PreNarrowingType; switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, diff --git a/clang/test/CXX/drs/dr28xx.cpp b/clang/test/CXX/drs/dr28xx.cpp index be35d366bdd61..9076598da1418 100644 --- a/clang/test/CXX/drs/dr28xx.cpp +++ b/clang/test/CXX/drs/dr28xx.cpp @@ -3,6 +3,7 @@ // RUN: %clang_cc1 -std=c++14 -verify=expected %s // RUN: %clang_cc1 -std=c++17 -verify=expected %s // RUN: %clang_cc1 -std=c++20 -verify=expected,since-cxx20 %s +// RUN: %clang_cc1 -std=c++20 -mlong-double-64 -verify=expected,since-cxx20 %s // RUN: %clang_cc1 -std=c++23 -verify=expected,since-cxx20,since-cxx23 %s // RUN: %clang_cc1 -std=c++2c -verify=expected,since-cxx20,since-cxx23,since-cxx26 %s @@ -67,6 +68,69 @@ void B<int>::g() requires true; } // namespace cwg2847 +namespace cwg2851 { // cwg2851: 19 + +#if __cplusplus >= 202002L +template<typename T, T v> struct Val { static constexpr T value = v; }; + + +// Floating-point promotions + +static_assert(Val<long double, 0.0>::value == 0.0L); +static_assert(Val<long double, 0.0f>::value == 0.0L); +static_assert(Val<double, 0.0f>::value == 0.0); +static_assert(Val<long double, -0.0>::value == -0.0L); + +static_assert(!__is_same(Val<long double, -0.0>, Val<long double, 0.0L>)); +static_assert(__is_same(Val<long double, 0.5>, Val<long double, 0.5L>)); + +static_assert(__is_same(Val<long double, __builtin_inff()>, Val<long double, __builtin_infl()>)); + +static_assert(__is_same(Val<long double, __builtin_nanf("")>, Val<long double, static_cast<long double>(__builtin_nanf(""))>)); +static_assert(__is_same(Val<long double, __builtin_nansf("")>, Val<long double, static_cast<long double>(__builtin_nansf(""))>)); +static_assert(__is_same(Val<long double, __builtin_nanf("0x1")>, Val<long double, static_cast<long double>(__builtin_nanf("0x1"))>)); +static_assert(__is_same(Val<long double, __builtin_nansf("0x1")>, Val<long double, static_cast<long double>(__builtin_nansf("0x1"))>)); + + +// Floating-point conversions where the source value can be represented exactly in the destination type + +static_assert(Val<float, 0.0L>::value == 0.0L); +static_assert(__is_same(Val<float, 0.0>, Val<float, 0.0L>)); +static_assert(__is_same(Val<float, 0.0>, Val<float, 0.0f>)); +static_assert(!__is_same(Val<float, -0.0L>, Val<float, 0.0f>)); +static_assert(__is_same(Val<float, 0.5L>, Val<float, 0.5f>)); +static_assert(__is_same(Val<float, 0.5L>, Val<float, 0.5f>)); + +static_assert(__is_same(Val<float, double{__FLT_DENORM_MIN__}>, Val<float, __FLT_DENORM_MIN__>)); +Val<float, double{__FLT_DENORM_MIN__} / 2.0> _1; +// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} which cannot be exactly represented in type 'float'}} +Val<float, static_cast<long double>(__FLT_DENORM_MIN__) / 2.0L> _2; +// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} which cannot be exactly represented in type 'float'}} +Val<float, __DBL_MAX__> _3; +// since-cxx20-error-re@-1 {{non-type template argument evaluates to {{.+}} which cannot be exactly represented in type 'float'}} + +static_assert(__is_same(Val<float, __builtin_infl()>, Val<float, __builtin_inff()>)); + +static_assert(__is_same(Val<float, __builtin_nanl("")>, Val<float, static_cast<float>(__builtin_nanl(""))>)); +static_assert(__is_same(Val<float, __builtin_nansl("")>, Val<float, static_cast<float>(__builtin_nansl(""))>)); +#if __SIZEOF_LONG_DOUBLE__ > 8 +// since-cxx20-error@-2 {{non-type template argument evaluates to nan which cannot be exactly represented in type 'float'}} +#endif +// Payload is shifted right so these payloads will be preserved +static_assert(__is_same(Val<float, __builtin_nan("0xFF00000000")>, Val<float, static_cast<float>(__builtin_nan("0xFF00000000"))>)); +static_assert(__is_same(Val<float, __builtin_nans("0xFF00000000")>, Val<float, static_cast<float>(__builtin_nans("0xFF00000000"))>)); +static_assert(__is_same(Val<float, __builtin_nanl("0x1")>, Val<float, static_cast<float>(__builtin_nanl("0x1"))>)); +// since-cxx20-error@-1 {{non-type template argument evaluates to nan which cannot be exactly represented in type 'float'}} +static_assert(__is_same(Val<float, __builtin_nansl("0x1")>, Val<float, static_cast<float>(__builtin_nansl("0x1"))>)); +// since-cxx20-error@-1 {{non-type template argument evaluates to nan which cannot be exactly represented in type 'float'}} +static_assert(__is_same(Val<float, __builtin_nanl("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")>, Val<float, static_cast<float>(__builtin_nanl("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"))>)); +// since-cxx20-error@-1 {{non-type template argument evaluates to nan which cannot be exactly represented in type 'float'}} +static_assert(__is_same(Val<float, __builtin_nansl("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")>, Val<float, static_cast<float>(__builtin_nansl("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"))>)); +// since-cxx20-error@-1 {{non-type template argument evaluates to nan which cannot be exactly represented in type 'float'}} +#endif + +} + namespace cwg2858 { // cwg2858: 19 tentatively ready 2024-04-05 #if __cplusplus > 202302L diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 875521bd505d5..331962ba0b9c3 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -16915,7 +16915,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/2851.html">2851</a></td> <td>DR</td> <td>Allow floating-point conversions in converted constant expressions</td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 19</td> </tr> <tr class="open" id="2852"> <td><a href="https://cplusplus.github.io/CWG/issues/2852.html">2852</a></td> >From cdb77d378d20c49b763a888fa35c62d35053f971 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 21 Jun 2024 20:36:24 +0100 Subject: [PATCH 2/3] namespace comment --- clang/test/CXX/drs/cwg28xx.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp index 5fb33c6e4cdaa..416b8bbdc2a62 100644 --- a/clang/test/CXX/drs/cwg28xx.cpp +++ b/clang/test/CXX/drs/cwg28xx.cpp @@ -89,7 +89,6 @@ void B<int>::g() requires true; } // namespace cwg2847 namespace cwg2851 { // cwg2851: 19 - #if __cplusplus >= 202002L template<typename T, T v> struct Val { static constexpr T value = v; }; @@ -148,8 +147,7 @@ static_assert(__is_same(Val<float, __builtin_nanl("0xFFFFFFFFFFFFFFFFFFFFFFFFFFF static_assert(__is_same(Val<float, __builtin_nansl("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")>, Val<float, static_cast<float>(__builtin_nansl("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"))>)); // since-cxx20-error@-1 {{non-type template argument evaluates to nan which cannot be exactly represented in type 'float'}} #endif - -} +} // namespace cwg2851 namespace cwg2857 { // cwg2857: no struct A {}; >From 2ae71ab46646f529f7cccafbc48eed3839c12d77 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Fri, 26 Jul 2024 08:47:25 +0100 Subject: [PATCH 3/3] Retarget clang 20 --- clang/test/CXX/drs/cwg28xx.cpp | 2 +- clang/www/cxx_dr_status.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp index 416b8bbdc2a62..f5b2804a3315a 100644 --- a/clang/test/CXX/drs/cwg28xx.cpp +++ b/clang/test/CXX/drs/cwg28xx.cpp @@ -88,7 +88,7 @@ void B<int>::g() requires true; } // namespace cwg2847 -namespace cwg2851 { // cwg2851: 19 +namespace cwg2851 { // cwg2851: 20 #if __cplusplus >= 202002L template<typename T, T v> struct Val { static constexpr T value = v; }; diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index c425e32699c99..5935f25260cbd 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -16922,7 +16922,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/2851.html">2851</a></td> <td>DR</td> <td>Allow floating-point conversions in converted constant expressions</td> - <td class="unreleased" align="center">Clang 19</td> + <td class="unreleased" align="center">Clang 20</td> </tr> <tr class="open" id="2852"> <td><a href="https://cplusplus.github.io/CWG/issues/2852.html">2852</a></td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits