Skip to content

Commit 1111678

Browse files
kepler-5dwblaikie
authored andcommitted
[clang] Add -Wsuggest-override
This patch adds `-Wsuggest-override`, which allows for more aggressive enforcement of modern C++ best practices, as well as better compatibility with gcc, which has had its own `-Wsuggest-override` since version 5.1. Clang already has `-Winconsistent-missing-override`, which only warns in the case where there is at least one function already marked `override` in a class. This warning strengthens that warning by suggesting the `override` keyword regardless of whether it is already present anywhere. The text between suggest-override and inconsistent-missing-override is now shared, using `TextSubstitution` for the entire diagnostic text. Reviewed By: dblaikie Differential Revision: https://reviews.llvm.org/D82728
1 parent c73f425 commit 1111678

File tree

6 files changed

+107
-22
lines changed

6 files changed

+107
-22
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,12 @@ def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
280280

281281
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
282282

283-
def CXX11WarnOverrideDestructor :
283+
def CXX11WarnInconsistentOverrideDestructor :
284284
DiagGroup<"inconsistent-missing-destructor-override">;
285-
def CXX11WarnOverrideMethod : DiagGroup<"inconsistent-missing-override">;
285+
def CXX11WarnInconsistentOverrideMethod :
286+
DiagGroup<"inconsistent-missing-override">;
287+
def CXX11WarnSuggestOverrideDestructor : DiagGroup<"suggest-destructor-override">;
288+
def CXX11WarnSuggestOverride : DiagGroup<"suggest-override">;
286289

287290
// Original name of this warning in Clang
288291
def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2367,12 +2367,22 @@ def override_keyword_hides_virtual_member_function : Error<
23672367
"%select{function|functions}1">;
23682368
def err_function_marked_override_not_overriding : Error<
23692369
"%0 marked 'override' but does not override any member functions">;
2370-
def warn_destructor_marked_not_override_overriding : Warning <
2371-
"%0 overrides a destructor but is not marked 'override'">,
2372-
InGroup<CXX11WarnOverrideDestructor>, DefaultIgnore;
2373-
def warn_function_marked_not_override_overriding : Warning <
2374-
"%0 overrides a member function but is not marked 'override'">,
2375-
InGroup<CXX11WarnOverrideMethod>;
2370+
def warn_destructor_marked_not_override_overriding : TextSubstitution <
2371+
"%0 overrides a destructor but is not marked 'override'">;
2372+
def warn_function_marked_not_override_overriding : TextSubstitution <
2373+
"%0 overrides a member function but is not marked 'override'">;
2374+
def warn_inconsistent_destructor_marked_not_override_overriding : Warning <
2375+
"%sub{warn_destructor_marked_not_override_overriding}0">,
2376+
InGroup<CXX11WarnInconsistentOverrideDestructor>, DefaultIgnore;
2377+
def warn_inconsistent_function_marked_not_override_overriding : Warning <
2378+
"%sub{warn_function_marked_not_override_overriding}0">,
2379+
InGroup<CXX11WarnInconsistentOverrideMethod>;
2380+
def warn_suggest_destructor_marked_not_override_overriding : Warning <
2381+
"%sub{warn_destructor_marked_not_override_overriding}0">,
2382+
InGroup<CXX11WarnSuggestOverrideDestructor>, DefaultIgnore;
2383+
def warn_suggest_function_marked_not_override_overriding : Warning <
2384+
"%sub{warn_function_marked_not_override_overriding}0">,
2385+
InGroup<CXX11WarnSuggestOverride>, DefaultIgnore;
23762386
def err_class_marked_final_used_as_base : Error<
23772387
"base %0 is marked '%select{final|sealed}1'">;
23782388
def warn_abstract_final_class : Warning<

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6965,7 +6965,7 @@ class Sema final {
69656965

69666966
/// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was
69676967
/// not used in the declaration of an overriding method.
6968-
void DiagnoseAbsenceOfOverrideControl(NamedDecl *D);
6968+
void DiagnoseAbsenceOfOverrideControl(NamedDecl *D, bool Inconsistent);
69696969

69706970
/// CheckForFunctionMarkedFinal - Checks whether a virtual member function
69716971
/// overrides a virtual member function marked 'final', according to

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3045,7 +3045,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) {
30453045
<< MD->getDeclName();
30463046
}
30473047

