Skip to content

Commit 4d5b0be

Browse files
committed
Add AllowFalseEvaluated to clang-tidy noexcept-move-constructor check
1 parent f09fd94 commit 4d5b0be

File tree

5 files changed

+86
-2
lines changed

5 files changed

+86
-2
lines changed

clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ void NoexceptFunctionBaseCheck::check(const MatchFinder::MatchResult &Result) {
3030
const Expr *NoexceptExpr = ProtoType->getNoexceptExpr();
3131
if (NoexceptExpr) {
3232
NoexceptExpr = NoexceptExpr->IgnoreImplicit();
33-
if (!isa<CXXBoolLiteralExpr>(NoexceptExpr))
33+
if (!isa<CXXBoolLiteralExpr>(NoexceptExpr) && !AllowFalseEvaluated)
3434
reportNoexceptEvaluatedToFalse(FuncDecl, NoexceptExpr);
3535
return;
3636
}

clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ namespace clang::tidy::performance {
2222
class NoexceptFunctionBaseCheck : public ClangTidyCheck {
2323
public:
2424
NoexceptFunctionBaseCheck(StringRef Name, ClangTidyContext *Context)
25-
: ClangTidyCheck(Name, Context) {}
25+
: ClangTidyCheck(Name, Context)
26+
, AllowFalseEvaluated(Options.getLocalOrGlobal("AllowFalseEvaluated", false)) {}
2627

2728
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
2829
return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions;
@@ -33,6 +34,10 @@ class NoexceptFunctionBaseCheck : public ClangTidyCheck {
3334
return TK_IgnoreUnlessSpelledInSource;
3435
}
3536

37+
void storeOptions(ClangTidyOptions::OptionMap &Opts) override {
38+
Options.store(Opts, "AllowFalseEvaluated", AllowFalseEvaluated);
39+
}
40+
3641
protected:
3742
virtual DiagnosticBuilder
3843
reportMissingNoexcept(const FunctionDecl *FuncDecl) = 0;
@@ -42,6 +47,7 @@ class NoexceptFunctionBaseCheck : public ClangTidyCheck {
4247
static constexpr StringRef BindFuncDeclName = "FuncDecl";
4348

4449
private:
50+
bool AllowFalseEvaluated;
4551
utils::ExceptionSpecAnalyzer SpecAnalyzer;
4652
};
4753

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ Changes in existing checks
110110
<clang-tidy/checks/misc/redundant-expression>` check by providing additional
111111
examples and fixing some macro related false positives.
112112

113+
- Improved :doc:`performance-noexcept-move-constructor
114+
<clang-tidy/checks/performance/noexcept-move-constructor>` check by adding
115+
a new (off-by-default) option `AllowFalseEvaluated`, which allows marking
116+
move constructors with ``noexcept(expr)`` even if ``expr``
117+
evaluates to ``false``.
118+
113119
Removed checks
114120
^^^^^^^^^^^^^^
115121

clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,12 @@ evaluates to ``false`` (but is not a ``false`` literal itself).
1111
Move constructors of all the types used with STL containers, for example,
1212
need to be declared ``noexcept``. Otherwise STL will choose copy constructors
1313
instead. The same is valid for move assignment operations.
14+
15+
Options
16+
-------
17+
18+
.. option:: AllowFalseEvaluated
19+
20+
When `true`, the check will not generate any warning
21+
if the ``expr`` in ``noexcept(expr)`` evaluates to ``false``.
22+
Default is `false`.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions
2+
3+
// RUN: %check_clang_tidy -check-suffix=CONFIG %s performance-noexcept-move-constructor,performance-noexcept-destructor %t -- \
4+
// RUN: -config="{CheckOptions: {performance-noexcept-move-constructor.AllowFalseEvaluated: true}}" \
5+
// RUN: -- -fexceptions
6+
7+
namespace std
8+
{
9+
template <typename T>
10+
struct is_nothrow_move_constructible
11+
{
12+
static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T));
13+
};
14+
} // namespace std
15+
16+
struct ThrowOnAnything {
17+
ThrowOnAnything() noexcept(false);
18+
ThrowOnAnything(ThrowOnAnything&&) noexcept(false);
19+
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept
20+
// CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:3: warning: move constructors should be marked noexcept
21+
ThrowOnAnything& operator=(ThrowOnAnything &&) noexcept(false);
22+
~ThrowOnAnything() noexcept(false);
23+
};
24+
25+
struct C_1 {
26+
static constexpr bool kFalse = false;
27+
C_1(C_1&&) noexcept(kFalse) = default;
28+
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
29+
// CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
30+
31+
C_1 &operator=(C_1 &&) noexcept(kFalse);
32+
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
33+
// CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
34+
};
35+
36+
struct C_2 {
37+
static constexpr bool kEval = std::is_nothrow_move_constructible<ThrowOnAnything>::value;
38+
static_assert(!kEval); // kEval == false;
39+
40+
C_2(C_2&&) noexcept(kEval) = default;
41+
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
42+
// CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
43+
44+
C_2 &operator=(C_2 &&) noexcept(kEval);
45+
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
46+
// CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
47+
48+
ThrowOnAnything field;
49+
};
50+
51+
struct C_3 {
52+
static constexpr bool kEval = std::is_nothrow_move_constructible<ThrowOnAnything>::value;
53+
static_assert(!kEval); // kEval == false;
54+
55+
C_3(C_3&&) noexcept(kEval) = default;
56+
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
57+
// CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
58+
59+
~C_3() noexcept(kEval) = default;
60+
// CHECK-MESSAGES-CONFIG: :[[@LINE-1]]:21: warning: noexcept specifier on the destructor evaluates to 'false'
61+
62+
ThrowOnAnything field;
63+
};

0 commit comments

Comments
 (0)