summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2018-09-28 01:16:43 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2018-09-28 01:16:43 +0000
commit9b2c5e7c44fd28c31f4a0b088d0bf71da4fddfa5 (patch)
tree2d42358db17e2e96f5d821a77572ecc8ae2cb1df /clang/lib
parentfdf4c76ca0a73b0c753329eb59804617a6003256 (diff)
downloadbcm5719-llvm-9b2c5e7c44fd28c31f4a0b088d0bf71da4fddfa5.tar.gz
bcm5719-llvm-9b2c5e7c44fd28c31f4a0b088d0bf71da4fddfa5.zip
[cxx2a] P0641R2: (Some) type mismatches on defaulted functions only
render the function deleted instead of rendering the program ill-formed. This change also adds an enabled-by-default warning for the case where an explicitly-defaulted special member function of a non-template class is implicitly deleted by the type checking rules. (This fires either due to this language change or due to pre-C++20 reasons for the member being implicitly deleted). I've tested this on a large codebase and found only bugs (where the program means something that's clearly different from what the programmer intended), so this is enabled by default, but we should revisit this if there are problems with this being enabled by default. llvm-svn: 343285
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp59
1 files changed, 46 insertions, 13 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index a18b8dd5967..3261a7031d5 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6451,20 +6451,29 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// 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>();
@@ -6489,9 +6498,13 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// 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;
+ }
}
}
@@ -6504,23 +6517,30 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
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
@@ -6582,14 +6602,27 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
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;
}
OpenPOWER on IntegriCloud