https://github.com/yronglin updated https://github.com/llvm/llvm-project/pull/89942
>From 8c5f1d0f92d77bffec88759c19133a0bac130f32 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Wed, 24 Apr 2024 23:36:10 +0800 Subject: [PATCH 1/6] [Clang] Implement P2748R5 "Disallow Binding a Returned Glvalue to a Temporary" Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/docs/ReleaseNotes.rst | 4 +++- .../include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/lib/Sema/SemaInit.cpp | 13 +++++++++++-- clang/test/CXX/drs/cwg650.cpp | 2 +- clang/test/CXX/stmt.stmt/stmt.return/p6.cpp | 18 ++++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 clang/test/CXX/stmt.stmt/stmt.return/p6.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 64526ed6d06f55..5e07000198d63a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -129,7 +129,9 @@ C++2c Feature Support - Implemented `P2662R3 Pack Indexing <https://wg21.link/P2662R3>`_. -- Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_ +- Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_. + +- Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary <https://wg21.link/P2748R5>`_. Resolutions to C++ Defect Reports diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6732a1a98452ad..7342215db9cc3d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9950,6 +9950,8 @@ def warn_ret_stack_addr_ref : Warning< def warn_ret_local_temp_addr_ref : Warning< "returning %select{address of|reference to}0 local temporary object">, InGroup<ReturnStackAddress>; +def err_ret_local_temp_addr_ref : Error< + "returning %select{address of|reference to}0 local temporary object">; def warn_ret_addr_label : Warning< "returning address of label, which is local">, InGroup<ReturnStackAddress>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 793e16df178914..003c4c34810e1f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8340,8 +8340,17 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, << Entity.getType()->isReferenceType() << CLE->getInitializer() << 2 << DiagRange; } else { - Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) - << Entity.getType()->isReferenceType() << DiagRange; + // P2748R5: Disallow Binding a Returned Glvalue to a Temporary. + // [stmt.return]/p6: In a function whose return type is a reference, + // other than an invented function for std::is_convertible ([meta.rel]), + // a return statement that binds the returned reference to a temporary + // expression ([class.temporary]) is ill-formed. + if (getLangOpts().CPlusPlus26) + Diag(DiagLoc, diag::err_ret_local_temp_addr_ref) + << Entity.getType()->isReferenceType() << DiagRange; + else + Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) + << Entity.getType()->isReferenceType() << DiagRange; } break; } diff --git a/clang/test/CXX/drs/cwg650.cpp b/clang/test/CXX/drs/cwg650.cpp index dcb844095b0598..01a841b04b42d3 100644 --- a/clang/test/CXX/drs/cwg650.cpp +++ b/clang/test/CXX/drs/cwg650.cpp @@ -4,7 +4,7 @@ // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK -// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// Since C++26, P2748R5 "Disallow Binding a Returned Glvalue to a Temporary". Therefore we do not test this issue after C++26. #if __cplusplus == 199711L #define NOTHROW throw() diff --git a/clang/test/CXX/stmt.stmt/stmt.return/p6.cpp b/clang/test/CXX/stmt.stmt/stmt.return/p6.cpp new file mode 100644 index 00000000000000..682d3a8a075d4e --- /dev/null +++ b/clang/test/CXX/stmt.stmt/stmt.return/p6.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c++26 -fsyntax-only -verify %s + +auto&& f1() { + return 42; // expected-error{{returning reference to local temporary object}} +} +const double& f2() { + static int x = 42; + return x; // expected-error{{returning reference to local temporary object}} +} +auto&& id(auto&& r) { + return static_cast<decltype(r)&&>(r); +} +auto&& f3() { + return id(42); // OK, but probably a bug +} + +static_assert(__is_convertible(int, const int &)); +static_assert(__is_nothrow_convertible(int, const int &)); >From 4386c08a14df41b15bb272443910107a0b1bba66 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Thu, 25 Apr 2024 07:29:11 +0800 Subject: [PATCH 2/6] Update cxx_status.html and address comments in cwg650 Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/test/CXX/drs/cwg650.cpp | 2 +- clang/www/cxx_status.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CXX/drs/cwg650.cpp b/clang/test/CXX/drs/cwg650.cpp index 01a841b04b42d3..33ea179986e32b 100644 --- a/clang/test/CXX/drs/cwg650.cpp +++ b/clang/test/CXX/drs/cwg650.cpp @@ -4,7 +4,7 @@ // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK -// Since C++26, P2748R5 "Disallow Binding a Returned Glvalue to a Temporary". Therefore we do not test this issue after C++26. +// We aren't testing this since C++26 because of P2748R5 "Disallow Binding a Returned Glvalue to a Temporary". #if __cplusplus == 199711L #define NOTHROW throw() diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index c233171e63c811..2dc219861c0aeb 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -167,7 +167,7 @@ <h2 id="cxx26">C++2c implementation status</h2> <tr> <td>Disallow Binding a Returned Glvalue to a Temporary</td> <td><a href="https://wg21.link/P2748R5">P2748R5</a></td> - <td class="none" align="center">No</td> + <td class="full" align="center">Clang 19</td> </tr> <tr> <td>Clarifying rules for brace elision in aggregate initialization</td> >From 0ee6abe93159a29052af3ef9befff6a7e029eb31 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 26 Apr 2024 13:34:02 +0800 Subject: [PATCH 3/6] Add more test in type-traits.cpp and ignore returning address of local temporary object Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/docs/ReleaseNotes.rst | 2 +- .../clang/Basic/DiagnosticSemaKinds.td | 4 +- clang/lib/Sema/SemaInit.cpp | 41 ++++++++++++++++++- clang/test/SemaCXX/type-traits.cpp | 28 +++++++++++++ 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5e07000198d63a..4ad438fdb2dfdb 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -129,7 +129,7 @@ C++2c Feature Support - Implemented `P2662R3 Pack Indexing <https://wg21.link/P2662R3>`_. -- Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_. +- Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_ - Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary <https://wg21.link/P2748R5>`_. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 7342215db9cc3d..06cf2bc97eaa72 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9950,8 +9950,8 @@ def warn_ret_stack_addr_ref : Warning< def warn_ret_local_temp_addr_ref : Warning< "returning %select{address of|reference to}0 local temporary object">, InGroup<ReturnStackAddress>; -def err_ret_local_temp_addr_ref : Error< - "returning %select{address of|reference to}0 local temporary object">; +def err_ret_local_temp_ref : Error< + "returning reference to local temporary object">; def warn_ret_addr_label : Warning< "returning address of label, which is local">, InGroup<ReturnStackAddress>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 003c4c34810e1f..d22ab1311d9da1 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8345,8 +8345,45 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, // other than an invented function for std::is_convertible ([meta.rel]), // a return statement that binds the returned reference to a temporary // expression ([class.temporary]) is ill-formed. - if (getLangOpts().CPlusPlus26) - Diag(DiagLoc, diag::err_ret_local_temp_addr_ref) + // + // C++0x [meta.rel]p4: + // Given the following function prototype: + // + // template <class T> + // typename add_rvalue_reference<T>::type create(); + // + // the predicate condition for a template specialization + // is_convertible<From, To> shall be satisfied if and only if + // the return expression in the following code would be + // well-formed, including any implicit conversions to the return + // type of the function: + // + // To test() { + // return create<From>(); + // } + // + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression + // of the return-statement (including conversions to the return type) + // is considered. + // + // We skip to check whether we are evaluating one of {__is_convertible, + // __is_nothrow_convertible, __is_convertible_to} type traits + // expression, because we model the initialization as a + // copy-initialization of a temporary of the appropriate type, which for + // this expression is identical to the return statement (since NRVO + // doesn't apply), and not really build a `return create<From>()` in + // type traits expression evaluation. Therefor, P2748R5 has no impact for + // {__is_convertible, __is_nothrow_convertible, __is_convertible_to} + // evaluation. + // + // Clang can correctly handle cases like the following: + // + // static_assert(__is_convertible(int, const int &)); + // static_assert(__is_nothrow_convertible(int, const int &)); + // static_assert(__is_convertible_to(int, const int &)); + if (getLangOpts().CPlusPlus26 && Entity.getType()->isReferenceType()) + Diag(DiagLoc, diag::err_ret_local_temp_ref) << Entity.getType()->isReferenceType() << DiagRange; else Diag(DiagLoc, diag::warn_ret_local_temp_addr_ref) diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index dee4a29bd2bffe..01991887b284a7 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -2509,6 +2509,20 @@ void is_convertible() static_assert(__is_convertible(FloatWrapper, IntWrapper)); static_assert(__is_convertible(FloatWrapper, float)); static_assert(__is_convertible(float, FloatWrapper)); + static_assert(__is_convertible(IntWrapper, IntWrapper&&)); + static_assert(__is_convertible(IntWrapper, const IntWrapper&)); + static_assert(__is_convertible(IntWrapper, int&&)); + static_assert(__is_convertible(IntWrapper, const int&)); + static_assert(__is_convertible(int, IntWrapper&&)); + static_assert(__is_convertible(int, const IntWrapper&)); + static_assert(__is_convertible(IntWrapper, FloatWrapper&&)); + static_assert(__is_convertible(IntWrapper, const FloatWrapper&)); + static_assert(__is_convertible(FloatWrapper, IntWrapper&&)); + static_assert(__is_convertible(FloatWrapper, const IntWrapper&&)); + static_assert(__is_convertible(FloatWrapper, float&&)); + static_assert(__is_convertible(FloatWrapper, const float&)); + static_assert(__is_convertible(float, FloatWrapper&&)); + static_assert(__is_convertible(float, const FloatWrapper&)); } void is_nothrow_convertible() @@ -2521,6 +2535,20 @@ void is_nothrow_convertible() static_assert(!__is_nothrow_convertible(FloatWrapper, IntWrapper)); static_assert(!__is_nothrow_convertible(FloatWrapper, float)); static_assert(__is_nothrow_convertible(float, FloatWrapper)); + static_assert(__is_nothrow_convertible(IntWrapper, IntWrapper&&)); + static_assert(__is_nothrow_convertible(IntWrapper, const IntWrapper&)); + static_assert(__is_nothrow_convertible(IntWrapper, int&&)); + static_assert(__is_nothrow_convertible(IntWrapper, const int&)); + static_assert(!__is_nothrow_convertible(int, IntWrapper&&)); + static_assert(!__is_nothrow_convertible(int, const IntWrapper&)); + static_assert(!__is_nothrow_convertible(IntWrapper, FloatWrapper&&)); + static_assert(!__is_nothrow_convertible(IntWrapper, const FloatWrapper&)); + static_assert(!__is_nothrow_convertible(FloatWrapper, IntWrapper&&)); + static_assert(!__is_nothrow_convertible(FloatWrapper, const IntWrapper&)); + static_assert(!__is_nothrow_convertible(FloatWrapper, float&&)); + static_assert(!__is_nothrow_convertible(FloatWrapper, const float&)); + static_assert(__is_nothrow_convertible(float, FloatWrapper&&)); + static_assert(__is_nothrow_convertible(float, const FloatWrapper&)); } struct FromInt { FromInt(int); }; >From 5c4fbe9709c1c379d71efadf18f288b091bdad39 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 26 Apr 2024 13:40:56 +0800 Subject: [PATCH 4/6] format Signed-off-by: yronglin <yronglin...@gmail.com> --- clang/lib/Sema/SemaInit.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index d22ab1311d9da1..af9de05500d35b 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8373,9 +8373,9 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, // copy-initialization of a temporary of the appropriate type, which for // this expression is identical to the return statement (since NRVO // doesn't apply), and not really build a `return create<From>()` in - // type traits expression evaluation. Therefor, P2748R5 has no impact for - // {__is_convertible, __is_nothrow_convertible, __is_convertible_to} - // evaluation. + // type traits expression evaluation. Therefor, P2748R5 has no impact + // for evaluation of + // {__is_convertible, __is_nothrow_convertible, __is_convertible_to}. // // Clang can correctly handle cases like the following: // >From f24c8fbdca928317780c712f4d4adc804c38bce7 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 26 Apr 2024 13:41:31 +0800 Subject: [PATCH 5/6] --amend --- clang/lib/Sema/SemaInit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index af9de05500d35b..e18c1b8ea64ed2 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8374,8 +8374,8 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, // this expression is identical to the return statement (since NRVO // doesn't apply), and not really build a `return create<From>()` in // type traits expression evaluation. Therefor, P2748R5 has no impact - // for evaluation of - // {__is_convertible, __is_nothrow_convertible, __is_convertible_to}. + // for evaluation of {__is_convertible, __is_nothrow_convertible, + // __is_convertible_to}. // // Clang can correctly handle cases like the following: // >From 9ffaf2f6771c4d54a7efdaeb9e1e7b4ba88ede81 Mon Sep 17 00:00:00 2001 From: yronglin <yronglin...@gmail.com> Date: Fri, 26 Apr 2024 13:41:45 +0800 Subject: [PATCH 6/6] --amend --- clang/lib/Sema/SemaInit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index e18c1b8ea64ed2..f877e004322b29 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8374,7 +8374,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, // this expression is identical to the return statement (since NRVO // doesn't apply), and not really build a `return create<From>()` in // type traits expression evaluation. Therefor, P2748R5 has no impact - // for evaluation of {__is_convertible, __is_nothrow_convertible, + // for evaluation of {__is_convertible, __is_nothrow_convertible, // __is_convertible_to}. // // Clang can correctly handle cases like the following: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits