Skip to content

Commit 9975dc3

Browse files
committed
Defer checking for mismatches between the deletedness of and overriding
function and an overridden function until we know whether the overriding function is deleted. We previously did these checks when we first built the declaration, which was too soon in some cases. We now defer all these checks to the end of the class. Also add missing check that a consteval function cannot override a non-consteval function and vice versa.
1 parent 2a2d242 commit 9975dc3

File tree

9 files changed

+176
-100
lines changed

9 files changed

+176
-100
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1509,9 +1509,12 @@ def err_deleted_decl_not_first : Error<
15091509

15101510
def err_deleted_override : Error<
15111511
"deleted function %0 cannot override a non-deleted function">;
1512-
15131512
def err_non_deleted_override : Error<
15141513
"non-deleted function %0 cannot override a deleted function">;
1514+
def err_consteval_override : Error<
1515+
"consteval function %0 cannot override a non-consteval function">;
1516+
def err_non_consteval_override : Error<
1517+
"non-consteval function %0 cannot override a consteval function">;
15151518

15161519
def warn_weak_vtable : Warning<
15171520
"%0 has no out-of-line virtual method definitions; its vtable will be "

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8032,30 +8032,8 @@ struct FindOverriddenMethod {
80328032
return false;
80338033
}
80348034
};
8035-
8036-
enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted };
80378035
} // end anonymous namespace
80388036

8039-
/// Report an error regarding overriding, along with any relevant
8040-
/// overridden methods.
8041-
///
8042-
/// \param DiagID the primary error to report.
8043-
/// \param MD the overriding method.
8044-
/// \param OEK which overrides to include as notes.
8045-
static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD,
8046-
OverrideErrorKind OEK = OEK_All) {
8047-
S.Diag(MD->getLocation(), DiagID) << MD->getDeclName();
8048-
for (const CXXMethodDecl *O : MD->overridden_methods()) {
8049-
// This check (& the OEK parameter) could be replaced by a predicate, but
8050-
// without lambdas that would be overkill. This is still nicer than writing
8051-
// out the diag loop 3 times.
8052-
if ((OEK == OEK_All) ||
8053-
(OEK == OEK_NonDeleted && !O->isDeleted()) ||
8054-
(OEK == OEK_Deleted && O->isDeleted()))
8055-
S.Diag(O->getLocation(), diag::note_overridden_virtual_function);
8056-
}
8057-
}
8058-
80598037
/// AddOverriddenMethods - See if a method overrides any in the base classes,
80608038
/// and if so, check that it's a valid override and remember it.
80618039
bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
@@ -8064,8 +8042,6 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
80648042
FindOverriddenMethod FOM;
80658043
FOM.Method = MD;
80668044
FOM.S = this;
8067-
bool hasDeletedOverridenMethods = false;
8068-
bool hasNonDeletedOverridenMethods = false;
80698045
bool AddedAny = false;
80708046
if (DC->lookupInBases(FOM, Paths)) {
80718047
for (auto *I : Paths.found_decls()) {
@@ -8075,21 +8051,12 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
80758051
!CheckOverridingFunctionAttributes(MD, OldMD) &&
80768052
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
80778053
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
8078-
hasDeletedOverridenMethods |= OldMD->isDeleted();
8079-
hasNonDeletedOverridenMethods |= !OldMD->isDeleted();
80808054
AddedAny = true;
80818055
}
80828056
}
80838057
}
80848058
}
80858059

8086-
if (hasDeletedOverridenMethods && !MD->isDeleted()) {
8087-
ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted);
8088-
}
8089-
if (hasNonDeletedOverridenMethods && MD->isDeleted()) {
8090-
ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted);
8091-
}
8092-
80938060
return AddedAny;
80948061
}
80958062

@@ -9095,8 +9062,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
90959062
}
90969063

