Author: Daniel Petrovic Date: 2026-10-24T15:31:48Z New Revision: 127d4f032302e315e03b78f40a535fcad13f7a55
URL: https://github.com/llvm/llvm-project/commit/127d4f032302e315e03b78f40a535fcad13f7a55 DIFF: https://github.com/llvm/llvm-project/commit/127d4f032302e315e03b78f40a535fcad13f7a55.diff LOG: [clang-tidy] Don't suggest const on `std::moved` locals in templates … (#226577) [clang-tidy] Don't suggest const on std::moved locals in templates Skip diagnostics in template instantiations for locals that are used as arguments of std::move. Reason: for some instantiations the move may be converted to copy so the variable may look unmutated and flagged, whereas for other template instantiations the real move semantics may apply. Fixes: #225395 Assisted by Gemini for constructing the matcher. --------- Co-authored-by: Zeyi Xu <[email protected]> Added: Modified: clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp clang-tools-extra/docs/ReleaseNotes.md clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp index 90919555d447e8..4532a27962af29 100644 --- a/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/ConstCorrectnessCheck.cpp @@ -199,6 +199,25 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) { } } +static bool isStdMoveOperandInTemplate(const VarDecl *Variable, + const FunctionDecl *Func, + ASTContext &Context) { + if (Func->isTemplateInstantiation()) + if (const Stmt *Body = Func->getBody()) { + // Match on the instantiated body where `std::move` is resolved to a + // concrete function and the argument references the instantiated + // variable. + const auto Moves = + match(stmt(forEachDescendant( + callExpr(callee(functionDecl(hasName("std::move"))), + hasArgument(0, ignoringParenImpCasts(declRefExpr( + to(equalsNode(Variable)))))))), + *Body, Context); + return !Moves.empty(); + } + return false; +} + static void addConstFixits(const DiagnosticBuilder &Diag, const VarDecl *Variable, const FunctionDecl *Function, @@ -255,9 +274,6 @@ void ConstCorrectnessCheck::check(const MatchFinder::MatchResult &Result) { /// dependent. Variables like 'int x = 42;' in a template that can become /// const emit multiple warnings otherwise. bool IsNormalVariableInTemplate = Function->isTemplateInstantiation(); - if (IsNormalVariableInTemplate && - TemplateDiagnosticsCache.contains(Variable->getBeginLoc())) - return; VariableCategory VC = VariableCategory::Value; const QualType VT = Variable->getType(); @@ -269,6 +285,14 @@ void ConstCorrectnessCheck::check(const MatchFinder::MatchResult &Result) { ArrayT && ArrayT->getElementType()->isPointerType()) VC = VariableCategory::Pointer; + if (IsNormalVariableInTemplate && VC != VariableCategory::Pointer && + isStdMoveOperandInTemplate(Variable, Function, *Result.Context)) + return; + + if (IsNormalVariableInTemplate && + TemplateDiagnosticsCache.contains(Variable->getBeginLoc())) + return; + const auto CheckValue = [&]() { // Offload const-analysis to utility function. if (isMutated(Variable, LocalScope, Function, Result.Context)) diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index 57ed93042aff2c..037df4cd0937c4 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -261,10 +261,14 @@ infrastructure are described first, followed by tool-specific sections. - No longer diagnoses variables declared with `decltype(auto)`, where the suggested `const` does not compile. - + - No longer diagnoses parameters of `main`, whose signature is fixed by the standard. + - No longer diagnoses variables used as operands of `std::move` in template + instantiations, where the suggested `const` would break the move for + instantiations with real move semantics. + - Fixed an infinite loop in {doc}`misc-multiple-inheritance <clang-tidy/checks/misc/multiple-inheritance>` when checking a class that inherits from itself or has a circular inheritance graph. @@ -429,7 +433,7 @@ infrastructure are described first, followed by tool-specific sections. - Ignored preprocessor directives such as `#endif` that appear immediately before an enum's closing brace, which previously produced a false positive and a fix-it that inserted a comma after the directive. - + - Fixed a false positive on empty brace initializers of types with default member initializers. diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp index 98bf27033c3b5f..624159210698c5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp @@ -6,6 +6,9 @@ // RUN: misc-const-correctness.TransformPointersAsValues: false} \ // RUN: }" -- -fno-delayed-template-parsing +#include <string> +#include <utility> + template <typename T> void type_dependent_variables() { T value = 42; @@ -27,6 +30,23 @@ void instantiate_template_cases() { type_dependent_variables<float>(); } +namespace gh225395 { + +template <typename T> void my_swap(T &t1, T &t2) { + auto tmp = std::move(t1); + t1 = std::move(t2); + t2 = std::move(tmp); +} +void instantiate() { + std::string a; + std::string b; + my_swap(a, b); + int x = 0; + int y = 0; + my_swap(x, y); +} +} // namespace gh225395 + namespace gh57297{ // The expression to check may not be the dependent operand in a dependent // operator. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