3048-
void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
3048+
void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D, bool Inconsistent) {
30493049
if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>())
30503050
return;
30513051
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D);
@@ -3061,12 +3061,22 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) {
30613061
return;
30623062

30633063
if (MD->size_overridden_methods() > 0) {
3064-
unsigned DiagID = isa<CXXDestructorDecl>(MD)
3065-
? diag::warn_destructor_marked_not_override_overriding
3066-
: diag::warn_function_marked_not_override_overriding;
3067-
Diag(MD->getLocation(), DiagID) << MD->getDeclName();
3068-
const CXXMethodDecl *OMD = *MD->begin_overridden_methods();
3069-
Diag(OMD->getLocation(), diag::note_overridden_virtual_function);
3064+
auto EmitDiag = [&](unsigned DiagInconsistent, unsigned DiagSuggest) {
3065+
unsigned DiagID =
3066+
Inconsistent && !Diags.isIgnored(DiagInconsistent, MD->getLocation())
3067+
? DiagInconsistent
3068+
: DiagSuggest;
3069+
Diag(MD->getLocation(), DiagID) << MD->getDeclName();
3070+
const CXXMethodDecl *OMD = *MD->begin_overridden_methods();
3071+
Diag(OMD->getLocation(), diag::note_overridden_virtual_function);
3072+
};
3073+
if (isa<CXXDestructorDecl>(MD))
3074+
EmitDiag(
3075+
diag::warn_inconsistent_destructor_marked_not_override_overriding,
3076+
diag::warn_suggest_destructor_marked_not_override_overriding);
3077+
else
3078+
EmitDiag(diag::warn_inconsistent_function_marked_not_override_overriding,
3079+
diag::warn_suggest_function_marked_not_override_overriding);
30703080
}
30713081
}
30723082

@@ -6749,13 +6759,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
67496759
}
67506760
}
67516761

6752-
if (HasMethodWithOverrideControl &&
6753-
HasOverridingMethodWithoutOverrideControl) {
6754-
// At least one method has the 'override' control declared.
6755-
// Diagnose all other overridden methods which do not have 'override'
6756-
// specified on them.
6762+
if (HasOverridingMethodWithoutOverrideControl) {
6763+
bool HasInconsistentOverrideControl = HasMethodWithOverrideControl;
67576764
for (auto *M : Record->methods())
6758-
DiagnoseAbsenceOfOverrideControl(M);
6765+
DiagnoseAbsenceOfOverrideControl(M, HasInconsistentOverrideControl);
67596766
}
67606767

67616768
// Check the defaulted secondary comparisons after any other member functions.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -Wsuggest-destructor-override
2+
3+
struct A {
4+
~A();
5+
virtual void run();
6+
};
7+
8+
struct B : public A {
9+
~B();
10+
};
11+
12+
struct C {
13+
virtual void run();
14+
virtual ~C(); // expected-note 2{{overridden virtual function is here}}
15+
};
16+
17+
struct D : public C {
18+
void run();
19+
~D();
20+
// expected-warning@-1 {{'~D' overrides a destructor but is not marked 'override'}}
21+
};
22+
23+
struct E : public C {
24+
void run();
25+
virtual ~E();
26+
// expected-warning@-1 {{'~E' overrides a destructor but is not marked 'override'}}
27+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify -Wsuggest-override
2+
3+
struct A {
4+
~A();
5+
void run();
6+
};
7+
8+
struct B : public A {
9+
~B();
10+
void run();
11+
};
12+
13+
struct C {
14+
virtual void run(); // expected-note 2{{overridden virtual function is here}}
15+
virtual ~C();
16+
};
17+
18+
struct D : public C {
19+
void run();
20+
// expected-warning@-1 {{'run()' overrides a member function but is not marked 'override'}}
21+
~D();
22+
};
23+
24+
struct E : public C {
25+
virtual void run();
26+
// expected-warning@-1 {{'run()' overrides a member function but is not marked 'override'}}
27+
virtual ~E();
28+
};
29+
30+
struct F : public C {
31+
void run() override;
32+
~F() override;
33+
};
34+
35+
struct G : public C {
36+
void run() final;
37+
~G() final;
38+
};

0 commit comments

Comments
 (0)