90979064
// If a function is defined as defaulted or deleted, mark it as such now.
9098-
// FIXME: Does this ever happen? ActOnStartOfFunctionDef forces the function
9099-
// definition kind to FDK_Definition.
9065+
// We'll do the relevant checks on defaulted / deleted functions later.
91009066
switch (D.getFunctionDefinitionKind()) {
91019067
case FDK_Declaration:
91029068
case FDK_Definition:
@@ -10745,12 +10711,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1074510711
if (!Method->isFunctionTemplateSpecialization() &&
1074610712
!Method->getDescribedFunctionTemplate() &&
1074710713
Method->isCanonicalDecl()) {
10748-
if (AddOverriddenMethods(Method->getParent(), Method)) {
10749-
// If the function was marked as "static", we have a problem.
10750-
if (NewFD->getStorageClass() == SC_Static) {
10751-
ReportOverrides(*this, diag::err_static_overrides_virtual, Method);
10752-
}
10753-
}
10714+
AddOverriddenMethods(Method->getParent(), Method);
1075410715
}
1075510716
if (Method->isVirtual() && NewFD->getTrailingRequiresClause())
1075610717
// C++2a [class.virtual]p6

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 98 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6172,27 +6172,31 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) {
61726172
return DefaultedFunctionKind();
61736173
}
61746174

6175-
static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
6176-
SourceLocation DefaultLoc) {
6177-
switch (S.getSpecialMember(MD)) {
6175+
static void DefineDefaultedFunction(Sema &S, FunctionDecl *FD,
6176+
SourceLocation DefaultLoc) {
6177+
Sema::DefaultedFunctionKind DFK = S.getDefaultedFunctionKind(FD);
6178+
if (DFK.isComparison())
6179+
return S.DefineDefaultedComparison(DefaultLoc, FD, DFK.asComparison());
6180+
6181+
switch (DFK.asSpecialMember()) {
61786182
case Sema::CXXDefaultConstructor:
61796183
S.DefineImplicitDefaultConstructor(DefaultLoc,
6180-
cast<CXXConstructorDecl>(MD));
6184+
cast<CXXConstructorDecl>(FD));
61816185
break;
61826186
case Sema::CXXCopyConstructor:
6183-
S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
6187+
S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD));
61846188
break;
61856189
case Sema::CXXCopyAssignment:
6186-
S.DefineImplicitCopyAssignment(DefaultLoc, MD);
6190+
S.DefineImplicitCopyAssignment(DefaultLoc, cast<CXXMethodDecl>(FD));
61876191
break;
61886192
case Sema::CXXDestructor:
6189-
S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD));
6193+
S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(FD));
61906194
break;
61916195
case Sema::CXXMoveConstructor:
6192-
S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
6196+
S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD));
61936197
break;
61946198
case Sema::CXXMoveAssignment:
6195-
S.DefineImplicitMoveAssignment(DefaultLoc, MD);
6199+
S.DefineImplicitMoveAssignment(DefaultLoc, cast<CXXMethodDecl>(FD));
61966200
break;
61976201
case Sema::CXXInvalid:
61986202
llvm_unreachable("Invalid special member.");
@@ -6313,6 +6317,28 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
63136317
return HasNonDeletedCopyOrMove;
63146318
}
63156319

6320+
/// Report an error regarding overriding, along with any relevant
6321+
/// overridden methods.
6322+
///
6323+
/// \param DiagID the primary error to report.
6324+
/// \param MD the overriding method.
6325+
/// \param OEK which overrides to include as notes.
6326+
static bool
6327+
ReportOverrides(Sema &S, unsigned DiagID, const CXXMethodDecl *MD,
6328+
llvm::function_ref<bool(const CXXMethodDecl *)> Report) {
6329+
bool IssuedDiagnostic = false;
6330+
for (const CXXMethodDecl *O : MD->overridden_methods()) {
6331+
if (Report(O)) {
6332+
if (!IssuedDiagnostic) {
6333+
S.Diag(MD->getLocation(), DiagID) << MD->getDeclName();
6334+
IssuedDiagnostic = true;
6335+
}
6336+
S.Diag(O->getLocation(), diag::note_overridden_virtual_function);
6337+
}
6338+
}
6339+
return IssuedDiagnostic;
6340+
}
6341+
63166342
/// Perform semantic checks on a class definition that has been
63176343
/// completing, introducing implicitly-declared members, checking for
63186344
/// abstract types, etc.
@@ -6427,21 +6453,64 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
64276453
// primary comparison functions (==, <=>).
64286454
llvm::SmallVector<FunctionDecl*, 5> DefaultedSecondaryComparisons;
64296455

6430-
auto CheckForDefaultedFunction = [&](FunctionDecl *FD) {
6431-
if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted())
6456+
// Perform checks that can't be done until we know all the properties of a
6457+
// member function (whether it's defaulted, deleted, virtual, overriding,
6458+
// ...).
6459+
auto CheckCompletedMemberFunction = [&](CXXMethodDecl *MD) {
6460+
// A static function cannot override anything.
6461+
if (MD->getStorageClass() == SC_Static) {
6462+
if (ReportOverrides(*this, diag::err_static_overrides_virtual, MD,
6463+
[](const CXXMethodDecl *) { return true; }))
6464+
return;
6465+
}
6466+
6467+
// A deleted function cannot override a non-deleted function and vice
6468+
// versa.
6469+
if (ReportOverrides(*this,
6470+
MD->isDeleted() ? diag::err_deleted_override
6471+
: diag::err_non_deleted_override,
6472+
MD, [&](const CXXMethodDecl *V) {
6473+
return MD->isDeleted() != V->isDeleted();
6474+
})) {
6475+
if (MD->isDefaulted() && MD->isDeleted())
6476+
// Explain why this defaulted function was deleted.
6477+
DiagnoseDeletedDefaultedFunction(MD);
64326478
return;
6479+
}
6480+
6481+
// A consteval function cannot override a non-consteval function and vice
6482+
// versa.
6483+
if (ReportOverrides(*this,
6484+
MD->isConsteval() ? diag::err_consteval_override
6485+
: diag::err_non_consteval_override,
6486+
MD, [&](const CXXMethodDecl *V) {
6487+
return MD->isConsteval() != V->isConsteval();
6488+
})) {
6489+
if (MD->isDefaulted() && MD->isDeleted())
6490+
// Explain why this defaulted function was deleted.
6491+
DiagnoseDeletedDefaultedFunction(MD);
6492+
return;
6493+
}
6494+
};
6495+
6496+
auto CheckForDefaultedFunction = [&](FunctionDecl *FD) -> bool {
6497+
if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted())
6498+
return false;
64336499

64346500
DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD);
64356501
if (DFK.asComparison() == DefaultedComparisonKind::NotEqual ||
6436-
DFK.asComparison() == DefaultedComparisonKind::Relational)
6502+
DFK.asComparison() == DefaultedComparisonKind::Relational) {
64376503
DefaultedSecondaryComparisons.push_back(FD);
6438-
else
6439-
CheckExplicitlyDefaultedFunction(S, FD);
6504+
return true;
6505+
}
6506+
6507+
CheckExplicitlyDefaultedFunction(S, FD);
6508+
return false;
64406509
};
64416510

64426511
auto CompleteMemberFunction = [&](CXXMethodDecl *M) {
64436512
// Check whether the explicitly-defaulted members are valid.
6444-
CheckForDefaultedFunction(M);
6513+
bool Incomplete = CheckForDefaultedFunction(M);
64456514

64466515
// Skip the rest of the checks for a member of a dependent class.
64476516
if (Record->isDependentType())
@@ -6488,7 +6557,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
64886557
// function right away.
64896558
// FIXME: We can defer doing this until the vtable is marked as used.
64906559
if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods())
6491-
DefineImplicitSpecialMember(*this, M, M->getLocation());
6560+
DefineDefaultedFunction(*this, M, M->getLocation());
6561+
6562+
if (!Incomplete)
6563+
CheckCompletedMemberFunction(M);
64926564
};
64936565

64946566
// Check the destructor before any other member function. We need to
@@ -6534,9 +6606,14 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
65346606
}
65356607

