def err_incorrect_defaulted_constexpr : Error<
"defaulted definition of %sub{select_special_member_kind}0 "
"is not constexpr">;
+def warn_defaulted_method_deleted : Warning<
+ "explicitly defaulted %sub{select_special_member_kind}0 is implicitly "
+ "deleted">, InGroup<DiagGroup<"defaulted-function-deleted">>;
def err_out_of_line_default_deletes : Error<
"defaulting this %sub{select_special_member_kind}0 "
"would delete it after its first declaration">;
+def note_deleted_type_mismatch : Note<
+ "function is implicitly deleted because its declared type does not match "
+ "the type of an implicit %sub{select_special_member_kind}0">;
+def warn_cxx17_compat_defaulted_method_type_mismatch : Warning<
+ "explicitly defaulting this %sub{select_special_member_kind}0 with a type "
+ "different from the implicit type is incompatible with C++ standards before "
+ "C++2a">, InGroup<CXXPre2aCompat>, DefaultIgnore;
def warn_vbase_moved_multiple_times : Warning<
"defaulted move assignment operator of %0 will move assign virtual base "
"class %1 multiple times">, InGroup<DiagGroup<"multiple-move-vbase">>;
// copy operation can take a non-const reference) as an implicit
// declaration, and
// -- not have default arguments.
+ // C++2a changes the second bullet to instead delete the function if it's
+ // defaulted on its first declaration, unless it's "an assignment operator,
+ // and its return type differs or its parameter type is not a reference".
+ bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus2a && First;
+ bool ShouldDeleteForTypeMismatch = false;
unsigned ExpectedParams = 1;
if (CSM == CXXDefaultConstructor || CSM == CXXDestructor)
ExpectedParams = 0;
if (MD->getNumParams() != ExpectedParams) {
- // This also checks for default arguments: a copy or move constructor with a
+ // This checks for default arguments: a copy or move constructor with a
// default argument is classified as a default constructor, and assignment
// operations and destructors can't have default arguments.
Diag(MD->getLocation(), diag::err_defaulted_special_member_params)
<< CSM << MD->getSourceRange();
HadError = true;
} else if (MD->isVariadic()) {
- Diag(MD->getLocation(), diag::err_defaulted_special_member_variadic)
- << CSM << MD->getSourceRange();
- HadError = true;
+ if (DeleteOnTypeMismatch)
+ ShouldDeleteForTypeMismatch = true;
+ else {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_variadic)
+ << CSM << MD->getSourceRange();
+ HadError = true;
+ }
}
const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();
// A defaulted special member cannot have cv-qualifiers.
if (Type->getTypeQuals()) {
- Diag(MD->getLocation(), diag::err_defaulted_special_member_quals)
- << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus14;
- HadError = true;
+ if (DeleteOnTypeMismatch)
+ ShouldDeleteForTypeMismatch = true;
+ else {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_quals)
+ << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus14;
+ HadError = true;
+ }
}
}
HasConstParam = ReferentType.isConstQualified();
if (ReferentType.isVolatileQualified()) {
- Diag(MD->getLocation(),
- diag::err_defaulted_special_member_volatile_param) << CSM;
- HadError = true;
+ if (DeleteOnTypeMismatch)
+ ShouldDeleteForTypeMismatch = true;
+ else {
+ Diag(MD->getLocation(),
+ diag::err_defaulted_special_member_volatile_param) << CSM;
+ HadError = true;
+ }
}
if (HasConstParam && !CanHaveConstParam) {
- if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment) {
+ if (DeleteOnTypeMismatch)
+ ShouldDeleteForTypeMismatch = true;
+ else if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment) {
Diag(MD->getLocation(),
diag::err_defaulted_special_member_copy_const_param)
<< (CSM == CXXCopyAssignment);
// FIXME: Explain why this special member can't be const.
+ HadError = true;
} else {
Diag(MD->getLocation(),
diag::err_defaulted_special_member_move_const_param)
<< (CSM == CXXMoveAssignment);
+ HadError = true;
}
- HadError = true;
}
} else if (ExpectedParams) {
// A copy assignment operator can take its argument by value, but a
EPI));
}
- if (ShouldDeleteSpecialMember(MD, CSM)) {
+ if (ShouldDeleteForTypeMismatch || ShouldDeleteSpecialMember(MD, CSM)) {
if (First) {
SetDeclDeleted(MD, MD->getLocation());
+ if (!inTemplateInstantiation() && !HadError) {
+ Diag(MD->getLocation(), diag::warn_defaulted_method_deleted) << CSM;
+ if (ShouldDeleteForTypeMismatch) {
+ Diag(MD->getLocation(), diag::note_deleted_type_mismatch) << CSM;
+ } else {
+ ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true);
+ }
+ }
+ if (ShouldDeleteForTypeMismatch && !HadError) {
+ Diag(MD->getLocation(),
+ diag::warn_cxx17_compat_defaulted_method_type_mismatch) << CSM;
+ }
} else {
// C++11 [dcl.fct.def.default]p4:
// [For a] user-provided explicitly-defaulted function [...] if such a
// function is implicitly defined as deleted, the program is ill-formed.
Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM;
+ assert(!ShouldDeleteForTypeMismatch && "deleted non-first decl");
ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true);
HadError = true;
}
// expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
// expected-note@-4 {{while declaring the implicit move assignment operator for 'G'}}
// expected-note@-5 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
-struct H : D {
- H &operator=(H&&) = default;
+struct H : D { // expected-note {{deleted because base class 'D' has an inaccessible move assignment}}
+ H &operator=(H&&) = default; // expected-warning {{implicitly deleted}}
// expected-error@-1 {{deleted function 'operator=' cannot override a non-deleted function}}
// expected-note@-3 {{move assignment operator of 'H' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
~H();
// RUN: %clang_cc1 -verify %s -std=c++11
+// RUN: %clang_cc1 -verify %s -std=c++17
+// RUN: %clang_cc1 -verify %s -std=c++2a
// A function that is explicitly defaulted shall
struct A {
// -- be a special member function,
A(int) = default; // expected-error {{only special member functions may be defaulted}}
+ A(A) = default; // expected-error {{must pass its first argument by reference}}
// -- have the same declared function type as if it had been implicitly
// declared
void operator=(const A &) = default; // expected-error {{must return 'A &'}}
- A(...) = default; // expected-error {{cannot be variadic}}
- A(const A &, ...) = default; // expected-error {{cannot be variadic}}
+ A(...) = default;
+ A(const A &, ...) = default;
+ A &operator=(const A&) const = default;
+ A &operator=(A) const = default; // expected-error {{must be an lvalue refe}}
+#if __cplusplus <= 201703L
+ // expected-error@-5 {{cannot be variadic}}
+ // expected-error@-5 {{cannot be variadic}}
+ // expected-error@-5 {{may not have 'const'}}
+ // expected-error@-5 {{may not have 'const'}}
+#else
+ // expected-warning@-10 {{implicitly deleted}} expected-note@-10 {{declared type does not match the type of an implicit default constructor}}
+ // expected-warning@-10 {{implicitly deleted}} expected-note@-10 {{declared type does not match the type of an implicit copy constructor}}
+ // expected-warning@-10 {{implicitly deleted}} expected-note@-10 {{declared type does not match the type of an implicit copy assignment}}
+#endif
// (except for possibly differing ref-qualifiers
A &operator=(A &&) & = default;
A(double = 0.0) = default; // expected-error {{cannot have default arguments}}
A(const A & = 0) = default; // expected-error {{cannot have default arguments}}
};
+
+struct A2 {
+ A2(...);
+ A2(const A2 &, ...);
+ A2 &operator=(const A2&) const;
+};
+A2::A2(...) = default; // expected-error {{cannot be variadic}}
+A2::A2(const A2&, ...) = default; // expected-error {{cannot be variadic}}
+A2 &A2::operator=(const A2&) const = default; // expected-error {{may not have 'const'}}
+
+struct B {
+ B(B&);
+ B &operator=(B&);
+};
+struct C : B {
+ C(const C&) = default;
+ C &operator=(const C&) = default;
+#if __cplusplus <= 201703L
+ // expected-error@-3 {{is const, but a member or base requires it to be non-const}}
+ // expected-error@-3 {{is const, but a member or base requires it to be non-const}}
+#else
+ // expected-warning@-6 {{implicitly deleted}} expected-note@-6 {{type does not match}}
+ // expected-warning@-6 {{implicitly deleted}} expected-note@-6 {{type does not match}}
+#endif
+};
+
+struct D : B { // expected-note 2{{base class}}
+ D(const D&);
+ D &operator=(const D&);
+};
+D::D(const D&) = default; // expected-error {{would delete}} expected-error {{is const, but}}
+D &D::operator=(const D&) = default; // expected-error {{would delete}} expected-error {{is const, but}}
#if __cplusplus >= 201103L
namespace dr667 { // dr667: yes
struct A {
- A() = default;
- int &r;
+ A() = default; // expected-warning {{explicitly defaulted default constructor is implicitly deleted}}
+ int &r; // expected-note {{because field 'r' of reference type 'int &' would not be initialized}}
};
static_assert(!__is_trivially_constructible(A), "");
-// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-defaulted-function-deleted
// expected-no-diagnostics
-// RUN: %clang_cc1 -verify %s -std=c++11
+// RUN: %clang_cc1 -verify %s -std=c++11 -Wno-defaulted-function-deleted
struct Trivial {};
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-defaulted-function-deleted
struct DefaultedDefCtor1 {};
struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
-// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -std=c++11 %s -Wno-defaulted-function-deleted
struct NonTrivDtor {
~NonTrivDtor();
-// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=gnu++11 -fsyntax-only -verify %s -Wno-defaulted-function-deleted
#include "Inputs/cuda.h"
good_const gc;
struct no_default {
- no_default() = delete; // expected-note 4{{deleted here}}
+ no_default() = delete; // expected-note 5{{deleted here}}
};
struct no_dtor {
~no_dtor() = delete; // expected-note 2{{deleted here}}
has_friend hf;
struct defaulted_delete {
- no_default nd; // expected-note {{because field 'nd' has a deleted default constructor}}
- defaulted_delete() = default; // expected-note{{implicitly deleted here}}
+ no_default nd; // expected-note 2{{because field 'nd' has a deleted default constructor}}
+ defaulted_delete() = default; // expected-note{{implicitly deleted here}} expected-warning {{implicitly deleted}}
};
defaulted_delete dd; // expected-error {{call to implicitly-deleted default constructor}}
// RUN: %clang_cc1 -fsyntax-only -std=c++17 -pedantic -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++2a -Wc++17-compat-pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++2a -Wc++17-compat-pedantic -verify %s -Wno-defaulted-function-deleted
struct A {};
int (A::*pa)() const&;
#else
// expected-warning@-4 {{assignment of lambda is incompatible with C++ standards before C++2a}}
#endif
+
+struct DefaultDeleteWrongTypeBase {
+ DefaultDeleteWrongTypeBase(DefaultDeleteWrongTypeBase&);
+};
+struct DefaultDeleteWrongType : DefaultDeleteWrongTypeBase {
+ DefaultDeleteWrongType(const DefaultDeleteWrongType&) = default;
+#if __cplusplus <= 201703L
+ // expected-error@-2 {{a member or base requires it to be non-const}}
+#else
+ // expected-warning@-4 {{explicitly defaulting this copy constructor with a type different from the implicit type is incompatible with C++ standards before C++2a}}
+#endif
+};
int a = A().n; // expected-error {{no matching constructor}}
struct B {
- B() = delete; // expected-note 3{{here}}
+ B() = delete; // expected-note 4{{here}}
int n;
};
int b = B().n; // expected-error {{call to deleted}}
int c = C().b.n; // expected-error {{call to implicitly-deleted default}}
struct D {
- D() = default; // expected-note {{here}}
- B b; // expected-note {{'b' has a deleted default constructor}}
+ D() = default; // expected-note {{here}} expected-warning {{implicitly deleted}}
+ B b; // expected-note 2{{'b' has a deleted default constructor}}
};
int d = D().b.n; // expected-error {{call to implicitly-deleted default}}
void operator delete(void*, double);
} s; // expected-error {{attempt to use a deleted function}}
-struct T { // expected-note{{virtual destructor requires an unambiguous, accessible 'operator delete'}}
- virtual ~T() = default; // expected-note {{explicitly defaulted function was implicitly deleted here}}
+struct T { // expected-note 2{{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+ virtual ~T() = default; // expected-note {{explicitly defaulted function was implicitly deleted here}} expected-warning {{implicitly deleted}}
void operator delete(void*, int);
void operator delete(void*, double);
} t; // expected-error {{attempt to use a deleted function}}
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -DCXX_EXCEPTIONS -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -DCXX_EXCEPTIONS -fsyntax-only -verify %s -Wno-defaulted-function-deleted
template <class _Tp> struct is_nothrow_move_constructible {
static const bool value = false;
<tr>
<td><tt>const</tt> mismatch with defaulted copy constructor</td>
<td><a href="http://wg21.link/p0641r2">P0641R2</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td rowspan="3">Consistent comparison (<tt>operator<=></tt>)</td>