[clang] [Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 (PR #90725)

2024-05-01 Thread Mital Ashok via cfe-commits

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)

2024-05-01 Thread via cfe-commits


@@ -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)

2024-05-01 Thread Mital Ashok via cfe-commits

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)

2024-05-01 Thread Mital Ashok via cfe-commits


@@ -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)

2024-05-01 Thread Mital Ashok via cfe-commits

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)

2024-05-01 Thread Mital Ashok via cfe-commits

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)

2024-05-01 Thread Nikolas Klauser via cfe-commits

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)

2024-05-01 Thread via cfe-commits


@@ -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)

2024-05-01 Thread via cfe-commits

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)

2024-05-01 Thread via cfe-commits

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)

2024-05-01 Thread via cfe-commits

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)

2024-05-01 Thread Mital Ashok via cfe-commits

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 {
@@