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 <mi...@mitalashok.co.uk> 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<typename T> struct B : A { virtual void f() = delete; }; template struct B<int>; } + +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<typename T> 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 &X::operator=(X&&) = default; // expected-error {{redefinition}} X::~X() = default; // expected-error {{redefinition}} +#if __cplusplus >= 201103L struct Y { Y() = default; Y(const Y&) = default; @@ -149,6 +157,7 @@ namespace PR13527 { Y &Y::operator=(const Y&) noexcept = default; // expected-error {{definition of explicitly defaulted}} Y &Y::operator=(Y&&) noexcept = default; // expected-error {{definition of explicitly defaulted}} Y::~Y() = default; // expected-error {{definition of explicitly defaulted}} +#endif } namespace PR27699 { @@ -185,6 +194,7 @@ extern "C" { // expected-note {{extern "C" language linkage specification begins void PR13573(const _Tp&) = delete; } +#if __cplusplus >= 201103L namespace PR15597 { template<typename T> struct A { A() noexcept(true) = default; @@ -197,6 +207,7 @@ namespace PR15597 { A<int> a; B<int> b; } +#endif namespace PR27941 { struct ExplicitBool { @@ -245,6 +256,7 @@ E<Type>::E(const int&) {} // expected-error {{definition of explicitly defaulte } +#if __cplusplus >= 201103L namespace P1286R2 { struct X { X(); @@ -286,3 +298,4 @@ struct B { auto operator = (RM<B>) -> RV<B> = delete; }; } +#endif >From cb60e46f60debd6e7bd3f3665326fd0bf6103b3d Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Wed, 1 May 2024 15:50:24 +0100 Subject: [PATCH 2/2] Change some tests' expected messages Now that `= default` will be deleted when ill-formed when used as an extension --- clang/test/CXX/drs/dr16xx.cpp | 70 ++++++------------- clang/test/CXX/drs/dr21xx.cpp | 14 ++-- .../SemaCXX/cxx0x-cursory-default-delete.cpp | 2 +- 3 files changed, 25 insertions(+), 61 deletions(-) diff --git a/clang/test/CXX/drs/dr16xx.cpp b/clang/test/CXX/drs/dr16xx.cpp index cf6b45ceabf2cc..ed59e456770e07 100644 --- a/clang/test/CXX/drs/dr16xx.cpp +++ b/clang/test/CXX/drs/dr16xx.cpp @@ -192,36 +192,24 @@ namespace cwg1658 { // cwg1658: 5 struct E : A { E(); virtual void foo() = 0; }; // #cwg1658-E1 E::E() = default; // #cwg1658-E1-ctor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-2 {{base class 'A' has private default constructor}} - // cxx98-note@-3 {{in defaulted default constructor for 'cwg1658::DefCtor::E' first required here}} - // cxx98-note@#cwg1658-A1 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-E1-ctor {{defaulting this default constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-E1 {{default constructor of 'E' is implicitly deleted because base class 'A' has an inaccessible default constructor}} + // expected-error@#cwg1658-E1-ctor {{defaulting this default constructor would delete it after its first declaration}} + // expected-note@#cwg1658-E1 {{default constructor of 'E' is implicitly deleted because base class 'A' has an inaccessible default constructor}} struct F : virtual A { F(); }; // #cwg1658-F1 F::F() = default; // #cwg1658-F1-ctor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-2 {{inherited virtual base class 'A' has private default constructor}} - // cxx98-note@-3 {{in defaulted default constructor for 'cwg1658::DefCtor::F' first required here}} - // cxx98-note@#cwg1658-A1 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-F1-ctor {{defaulting this default constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-F1 {{default constructor of 'F' is implicitly deleted because base class 'A' has an inaccessible default constructor}} + // expected-error@#cwg1658-F1-ctor {{defaulting this default constructor would delete it after its first declaration}} + // expected-note@#cwg1658-F1 {{default constructor of 'F' is implicitly deleted because base class 'A' has an inaccessible default constructor}} struct G : B { G(); virtual void foo() = 0; }; // #cwg1658-G1 G::G() = default; // #cwg1658-G1-ctor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@#cwg1658-G1 {{base class 'B' has private destructor}} - // cxx98-note@#cwg1658-G1-ctor {{in defaulted default constructor for 'cwg1658::DefCtor::G' first required here}} - // cxx98-note@#cwg1658-B1 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-G1-ctor {{defaulting this default constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-G1 {{default constructor of 'G' is implicitly deleted because base class 'B' has an inaccessible destructor}} + // expected-error@#cwg1658-G1-ctor {{defaulting this default constructor would delete it after its first declaration}} + // expected-note@#cwg1658-G1 {{default constructor of 'G' is implicitly deleted because base class 'B' has an inaccessible destructor}} struct H : virtual B { H(); }; // #cwg1658-H1 H::H() = default; // #cwg1658-H1-ctor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@#cwg1658-H1 {{base class 'B' has private destructor}} - // cxx98-note@#cwg1658-H1-ctor {{in defaulted default constructor for 'cwg1658::DefCtor::H' first required here}} - // cxx98-note@#cwg1658-B1 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-H1-ctor {{defaulting this default constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-H1 {{default constructor of 'H' is implicitly deleted because base class 'B' has an inaccessible destructor}} + // expected-error@#cwg1658-H1-ctor {{defaulting this default constructor would delete it after its first declaration}} + // expected-note@#cwg1658-H1 {{default constructor of 'H' is implicitly deleted because base class 'B' has an inaccessible destructor}} } namespace Dtor { @@ -234,19 +222,13 @@ namespace cwg1658 { // cwg1658: 5 struct G : B { ~G(); virtual void foo() = 0; }; // #cwg1658-G2 G::~G() = default; // #cwg1658-G2-dtor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@#cwg1658-G2 {{base class 'B' has private destructor}} - // cxx98-note@#cwg1658-G2-dtor {{in defaulted destructor for 'cwg1658::Dtor::G' first required here}} - // cxx98-note@#cwg1658-B2 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-G2-dtor {{defaulting this destructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-G2 {{destructor of 'G' is implicitly deleted because base class 'B' has an inaccessible destructor}} + // expected-error@#cwg1658-G2-dtor {{defaulting this destructor would delete it after its first declaration}} + // expected-note@#cwg1658-G2 {{destructor of 'G' is implicitly deleted because base class 'B' has an inaccessible destructor}} struct H : virtual B { ~H(); }; // #cwg1658-H2 H::~H() = default; // #cwg1658-H2-dtor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@#cwg1658-H2 {{base class 'B' has private destructor}} - // cxx98-note@#cwg1658-H2-dtor {{in defaulted destructor for 'cwg1658::Dtor::H' first required here}} - // cxx98-note@#cwg1658-B2 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-H2-dtor {{defaulting this destructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-H2 {{destructor of 'H' is implicitly deleted because base class 'B' has an inaccessible destructor}} + // expected-error@#cwg1658-H2-dtor {{defaulting this destructor would delete it after its first declaration}} + // expected-note@#cwg1658-H2 {{destructor of 'H' is implicitly deleted because base class 'B' has an inaccessible destructor}} } namespace MemInit { @@ -291,36 +273,24 @@ namespace cwg1658 { // cwg1658: 5 // cxx98-error@-1 {{rvalue references are a C++11 extension}} E::E(const E&) = default; // #cwg1658-E5-copy-ctor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-2 {{base class 'A' has private copy constructor}} - // cxx98-note@-3 {{in defaulted copy constructor for 'cwg1658::CopyCtor::E' first required here}} - // cxx98-note@#cwg1658-A5 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-E5-copy-ctor {{defaulting this copy constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-E5 {{copy constructor of 'E' is implicitly deleted because base class 'A' has an inaccessible copy constructor}} + // expected-error@#cwg1658-E5-copy-ctor {{defaulting this copy constructor would delete it after its first declaration}} + // expected-note@#cwg1658-E5 {{copy constructor of 'E' is implicitly deleted because base class 'A' has an inaccessible copy constructor}} E::E(E&&) = default; // #cwg1658-E5-move-ctor // cxx98-error@-1 {{rvalue references are a C++11 extension}} // cxx98-error@-2 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-3 {{base class 'A' has private move constructor}} - // cxx98-note@-4 {{in defaulted move constructor for 'cwg1658::CopyCtor::E' first required here}} - // cxx98-note@#cwg1658-A5 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-E5-move-ctor {{defaulting this move constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-E5 {{move constructor of 'E' is implicitly deleted because base class 'A' has an inaccessible move constructor}} + // expected-error@#cwg1658-E5-move-ctor {{defaulting this move constructor would delete it after its first declaration}} + // expected-note@#cwg1658-E5 {{move constructor of 'E' is implicitly deleted because base class 'A' has an inaccessible move constructor}} struct F : virtual A { F(const F&); F(F&&); }; // #cwg1658-F5 // cxx98-error@-1 {{rvalue references are a C++11 extension}} F::F(const F&) = default; // #cwg1658-F5-copy-ctor // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-2 {{inherited virtual base class 'A' has private copy constructor}} - // cxx98-note@-3 {{in defaulted copy constructor for 'cwg1658::CopyCtor::F' first required here}} - // cxx98-note@#cwg1658-A5 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-F5-copy-ctor {{defaulting this copy constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-F5 {{copy constructor of 'F' is implicitly deleted because base class 'A' has an inaccessible copy constructor}} + // expected-error@#cwg1658-F5-copy-ctor {{defaulting this copy constructor would delete it after its first declaration}} + // expected-note@#cwg1658-F5 {{copy constructor of 'F' is implicitly deleted because base class 'A' has an inaccessible copy constructor}} F::F(F&&) = default; // #cwg1658-F5-move-ctor // cxx98-error@-1 {{rvalue references are a C++11 extension}} // cxx98-error@-2 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-3 {{inherited virtual base class 'A' has private move constructor}} - // cxx98-note@-4 {{in defaulted move constructor for 'cwg1658::CopyCtor::F' first required here}} - // cxx98-note@#cwg1658-A5 {{implicitly declared private here}} - // since-cxx11-error@#cwg1658-F5-move-ctor {{defaulting this move constructor would delete it after its first declaration}} - // since-cxx11-note@#cwg1658-F5 {{move constructor of 'F' is implicitly deleted because base class 'A' has an inaccessible move constructor}} + // expected-error@#cwg1658-F5-move-ctor {{defaulting this move constructor would delete it after its first declaration}} + // expected-note@#cwg1658-F5 {{move constructor of 'F' is implicitly deleted because base class 'A' has an inaccessible move constructor}} } // assignment case is superseded by cwg2180 diff --git a/clang/test/CXX/drs/dr21xx.cpp b/clang/test/CXX/drs/dr21xx.cpp index 082deb42e4fa09..84086ea2f21b73 100644 --- a/clang/test/CXX/drs/dr21xx.cpp +++ b/clang/test/CXX/drs/dr21xx.cpp @@ -246,19 +246,13 @@ namespace cwg2180 { // cwg2180: yes }; B &B::operator=(const B&) = default; // #cwg2180-B-copy // cxx98-error@-1 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-2 {{'operator=' is a private member of 'cwg2180::A'}} - // cxx98-note@-3 {{in defaulted copy assignment operator for 'cwg2180::B' first required here}} - // cxx98-note@#cwg2180-A-copy {{implicitly declared private here}} - // since-cxx11-error@#cwg2180-B-copy {{defaulting this copy assignment operator would delete it after its first declaration}} - // since-cxx11-note@#cwg2180-B {{copy assignment operator of 'B' is implicitly deleted because base class 'A' has an inaccessible copy assignment operator}} + // expected-error@#cwg2180-B-copy {{defaulting this copy assignment operator would delete it after its first declaration}} + // expected-note@#cwg2180-B {{copy assignment operator of 'B' is implicitly deleted because base class 'A' has an inaccessible copy assignment operator}} B &B::operator=(B&&) = default; // #cwg2180-B-move // cxx98-error@-1 {{rvalue references are a C++11 extension}} // cxx98-error@-2 {{defaulted function definitions are a C++11 extension}} - // cxx98-error@-3 {{'operator=' is a private member of 'cwg2180::A'}} - // cxx98-note@-4 {{in defaulted move assignment operator for 'cwg2180::B' first required here}} - // cxx98-note@#cwg2180-A-move {{implicitly declared private here}} - // since-cxx11-error@#cwg2180-B-move {{defaulting this move assignment operator would delete it after its first declaration}} - // since-cxx11-note@#cwg2180-B {{move assignment operator of 'B' is implicitly deleted because base class 'A' has an inaccessible move assignment operator}} + // expected-error@#cwg2180-B-move {{defaulting this move assignment operator would delete it after its first declaration}} + // expected-note@#cwg2180-B {{move assignment operator of 'B' is implicitly deleted because base class 'A' has an inaccessible move assignment operator}} } namespace cwg2199 { // cwg2199: 3.8 diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp index f884725a234671..313a4253641ae1 100644 --- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -std=c++03 -Wno-c++11-extensions -fsyntax-only -verify %s #if __cplusplus < 201103L -#define static_assert _Static_assert +#define static_assert __extension__ _Static_assert #define nullptr 0 #define noexcept throw() #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits