[clang-tools-extra] 127d4f0 - [clang-tidy] Don't suggest const on `std::moved` locals in templates … (#226577)

via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 24 08:31:54 PDT 2026


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 <zeyi2 at nekoarch.cc>

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.


        


More information about the cfe-commits mailing list