65366608
// Check the defaulted secondary comparisons after any other member functions.
6537-
for (FunctionDecl *FD : DefaultedSecondaryComparisons)
6609+
for (FunctionDecl *FD : DefaultedSecondaryComparisons) {
65386610
CheckExplicitlyDefaultedFunction(S, FD);
65396611

6612+
// If this is a member function, we deferred checking it until now.
6613+
if (auto *MD = dyn_cast<CXXMethodDecl>(FD))
6614+
CheckCompletedMemberFunction(MD);
6615+
}
6616+
65406617
// ms_struct is a request to use the same ABI rules as MSVC. Check
65416618
// whether this class uses any C++ features that are implemented
65426619
// completely differently in MSVC, and if so, emit a diagnostic.
@@ -13023,7 +13100,7 @@ void Sema::ActOnFinishCXXNonNestedClass() {
1302313100
SmallVector<CXXMethodDecl*, 4> WorkList;
1302413101
std::swap(DelayedDllExportMemberFunctions, WorkList);
1302513102
for (CXXMethodDecl *M : WorkList) {
13026-
DefineImplicitSpecialMember(*this, M, M->getLocation());
13103+
DefineDefaultedFunction(*this, M, M->getLocation());
1302713104

1302813105
// Pass the method to the consumer to get emitted. This is not necessary
1302913106
// for explicit instantiation definitions, as they will get emitted
@@ -16368,9 +16445,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
1636816445
Fn->setInvalidDecl();
1636916446
}
1637016447

16371-
if (Fn->isDeleted())
16372-
return;
16373-
1637416448
// C++11 [basic.start.main]p3:
1637516449
// A program that defines main as deleted [...] is ill-formed.
1637616450
if (Fn->isMain())
@@ -16380,25 +16454,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
1638016454
// A deleted function is implicitly inline.
1638116455
Fn->setImplicitlyInline();
1638216456
Fn->setDeletedAsWritten();
16383-
16384-
// See if we're deleting a function which is already known to override a
16385-
// non-deleted virtual function.
16386-
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
16387-
bool IssuedDiagnostic = false;
16388-
for (const CXXMethodDecl *O : MD->overridden_methods()) {
16389-
if (!(*MD->begin_overridden_methods())->isDeleted()) {
16390-
if (!IssuedDiagnostic) {
16391-
Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName();
16392-
IssuedDiagnostic = true;
16393-
}
16394-
Diag(O->getLocation(), diag::note_overridden_virtual_function);
16395-
}
16396-
}
16397-
// If this function was implicitly deleted because it was defaulted,
16398-
// explain why it was deleted.
16399-
if (IssuedDiagnostic && MD->isDefaulted())
16400-
DiagnoseDeletedDefaultedFunction(MD);
16401-
}
1640216457
}
1640316458

1640416459
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
@@ -16480,10 +16535,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
1648016535
if (Primary->getCanonicalDecl()->isDefaulted())
1648116536
return;
1648216537

16538+
// FIXME: Once we support defining comparisons out of class, check for a
16539+
// defaulted comparison here.
1648316540
if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
1648416541
MD->setInvalidDecl();
1648516542
else
16486-
DefineImplicitSpecialMember(*this, MD, DefaultLoc);
16543+
DefineDefaultedFunction(*this, MD, DefaultLoc);
1648716544
}
1648816545

