-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Clang] Ensure "=default"ed function can be deleted when used as an extension in C++03 #90725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…xtension in C++03 Fixes llvm#90605
@llvm/pr-subscribers-clang Author: Mital Ashok (MitalAshok) ChangesFixes #90605 Full diff: https://github.com/llvm/llvm-project/pull/90725.diff 3 Files Affected:
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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a changelog entry?
clang/lib/Sema/SemaDeclCXX.cpp
Outdated
@@ -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 || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are there cases where !LangOpts.CPlusPlus
is true here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would try to remove it and see if tests pass (which i suspect they will)
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 |
Now that `= default` will be deleted when ill-formed when used as an extension
ca63e41
to
5df6f72
Compare
Fixes #90605