[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/90725 >From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Wed, 1 May 2024 12:45:54 +0100 Subject: [PATCH 1/3] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 Fixes #90605 --- clang/lib/Sema/SemaDeclCXX.cpp| 4 ++- .../SemaCXX/cxx0x-cursory-default-delete.cpp | 34 +-- .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 157d42c09cfcd8..e3c90c8ee1d644 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || + (!LangOpts.CPlusPlus11 && !RD->isLambda() && + !MD->isExplicitlyDefaulted()) || RD->isInvalidDecl()) return false; diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 6ae146f0d08c7d..f884725a234671 100644 --- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -1,4 +1,11 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#define nullptr 0 +#define noexcept throw() +#endif struct non_copiable { non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}} @@ -25,10 +32,12 @@ void fn1 () { non_const_copy ncc; non_const_copy ncc2 = ncc; ncc = ncc2; +#if __cplusplus >= 201103L const non_const_copy cncc{}; +#endif const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} - non_const_copy ncc3 = cncc; // expected-error {{no matching}} - ncc = cncc; // expected-error {{no viable overloaded}} + non_const_copy ncc3 = cncc1; // expected-error {{no matching}} + ncc = cncc1; // expected-error {{no viable overloaded}} }; struct no_fields { }; @@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b { struct S { S(); }; S::S() __attribute((noreturn)) = default; -using size_t = decltype(sizeof(0)); +using size_t = __SIZE_TYPE__; void *operator new(size_t) = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} void operator delete(void *) noexcept = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} @@ -217,3 +226,22 @@ namespace deleted_overrides_deleted { template struct B : A { virtual void f() = delete; }; template struct B; } + +namespace GH90605 { +struct Element { +Element& operator=(const Element&) = delete; // #GH90605-Element-assign +}; + +struct S { +Element i; // #GH90605-i + +S& operator=(const S&) = default; +// expected-warning@-1 {{explicitly defaulted copy assignment operator is implicitly deleted}} +// expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly deleted because field 'i' has a deleted copy assignment operator}} +// expected-note@#GH90605-Element-assign {{'operator=' has been explicitly marked deleted here}} +// expected-note@-4 {{replace 'default' with 'delete'}} +}; + +static_assert(!__is_trivially_assignable(S&, const S&), ""); +static_assert(!__is_assignable(S&, const S&), ""); +} diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp index 0c3dd1ea7aa274..30d54920a1a686 100644 --- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp +++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp @@ -1,4 +1,9 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#endif void fn() = default; // expected-error {{only special member}} struct foo { @@ -43,6 +48,7 @@ void tester() { b = c; } +#if __cplusplus >= 201103L template struct S : T { constexpr S() = default; // expected-note {{previous declaration is here}} constexpr S(const S&) = default; // expected-note {{previous declaration is here}} @@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec { *p = *p; // expected-note {{instantiation of}} } } +#endif namespace PR13527 { struct X { @@ -135,6
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || cor3ntin wrote: I would try to remove it and see if tests pass (which i suspect they will) https://github.com/llvm/llvm-project/pull/90725 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/90725 >From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Wed, 1 May 2024 12:45:54 +0100 Subject: [PATCH 1/2] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 Fixes #90605 --- clang/lib/Sema/SemaDeclCXX.cpp| 4 ++- .../SemaCXX/cxx0x-cursory-default-delete.cpp | 34 +-- .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 157d42c09cfcd8..e3c90c8ee1d644 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || + (!LangOpts.CPlusPlus11 && !RD->isLambda() && + !MD->isExplicitlyDefaulted()) || RD->isInvalidDecl()) return false; diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 6ae146f0d08c7d..f884725a234671 100644 --- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -1,4 +1,11 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#define nullptr 0 +#define noexcept throw() +#endif struct non_copiable { non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}} @@ -25,10 +32,12 @@ void fn1 () { non_const_copy ncc; non_const_copy ncc2 = ncc; ncc = ncc2; +#if __cplusplus >= 201103L const non_const_copy cncc{}; +#endif const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} - non_const_copy ncc3 = cncc; // expected-error {{no matching}} - ncc = cncc; // expected-error {{no viable overloaded}} + non_const_copy ncc3 = cncc1; // expected-error {{no matching}} + ncc = cncc1; // expected-error {{no viable overloaded}} }; struct no_fields { }; @@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b { struct S { S(); }; S::S() __attribute((noreturn)) = default; -using size_t = decltype(sizeof(0)); +using size_t = __SIZE_TYPE__; void *operator new(size_t) = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} void operator delete(void *) noexcept = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} @@ -217,3 +226,22 @@ namespace deleted_overrides_deleted { template struct B : A { virtual void f() = delete; }; template struct B; } + +namespace GH90605 { +struct Element { +Element& operator=(const Element&) = delete; // #GH90605-Element-assign +}; + +struct S { +Element i; // #GH90605-i + +S& operator=(const S&) = default; +// expected-warning@-1 {{explicitly defaulted copy assignment operator is implicitly deleted}} +// expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly deleted because field 'i' has a deleted copy assignment operator}} +// expected-note@#GH90605-Element-assign {{'operator=' has been explicitly marked deleted here}} +// expected-note@-4 {{replace 'default' with 'delete'}} +}; + +static_assert(!__is_trivially_assignable(S&, const S&), ""); +static_assert(!__is_assignable(S&, const S&), ""); +} diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp index 0c3dd1ea7aa274..30d54920a1a686 100644 --- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp +++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp @@ -1,4 +1,9 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#endif void fn() = default; // expected-error {{only special member}} struct foo { @@ -43,6 +48,7 @@ void tester() { b = c; } +#if __cplusplus >= 201103L template struct S : T { constexpr S() = default; // expected-note {{previous declaration is here}} constexpr S(const S&) = default; // expected-note {{previous declaration is here}} @@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec { *p = *p; // expected-note {{instantiation of}} } } +#endif namespace PR13527 { struct X { @@ -135,6
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || MitalAshok wrote: I wouldn't think so since we have a CXXMethodDecl and CXXRecordDecl. It was added with #73376 which changed it from`!CPlusPlus11` when adding C++03 lambdas https://github.com/llvm/llvm-project/pull/90725 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
https://github.com/MitalAshok converted_to_draft https://github.com/llvm/llvm-project/pull/90725 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/90725 >From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Wed, 1 May 2024 12:45:54 +0100 Subject: [PATCH 1/2] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 Fixes #90605 --- clang/lib/Sema/SemaDeclCXX.cpp| 4 ++- .../SemaCXX/cxx0x-cursory-default-delete.cpp | 34 +-- .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 157d42c09cfcd8..e3c90c8ee1d644 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || + (!LangOpts.CPlusPlus11 && !RD->isLambda() && + !MD->isExplicitlyDefaulted()) || RD->isInvalidDecl()) return false; diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 6ae146f0d08c7d..f884725a234671 100644 --- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -1,4 +1,11 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#define nullptr 0 +#define noexcept throw() +#endif struct non_copiable { non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}} @@ -25,10 +32,12 @@ void fn1 () { non_const_copy ncc; non_const_copy ncc2 = ncc; ncc = ncc2; +#if __cplusplus >= 201103L const non_const_copy cncc{}; +#endif const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} - non_const_copy ncc3 = cncc; // expected-error {{no matching}} - ncc = cncc; // expected-error {{no viable overloaded}} + non_const_copy ncc3 = cncc1; // expected-error {{no matching}} + ncc = cncc1; // expected-error {{no viable overloaded}} }; struct no_fields { }; @@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b { struct S { S(); }; S::S() __attribute((noreturn)) = default; -using size_t = decltype(sizeof(0)); +using size_t = __SIZE_TYPE__; void *operator new(size_t) = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} void operator delete(void *) noexcept = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} @@ -217,3 +226,22 @@ namespace deleted_overrides_deleted { template struct B : A { virtual void f() = delete; }; template struct B; } + +namespace GH90605 { +struct Element { +Element& operator=(const Element&) = delete; // #GH90605-Element-assign +}; + +struct S { +Element i; // #GH90605-i + +S& operator=(const S&) = default; +// expected-warning@-1 {{explicitly defaulted copy assignment operator is implicitly deleted}} +// expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly deleted because field 'i' has a deleted copy assignment operator}} +// expected-note@#GH90605-Element-assign {{'operator=' has been explicitly marked deleted here}} +// expected-note@-4 {{replace 'default' with 'delete'}} +}; + +static_assert(!__is_trivially_assignable(S&, const S&), ""); +static_assert(!__is_assignable(S&, const S&), ""); +} diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp index 0c3dd1ea7aa274..30d54920a1a686 100644 --- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp +++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp @@ -1,4 +1,9 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#endif void fn() = default; // expected-error {{only special member}} struct foo { @@ -43,6 +48,7 @@ void tester() { b = c; } +#if __cplusplus >= 201103L template struct S : T { constexpr S() = default; // expected-note {{previous declaration is here}} constexpr S(const S&) = default; // expected-note {{previous declaration is here}} @@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec { *p = *p; // expected-note {{instantiation of}} } } +#endif namespace PR13527 { struct X { @@ -135,6
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
philnik777 wrote: Note that this is also a problem with an implicit assignment operator: https://godbolt.org/z/jrh5novMo. I'm not 100% sure it's not a bug, but it definitely looks to me like one. It's definitely a mismatch between C++03 and C++11, which I wouldn't expect given that `= delete` a C++11 extension. https://github.com/llvm/llvm-project/pull/90725 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
@@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || cor3ntin wrote: are there cases where `!LangOpts.CPlusPlus` is true here? https://github.com/llvm/llvm-project/pull/90725 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
https://github.com/cor3ntin commented: Can you add a changelog entry? https://github.com/llvm/llvm-project/pull/90725 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
https://github.com/cor3ntin edited https://github.com/llvm/llvm-project/pull/90725 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Mital Ashok (MitalAshok) Changes Fixes #90605 --- Full diff: https://github.com/llvm/llvm-project/pull/90725.diff 3 Files Affected: - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+3-1) - (modified) clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp (+31-3) - (modified) clang/test/SemaCXX/cxx0x-defaulted-functions.cpp (+13) ``diff diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 157d42c09cfcd8..e3c90c8ee1d644 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || + (!LangOpts.CPlusPlus11 && !RD->isLambda() && + !MD->isExplicitlyDefaulted()) || RD->isInvalidDecl()) return false; diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 6ae146f0d08c7d..f884725a234671 100644 --- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -1,4 +1,11 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#define nullptr 0 +#define noexcept throw() +#endif struct non_copiable { non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}} @@ -25,10 +32,12 @@ void fn1 () { non_const_copy ncc; non_const_copy ncc2 = ncc; ncc = ncc2; +#if __cplusplus >= 201103L const non_const_copy cncc{}; +#endif const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} - non_const_copy ncc3 = cncc; // expected-error {{no matching}} - ncc = cncc; // expected-error {{no viable overloaded}} + non_const_copy ncc3 = cncc1; // expected-error {{no matching}} + ncc = cncc1; // expected-error {{no viable overloaded}} }; struct no_fields { }; @@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b { struct S { S(); }; S::S() __attribute((noreturn)) = default; -using size_t = decltype(sizeof(0)); +using size_t = __SIZE_TYPE__; void *operator new(size_t) = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} void operator delete(void *) noexcept = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} @@ -217,3 +226,22 @@ namespace deleted_overrides_deleted { template struct B : A { virtual void f() = delete; }; template struct B; } + +namespace GH90605 { +struct Element { +Element& operator=(const Element&) = delete; // #GH90605-Element-assign +}; + +struct S { +Element i; // #GH90605-i + +S& operator=(const S&) = default; +// expected-warning@-1 {{explicitly defaulted copy assignment operator is implicitly deleted}} +// expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly deleted because field 'i' has a deleted copy assignment operator}} +// expected-note@#GH90605-Element-assign {{'operator=' has been explicitly marked deleted here}} +// expected-note@-4 {{replace 'default' with 'delete'}} +}; + +static_assert(!__is_trivially_assignable(S&, const S&), ""); +static_assert(!__is_assignable(S&, const S&), ""); +} diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp index 0c3dd1ea7aa274..30d54920a1a686 100644 --- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp +++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp @@ -1,4 +1,9 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#endif void fn() = default; // expected-error {{only special member}} struct foo { @@ -43,6 +48,7 @@ void tester() { b = c; } +#if __cplusplus >= 201103L template struct S : T { constexpr S() = default; // expected-note {{previous declaration is here}} constexpr S(const S&) = default; // expected-note {{previous declaration is here}} @@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec { *p = *p; // expected-note {{instantiation of}} } } +#endif namespace PR13527 { struct X { @@ -135,6 +142,7 @@ namespace PR13527 { X ::operator=(X&&) = default; // expected-error {{redefinition}} X::~X() = default; // expected-error {{redefinition}} +#if __cplusplus >=
[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)
https://github.com/MitalAshok created https://github.com/llvm/llvm-project/pull/90725 Fixes #90605 >From 0793795ba7d5d5974b1403cd6ead0221fc20c5bb Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Wed, 1 May 2024 12:45:54 +0100 Subject: [PATCH] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 Fixes #90605 --- clang/lib/Sema/SemaDeclCXX.cpp| 4 ++- .../SemaCXX/cxx0x-cursory-default-delete.cpp | 34 +-- .../SemaCXX/cxx0x-defaulted-functions.cpp | 13 +++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 157d42c09cfcd8..e3c90c8ee1d644 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9767,7 +9767,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return false; CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); - if (!LangOpts.CPlusPlus || (!LangOpts.CPlusPlus11 && !RD->isLambda()) || + if (!LangOpts.CPlusPlus || + (!LangOpts.CPlusPlus11 && !RD->isLambda() && + !MD->isExplicitlyDefaulted()) || RD->isInvalidDecl()) return false; diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 6ae146f0d08c7d..f884725a234671 100644 --- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -1,4 +1,11 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#define nullptr 0 +#define noexcept throw() +#endif struct non_copiable { non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}} @@ -25,10 +32,12 @@ void fn1 () { non_const_copy ncc; non_const_copy ncc2 = ncc; ncc = ncc2; +#if __cplusplus >= 201103L const non_const_copy cncc{}; +#endif const non_const_copy cncc1; // expected-error {{default initialization of an object of const type 'const non_const_copy' without a user-provided default constructor}} - non_const_copy ncc3 = cncc; // expected-error {{no matching}} - ncc = cncc; // expected-error {{no viable overloaded}} + non_const_copy ncc3 = cncc1; // expected-error {{no matching}} + ncc = cncc1; // expected-error {{no viable overloaded}} }; struct no_fields { }; @@ -196,7 +205,7 @@ struct except_spec_d_match : except_spec_a, except_spec_b { struct S { S(); }; S::S() __attribute((noreturn)) = default; -using size_t = decltype(sizeof(0)); +using size_t = __SIZE_TYPE__; void *operator new(size_t) = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} void operator delete(void *) noexcept = delete; // expected-error {{deleted definition must be first declaration}} expected-note {{implicit}} @@ -217,3 +226,22 @@ namespace deleted_overrides_deleted { template struct B : A { virtual void f() = delete; }; template struct B; } + +namespace GH90605 { +struct Element { +Element& operator=(const Element&) = delete; // #GH90605-Element-assign +}; + +struct S { +Element i; // #GH90605-i + +S& operator=(const S&) = default; +// expected-warning@-1 {{explicitly defaulted copy assignment operator is implicitly deleted}} +// expected-note@#GH90605-i {{copy assignment operator of 'S' is implicitly deleted because field 'i' has a deleted copy assignment operator}} +// expected-note@#GH90605-Element-assign {{'operator=' has been explicitly marked deleted here}} +// expected-note@-4 {{replace 'default' with 'delete'}} +}; + +static_assert(!__is_trivially_assignable(S&, const S&), ""); +static_assert(!__is_assignable(S&, const S&), ""); +} diff --git a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp index 0c3dd1ea7aa274..30d54920a1a686 100644 --- a/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp +++ b/clang/test/SemaCXX/cxx0x-defaulted-functions.cpp @@ -1,4 +1,9 @@ // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s +// RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-builtins %s + +#if __cplusplus < 201103L +#define static_assert _Static_assert +#endif void fn() = default; // expected-error {{only special member}} struct foo { @@ -43,6 +48,7 @@ void tester() { b = c; } +#if __cplusplus >= 201103L template struct S : T { constexpr S() = default; // expected-note {{previous declaration is here}} constexpr S(const S&) = default; // expected-note {{previous declaration is here}} @@ -118,6 +124,7 @@ namespace DefaultedFnExceptionSpec { *p = *p; // expected-note {{instantiation of}} } } +#endif namespace PR13527 { struct X { @@