1648916546
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {

clang/test/CXX/class.derived/class.abstract/p16.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,13 @@ struct E : D {};
3535
// expected-error@-1 {{deleted function '~E' cannot override a non-deleted function}}
3636
// expected-note@-2 {{destructor of 'E' is implicitly deleted because base class 'D' has an inaccessible destructor}}
3737
// expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
38-
// expected-note@-4 {{while declaring the implicit copy assignment operator for 'E'}}
39-
// expected-note@-5 {{copy assignment operator of 'E' is implicitly deleted because base class 'D' has an inaccessible copy assignment operator}}
38+
// expected-note@-4 {{copy assignment operator of 'E' is implicitly deleted because base class 'D' has an inaccessible copy assignment operator}}
4039
struct F : D {};
4140
struct G : D {};
4241
// expected-error@-1 {{deleted function '~G' cannot override a non-deleted function}}
4342
// expected-note@-2 {{destructor of 'G' is implicitly deleted because base class 'D' has an inaccessible destructor}}
4443
// expected-error@-3 {{deleted function 'operator=' cannot override a non-deleted function}}
45-
// expected-note@-4 {{while declaring the implicit move assignment operator for 'G'}}
46-
// expected-note@-5 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
44+
// expected-note@-4 {{move assignment operator of 'G' is implicitly deleted because base class 'D' has an inaccessible move assignment operator}}
4745
struct H : D { // expected-note {{deleted because base class 'D' has an inaccessible move assignment}}
4846
H &operator=(H&&) = default; // expected-warning {{implicitly deleted}}
4947
// expected-error@-1 {{deleted function 'operator=' cannot override a non-deleted function}}

clang/test/CXX/special/class.dtor/p5-0x.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ struct C4 : virtual InaccessibleDtor { C4(); } c4; // expected-error {{deleted f
8686
// -- for a virtual destructor, lookup of the non-array deallocation function
8787
// results in an ambiguity or a function that is deleted or inaccessible.
8888
class D1 {
89-
void operator delete(void*);
89+
void operator delete(void*); // expected-note {{here}}
9090
public:
91-
virtual ~D1() = default; // expected-note {{here}}
91+
virtual ~D1() = default; // expected-note 2{{here}}
9292
} d1; // ok
9393
struct D2 : D1 { // expected-note 2{{virtual destructor requires an unambiguous, accessible 'operator delete'}} \
9494
// expected-error {{deleted function '~D2' cannot override a non-deleted}}
@@ -103,3 +103,10 @@ struct D4 { // expected-note {{virtual destructor requires an unambiguous, acces
103103
virtual ~D4() = default; // expected-note {{implicitly deleted here}}
104104
void operator delete(void*) = delete;
105105
} d4; // expected-error {{deleted function}}
106+
struct D5 : D1 {
107+
~D5(); // ok (but not definable)
108+
} d5;
109+
D5::~D5() {} // expected-error {{'operator delete' is a private member of 'D1'}}
110+
struct D6 : D1 {
111+
~D6() = delete; // expected-error {{deleted function '~D6' cannot override a non-deleted}}
112+
};

clang/test/SemaCXX/PR9572.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ struct Foo : public Base {
1616
// expected-error@-2 {{base class 'Base' has private destructor}}
1717
#else
1818
// expected-error@-4 {{deleted function '~Foo' cannot override a non-deleted function}}
19-
// expected-note@-5 {{overridden virtual function is here}}
20-
// expected-note@-6 3 {{destructor of 'Foo' is implicitly deleted because base class 'Base' has an inaccessible destructor}}
19+
// expected-note@-5 3{{destructor of 'Foo' is implicitly deleted because base class 'Base' has an inaccessible destructor}}
2120
#endif
2221

2322
const int kBlah = 3;
@@ -29,10 +28,6 @@ struct Foo : public Base {
2928
};
3029

3130
struct Bar : public Foo {
32-
#if __cplusplus >= 201103L
33-
// expected-error@-2 {{non-deleted function '~Bar' cannot override a deleted function}}
34-
// expected-note@-3 {{while declaring the implicit destructor for 'Bar'}}
35-
#endif
3631
Bar() { }
3732
#if __cplusplus <= 199711L
3833
// expected-note@-2 {{implicit destructor for 'Foo' first required here}}

clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,9 @@ struct DeletedMemberTemplateTooLate {
211211
};
212212
template<typename T> void DeletedMemberTemplateTooLate::f() = delete; // expected-error {{must be first decl}} expected-note {{substitution failure}}
213213
void use_member_template_deleted_too_late() { DeletedMemberTemplateTooLate::f<int>(); } // expected-error {{no matching function}}
214+
215+
namespace deleted_overrides_deleted {
216+
struct A { virtual void f() = delete; };
217+
template<typename T> struct B : A { virtual void f() = delete; };
218+
template struct B<int>;
219+
}

0 commit comments

Comments
 (0)