llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: StefanPaulet <details> <summary>Changes</summary> Clang allows friend declarations of closure type members, which is disallowed per CWG 1780 (Issue #<!-- -->26540). Added a new diagnostic when the friend declaration targets a member of a `CXXRecordDecl` that is a lambda. --- Full diff: https://github.com/llvm/llvm-project/pull/191419.diff 6 Files Affected: - (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+5) - (modified) clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp (+2-2) - (modified) clang/test/SemaCXX/lambda-expressions.cpp (+50-8) - (modified) clang/test/SemaTemplate/GH75426.cpp (+1-2) - (modified) clang/test/SemaTemplate/concepts.cpp (+1-1) ``````````diff diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6d2fae551566f..6563dc11e39f1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8907,6 +8907,8 @@ let CategoryName = "Lambda Issue" in { "capture of variable '%0' as type %1 calls %select{private|protected}3 " "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">, AccessControl; + def err_friend_lambda_decl : Error< + "a member of a lambda should not be the target of a friend declaration">; def note_lambda_to_block_conv : Note< "implicit capture of lambda object due to conversion to block pointer " "here">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c1d3960e65ef6..ba1b4c4e5ef7e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -18465,6 +18465,11 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, Diag(Loc, diag::err_introducing_special_friend) << DiagArg; return nullptr; } + } else { + CXXRecordDecl *RC = dyn_cast<CXXRecordDecl>(DC); + if (RC->isLambda()) { + Diag(NameInfo.getBeginLoc(), diag::err_friend_lambda_decl); + } } // FIXME: This is an egregious hack to cope with cases where the scope stack diff --git a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp index aa8d055e44971..20922f2fdaa4f 100644 --- a/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp +++ b/clang/test/SemaCXX/cxx1z-constexpr-lambdas.cpp @@ -57,8 +57,8 @@ struct test_never_constant { // expected-error@+3 {{non-constexpr declaration of 'operator()' follows constexpr declaration}} // expected-error@+3 {{non-constexpr declaration of 'operator()' follows constexpr declaration}} #endif - friend auto decltype(never_constant_1)::operator()() const; - friend int decltype(never_constant_2)::operator()() const; + friend auto decltype(never_constant_1)::operator()() const; // expected-error {{a member of a lambda should not be the target of a friend declaration}} + friend int decltype(never_constant_2)::operator()() const; // expected-error {{a member of a lambda should not be the target of a friend declaration}} }; } // end ns test_constexpr_checking diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index 00c52efb78a7d..6ae7ac9888b41 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -657,26 +657,29 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType { struct X { #if __cplusplus > 201402L - friend constexpr auto T::operator()(int) const; - friend constexpr T::operator ExpectedTypeT() const noexcept; + friend constexpr auto T::operator()(int) const; // expected-error {{a member of a lambda should not be the target of a friend declaration}} + friend constexpr T::operator ExpectedTypeT() const noexcept; // expected-error {{a member of a lambda should not be the target of a friend declaration}} template<typename T> - friend constexpr void U::operator()(T&) const; + friend constexpr void U::operator()(T&) const; // expected-error {{a member of a lambda should not be the target of a friend declaration}} // FIXME: This should not match; the return type is specified as behaving // "as if it were a decltype-specifier denoting the return type of // [operator()]", which is not equivalent to this alias template. template<typename T> - friend constexpr U::operator ExpectedTypeU<T>() const noexcept; + friend constexpr U::operator ExpectedTypeU<T>() const noexcept; // expected-error {{a member of a lambda should not be the target of a friend declaration}} #else friend auto T::operator()(int) const; // cxx11-error {{'auto' return without trailing return type; deduced return types are a C++14 extension}} \ - cxx03-error {{'auto' not allowed in function return type}} - friend T::operator ExpectedTypeT() const; + cxx03-error {{'auto' not allowed in function return type}} \ + expected-error {{a member of a lambda should not be the target of a friend declaration}} + friend T::operator ExpectedTypeT() const; // expected-error {{a member of a lambda should not be the target of a friend declaration}} template<typename T> - friend void U::operator()(T&) const; // cxx03-cxx11-error {{friend declaration of 'operator()' does not match any declaration}} + friend void U::operator()(T&) const; // cxx03-cxx11-error {{friend declaration of 'operator()' does not match any declaration}} \ + expected-error {{a member of a lambda should not be the target of a friend declaration}} // FIXME: This should not match, as above. template<typename T> - friend U::operator ExpectedTypeU<T>() const; // cxx03-cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}} + friend U::operator ExpectedTypeU<T>() const; // cxx03-cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}} \ + expected-error {{a member of a lambda should not be the target of a friend declaration}} #endif private: @@ -812,3 +815,42 @@ void test_lambda_return_type() { }; } } + +namespace GH26540 { +#if __cplusplus >= 201703L +#define CONSTEXPR17 constexpr +#define NOEXCEPT17 noexcept +#else +#define CONSTEXPR17 +#define NOEXCEPT17 +#endif + auto l = []() -> int { + return 5; + }; + using L = decltype(l); + using ConvertL = int(*)(); + + class NonGenericLambdaFriend { + friend CONSTEXPR17 int L::operator()() const; // expected-error{{a member of a lambda should not be the target of a friend declaration}} + friend CONSTEXPR17 L::operator ConvertL() const NOEXCEPT17; // expected-error{{a member of a lambda should not be the target of a friend declaration}} + }; + +#if __cplusplus > 201103L + auto gl = [](auto t) -> int { + return t.x; + }; + using GL = decltype(gl); + template <typename T> + using ConvertGL = int(*)(T); + + class GenericLambdaFriend { + int x{2}; + template <typename T> + friend CONSTEXPR17 auto GL::operator()(T t) const -> int; // expected-error{{a member of a lambda should not be the target of a friend declaration}} + template <typename T> + friend CONSTEXPR17 GL::operator ConvertGL<T>() const NOEXCEPT17; // expected-error{{a member of a lambda should not be the target of a friend declaration}} + }; +#endif +#undef NOEXCEPT17 +#undef CONSTEXPR17 +} diff --git a/clang/test/SemaTemplate/GH75426.cpp b/clang/test/SemaTemplate/GH75426.cpp index faf70699f9c5f..776db332358a8 100644 --- a/clang/test/SemaTemplate/GH75426.cpp +++ b/clang/test/SemaTemplate/GH75426.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -// expected-no-diagnostics template<typename T> concept C = true; @@ -12,5 +11,5 @@ auto L = []<C T>{}; template<typename X> class Friends { template<C T> friend void A::f(); - template<C T> friend void decltype(L)::operator()(); + template<C T> friend void decltype(L)::operator()(); // expected-error {{a member of a lambda should not be the target of a friend declaration}} }; diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index ac80d16b4ccf8..b2faf13d53033 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -849,7 +849,7 @@ template<typename T, typename U> concept C = true; template<typename T> auto L = []<C<T> U>() {}; struct Q { - template<C<int> U> friend constexpr auto decltype(L<int>)::operator()() const; + template<C<int> U> friend constexpr auto decltype(L<int>)::operator()() const; // expected-error {{a member of a lambda should not be the target of a friend declaration}} }; template <class T> `````````` </details> https://github.com/llvm/llvm-project/pull/191419 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
