- Notifications
You must be signed in to change notification settings - Fork 15.3k
[clang-tidy] Add AllowFalseEvaluated flag to clang-tidy noexcept-move-constructor check #126897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[clang-tidy] Add AllowFalseEvaluated flag to clang-tidy noexcept-move-constructor check #126897
Conversation
| Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
| @llvm/pr-subscribers-clang-tools-extra @llvm/pr-subscribers-clang-tidy Author: Dmitry Nechitaev (Nechda) ChangesThis pull request aims to add a new flag to customize the Problem. Now the code below triggers the warning: #include <type_traits> /* External class */ struct NotMarkedNoexcept { int x; NotMarkedNoexcept() = default; // NOLINTNEXTLINE(performance-noexcept-move-constructor) NotMarkedNoexcept(NotMarkedNoexcept&& rhs); }; struct Complicated { static constexpr bool NOEXCEPT_MOVE = std::is_nothrow_move_constructible_v<NotMarkedNoexcept>; Complicated() = default; Complicated(Complicated&&) noexcept(NOEXCEPT_MOVE) = default; // Warning NotMarkedNoexcept inner; }; int main() {}https://godbolt.org/z/E4E65jdhh I had created a related issue: #126702 My proposal is to add an option to allow Full diff: https://github.com/llvm/llvm-project/pull/126897.diff 3 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp index 911cd1b533367..8371b6aafd8ba 100644 --- a/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp @@ -30,7 +30,7 @@ void NoexceptFunctionBaseCheck::check(const MatchFinder::MatchResult &Result) { const Expr *NoexceptExpr = ProtoType->getNoexceptExpr(); if (NoexceptExpr) { NoexceptExpr = NoexceptExpr->IgnoreImplicit(); - if (!isa<CXXBoolLiteralExpr>(NoexceptExpr)) + if (!isa<CXXBoolLiteralExpr>(NoexceptExpr) && !AllowFalseEvaluated) reportNoexceptEvaluatedToFalse(FuncDecl, NoexceptExpr); return; } diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.h index 4775219d7e439..cd1da1fbeca55 100644 --- a/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.h +++ b/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.h @@ -22,7 +22,8 @@ namespace clang::tidy::performance { class NoexceptFunctionBaseCheck : public ClangTidyCheck { public: NoexceptFunctionBaseCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + : ClangTidyCheck(Name, Context) + , AllowFalseEvaluated(Options.getLocalOrGlobal("AllowFalseEvaluated", false)) {} bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions; @@ -33,6 +34,10 @@ class NoexceptFunctionBaseCheck : public ClangTidyCheck { return TK_IgnoreUnlessSpelledInSource; } + void storeOptions(ClangTidyOptions::OptionMap &Opts) override { + Options.store(Opts, "AllowFalseEvaluated", AllowFalseEvaluated); + } + protected: virtual DiagnosticBuilder reportMissingNoexcept(const FunctionDecl *FuncDecl) = 0; @@ -42,6 +47,7 @@ class NoexceptFunctionBaseCheck : public ClangTidyCheck { static constexpr StringRef BindFuncDeclName = "FuncDecl"; private: + bool AllowFalseEvaluated; utils::ExceptionSpecAnalyzer SpecAnalyzer; }; diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-allow-false-evaluated.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-allow-false-evaluated.cpp new file mode 100644 index 0000000000000..3552eaa7c50ea --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-allow-false-evaluated.cpp @@ -0,0 +1,63 @@ +// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions + +// RUN: %check_clang_tidy -check-suffix=CONFIG %s performance-noexcept-move-constructor,performance-noexcept-destructor %t -- \ +// RUN: -config="{CheckOptions: {performance-noexcept-move-constructor.AllowFalseEvaluated: true}}" \ +// RUN: -- -fexceptions + +namespace std +{ + template <typename T> + struct is_nothrow_move_constructible + { + static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T)); + }; +} // namespace std + +struct ThrowOnAnything { + ThrowOnAnything() noexcept(false); + ThrowOnAnything(ThrowOnAnything&&) noexcept(false); + // CHECK-MESSAGES-NOT: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept + // CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:3: warning: move constructors should be marked noexcept + ThrowOnAnything& operator=(ThrowOnAnything &&) noexcept(false); + ~ThrowOnAnything() noexcept(false); +}; + +struct C_1 { + static constexpr bool kFalse = false; + C_1(C_1&&) noexcept(kFalse) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] + // CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] + + C_1 &operator=(C_1 &&) noexcept(kFalse); + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor] + // CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor] +}; + +struct C_2 { + static constexpr bool kEval = std::is_nothrow_move_constructible<ThrowOnAnything>::value; + static_assert(!kEval); // kEval == false; + + C_2(C_2&&) noexcept(kEval) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] + // CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] + + C_2 &operator=(C_2 &&) noexcept(kEval); + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor] + // CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:37: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor] + + ThrowOnAnything field; +}; + +struct C_3 { + static constexpr bool kEval = std::is_nothrow_move_constructible<ThrowOnAnything>::value; + static_assert(!kEval); // kEval == false; + + C_3(C_3&&) noexcept(kEval) = default; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] + // CHECK-MESSAGES-CONFIG-NOT: :[[@LINE-2]]:25: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] + + ~C_3() noexcept(kEval) = default; + // CHECK-MESSAGES-CONFIG: :[[@LINE-1]]:21: warning: noexcept specifier on the destructor evaluates to 'false' + + ThrowOnAnything field; +}; |
| Ask for review @PiotrZSL |
| Please mention changes in Release Notes and check documentation. |
clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst Outdated Show resolved Hide resolved
clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst Outdated Show resolved Hide resolved
clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst Outdated Show resolved Hide resolved
clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst Outdated Show resolved Hide resolved
6b9b6e4 to 4d5b0be Compare | I apologize for the spam in my emails. I am having some issues with the GitHub UI. The changes to the branch are only related to merging commits into one. |
| If you squash commits solely for merging into main - there is no need for it. They will be squashed automatically during merge. |
| Ping |
clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.h Outdated Show resolved Hide resolved
| | ||
| - Improved :doc:`performance-noexcept-move-constructor | ||
| <clang-tidy/checks/performance/noexcept-move-constructor>` check by adding | ||
| a new (off-by-default) option `AllowFalseEvaluated`, which allows marking |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally, we add "default is xxx" at the end of option description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, these changes are related to the release notes, not the option description.
The check's documentation has already satisfied your change request. Changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually we don't write default values of options in ReleaseNotes, you could remove it
4d5b0be to c0eecd1 Compare | ✅ With the latest revision this PR passed the C/C++ code formatter. |
| If you are happy with this change, please approve it and merge it. I do not have the necessary permissions to perform the merge operation. |
| Ping |
EugeneZelenko left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rebase from main. There are some changes in Release Notes.
vbvictor left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Nechda, gentle ping, do you still wish to work on this PR? 21th LLVM release will be soon, If you wish to have your changes in the upcoming release please rebase on main and fix suggestions.
...tra/test/clang-tidy/checkers/performance/noexcept-move-constructor-allow-false-evaluated.cpp Outdated Show resolved Hide resolved
...tra/test/clang-tidy/checkers/performance/noexcept-move-constructor-allow-false-evaluated.cpp Outdated Show resolved Hide resolved
| Yes, this PR is still alive. I'll rebase it. |
75e9e45 to 77ef35c Compare | I've rebased the branch, gentle pings to reviewers. |
vbvictor left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you de-facto added this option to performance-noexcept-destructor check too, please add it to performance-noexcept-destructor.rst docs (just copypaste), add to ReleaseNotes and add a separate test-file for noexcept destructors.
| public: | ||
| NoexceptFunctionBaseCheck(StringRef Name, ClangTidyContext *Context) | ||
| : ClangTidyCheck(Name, Context) {} | ||
| : ClangTidyCheck(Name, Context), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please place definition in .cpp file.
We usually define only isLanguageVersionSupported and getCheckTraversalKind in headers
| return TK_IgnoreUnlessSpelledInSource; | ||
| } | ||
| | ||
| void storeOptions(ClangTidyOptions::OptionMap &Opts) override { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please place definition in .cpp file
| <clang-tidy/checks/readability/redundant-smartptr-get>` check by fixing | ||
| some false positives involving smart pointers to arrays. | ||
| | ||
| - Improved :doc:`performance-noexcept-move-constructor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please place this in alphabetical order (by check name).
Should be placed after performance-move-const-arg.
| | ||
| - Improved :doc:`performance-noexcept-move-constructor | ||
| <clang-tidy/checks/performance/noexcept-move-constructor>` check by adding | ||
| a new (off-by-default) option `AllowFalseEvaluated`, which allows marking |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually we don't write default values of options in ReleaseNotes, you could remove it
| // CHECK-MESSAGES-CONFIG: :[[@LINE-1]]:21: warning: noexcept specifier on the destructor evaluates to 'false' | ||
| | ||
| ThrowOnAnything field; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test-case that basic functionality of the check is preserved - when there is no noexcept at all move-ctor is flagged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry, I don't quite understand what test case you are referring to. It looks like the default behavior of this check is already covered by another test case. https://github.com/llvm/llvm-project/blob/a663e78a6eb6bbd20c0c74b3e6a78e24ee423544/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp
After the test simplification, only one line should be displayed in the output if the option in the config is enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we assume that the check is a "black box" then after enabling your option it can, for example, stop emitting all messages. To make sure that we still flag C_1(C_1&&);, we need to add a small test-case for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it more clear, I can write something like
diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp index 8371b6aafd8b..dd1ee023bde3 100644 --- a/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoexceptFunctionBaseCheck.cpp @@ -20,6 +20,9 @@ void NoexceptFunctionBaseCheck::check(const MatchFinder::MatchResult &Result) { const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>(BindFuncDeclName); assert(FuncDecl); + if (AllowFalseEvaluated) + return; + if (SpecAnalyzer.analyze(FuncDecl) != utils::ExceptionSpecAnalyzer::State::Throwing) return;and all the tests will still pass. But clearly I broke the whole check.
This pull request aims to add a new flag to customize the
noexcept-move-constructorcheck in clang-tidy.Problem. Now the code below triggers the warning:
https://godbolt.org/z/E4E65jdhh
I had created a related issue: #126702
My proposal is to add an option to allow
noexcept(expr), even if this expression can be folded to false. This would force users to mark their move constructors as noexcept, while at the same time, the check would not trigger if the move constructor is not actually noexcept.