Skip to content

Commit 4007de0

Browse files
authored
Enable unnecessary-virtual-specifier by default (#133265)
This turns on the unnecessary-virtual-specifier warning in general, but disables it when building LLVM. It also tweaks the warning description to be slightly more accurate. Background: I've been working on cleaning up this warning in two codebases: LLVM and chromium (plus its dependencies). The chromium cleanup has been straightforward. Git archaeology shows that there are two reasons for the warnings: classes to which `final` was added after they were initially committed, and classes with virtual destructors that nobody remarks on. Presumably the latter case is because people are just very used to destructors being virtual. The LLVM cleanup was more surprising: I discovered that we have an [old policy](https://llvm.org/docs/CodingStandards.html#provide-a-virtual-method-anchor-for-classes-in-headers) about including out-of-line virtual functions in every class with a vtable, even `final` ones. This means our codebase has many virtual "anchor" functions which do nothing except control where the vtable is emitted, and which trigger the warning. I looked into alternatives to satisfy the policy, such as using destructors instead of introducing a new function, but it wasn't clear if they had larger implications. Overall, it seems like the warning is genuinely useful in most codebases (evidenced by chromium and its dependencies), and LLVM is an unusual case. Therefore we should enable the warning by default, and turn it off only for LLVM builds.
1 parent a61cc1b commit 4007de0

File tree

7 files changed

+16
-9
lines changed

7 files changed

+16
-9
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

+3-4
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,12 @@ def CXX11WarnSuggestOverride : DiagGroup<"suggest-override">;
377377
def WarnUnnecessaryVirtualSpecifier : DiagGroup<"unnecessary-virtual-specifier"> {
378378
code Documentation = [{
379379
Warns when a ``final`` class contains a virtual method (including virtual
380-
destructors). Since ``final`` classes cannot be subclassed, their methods
381-
cannot be overridden, and hence the ``virtual`` specifier is useless.
380+
destructors) that does not override anything. Since ``final`` classes cannot be
381+
subclassed, their methods cannot be overridden, so there is no point to
382+
introducing new ``virtual`` methods.
382383

383384
The warning also detects virtual methods in classes whose destructor is
384385
``final``, for the same reason.
385-
386-
The warning does not fire on virtual methods which are also marked ``override``.
387386
}];
388387
}
389388

clang/include/clang/Basic/DiagnosticSemaKinds.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -2733,7 +2733,7 @@ def note_final_dtor_non_final_class_silence : Note<
27332733
"mark %0 as '%select{final|sealed}1' to silence this warning">;
27342734
def warn_unnecessary_virtual_specifier : Warning<
27352735
"virtual method %0 is inside a 'final' class and can never be overridden">,
2736-
InGroup<WarnUnnecessaryVirtualSpecifier>, DefaultIgnore;
2736+
InGroup<WarnUnnecessaryVirtualSpecifier>;
27372737

27382738
// C++11 attributes
27392739
def err_repeat_attribute : Error<"%0 attribute cannot be repeated">;

clang/test/Analysis/Checkers/WebKit/ref-cntbl-crtp-base-no-virtual-dtor.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s -Wno-unnecessary-virtual-specifier
22

33
#include "mock-types.h"
44

clang/test/CXX/class/p2-0x.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct C : A<int> { }; // expected-error {{base 'A' is marked 'final'}}
2828

2929
namespace Test4 {
3030

31-
struct A final { virtual void func() = 0; }; // expected-warning {{abstract class is marked 'final'}} expected-note {{unimplemented pure virtual method 'func' in 'A'}}
31+
struct A final { virtual void func() = 0; }; // expected-warning {{abstract class is marked 'final'}} expected-note {{unimplemented pure virtual method 'func' in 'A'}} expected-warning {{virtual method 'func' is inside a 'final' class}}}
3232
struct B { virtual void func() = 0; }; // expected-note {{unimplemented pure virtual method 'func' in 'C'}}
3333

3434
struct C final : B { }; // expected-warning {{abstract class is marked 'final'}}

clang/test/SemaCXX/MicrosoftExtensions.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ struct InheritFromSealed : SealedType {};
470470
class SealedDestructor { // expected-note {{mark 'SealedDestructor' as 'sealed' to silence this warning}}
471471
// expected-warning@+1 {{'sealed' keyword is a Microsoft extension}}
472472
virtual ~SealedDestructor() sealed; // expected-warning {{class with destructor marked 'sealed' cannot be inherited from}}
473+
// expected-warning@-1 {{virtual method '~SealedDestructor' is inside a 'final' class}}
473474
};
474475

475476
// expected-warning@+1 {{'abstract' keyword is a Microsoft extension}}

clang/test/SemaCXX/warn-final-dtor-non-final-class.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -Wfinal-dtor-non-final-class
2-
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -Wfinal-dtor-non-final-class -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
1+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -Wfinal-dtor-non-final-class -Wno-unnecessary-virtual-specifier
2+
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -Wfinal-dtor-non-final-class -Wno-unnecessary-virtual-specifier \
3+
// RUN: -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
34

45
class A {
56
~A();

llvm/cmake/modules/HandleLLVMOptions.cmake

+6
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,12 @@ endif( LLVM_COMPILER_IS_GCC_COMPATIBLE OR CMAKE_CXX_COMPILER_ID MATCHES "XL" )
690690

691691
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
692692
append("-Werror=unguarded-availability-new" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
693+
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 21.0)
694+
# LLVM has a policy of including virtual "anchor" functions to control
695+
# where the vtable is emitted. In `final` classes, these are exactly what
696+
# this warning detects: unnecessary virtual methods.
697+
append("-Wno-unnecessary-virtual-specifier" CMAKE_CXX_FLAGS)
698+
endif()
693699
endif()
694700

695701
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND LLVM_ENABLE_LTO)

0 commit comments

Comments
 (0)