Skip to content

[clang-tidy] fix misc-const-correctnes false-positive for fold expressions #78320

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

Merged

Conversation

5chmidti
Copy link
Contributor

@5chmidti 5chmidti commented Jan 16, 2024

The check no longer emits a diagnostic for non-parameter-pack
variables in C++17 fold expressions.
The operator used is type-dependent because of the parameter pack
and can therefore not be guaranteed to not mutate the variable.

Fixes: #70323

@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tidy clang:analysis labels Jan 16, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 16, 2024

@llvm/pr-subscribers-clang-analysis
@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang

Author: Julian Schmidt (5chmidti)

Changes

The check no longer emits a diagnostic for variables used as the
initializer of C++17 fold expressions.
The operator used is type-dependent because of the parameter pack
and can therefore not be guaranteed to not mutate the variable.

Fixes: #70323


Full diff: https://github.com/llvm/llvm-project/pull/78320.diff

4 Files Affected:

  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+3-7)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp (+17)
  • (modified) clang/lib/Analysis/ExprMutationAnalyzer.cpp (+4)
  • (modified) clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp (+15)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index d77267588db9158..c975b99c5786bef 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -382,7 +382,8 @@ Changes in existing checks
   using pointer to member function. Additionally, the check no longer emits
   a diagnostic when a variable that is not type-dependent is an operand of a
   type-dependent binary operator. Improved performance of the check through
-  optimizations.
+  optimizations. The check no longer emits a diagnostic for
+  variables used as the initializer of C++17 fold expressions.
 
 - Improved :doc:`misc-include-cleaner
   <clang-tidy/checks/misc/include-cleaner>` check by adding option
@@ -502,12 +503,7 @@ Changes in existing checks
   <clang-tidy/checks/readability/implicit-bool-conversion>` check to take
   do-while loops into account for the `AllowIntegerConditions` and
   `AllowPointerConditions` options. It also now provides more consistent
-  suggestions when parentheses are added to the return value or expressions. 
-  It also ignores false-positives for comparison containing bool bitfield.
-
-- Improved :doc:`readability-misleading-indentation
-  <clang-tidy/checks/readability/misleading-indentation>` check to ignore
-  false-positives for line started with empty macro.
+  suggestions when parentheses are added to the return value.
 
 - Improved :doc:`readability-non-const-parameter
   <clang-tidy/checks/readability/non-const-parameter>` check to ignore
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 794578ceeeba8fc..a4be41d20eae131 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
@@ -30,3 +30,20 @@ namespace gh57297{
 struct Stream { };
 template <typename T> void f() { T t; Stream x; x << t; }
 } // namespace gh57297
+
+namespace gh70323{
+// A fold expression may contain the checked variable as it's initializer.
+// We don't know if the operator modifies that variable because the
+// operator is type dependent due to the parameter pack.
+
+struct Stream {};
+template <typename T>
+Stream& operator<<(Stream&, T);
+template <typename... Args>
+void concatenate(Args... args)
+{
+    Stream stream;
+    (stream << ... << args);
+    (args << ... << stream);
+}
+} // namespace gh70323
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 9af818be0415f39..bb042760d297a78 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -343,6 +343,10 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
       // in different instantiations of the template.
       binaryOperator(isTypeDependent(),
                      hasEitherOperand(ignoringImpCasts(canResolveToExpr(Exp)))),
+      // A fold expression may contain `Exp` as it's initializer.
+      // We don't know if the operator modifies `Exp` because the
+      // operator is type dependent due to the parameter pack.
+      cxxFoldExpr(hasFoldInit(ignoringImpCasts(canResolveToExpr(Exp)))),
       // Within class templates and member functions the member expression might
       // not be resolved. In that case, the `callExpr` is considered to be a
       // modification.
diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
index a94f857720b0357..50d0399ed4b0159 100644
--- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -359,6 +359,21 @@ TEST(ExprMutationAnalyzerTest, DependentOperatorWithNonDependentOperand) {
   EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x << t"));
 }
 
+TEST(ExprMutationAnalyzerTest, FoldExpression) {
+  // gh70323
+  // A fold expression may contain `Exp` as it's initializer.
+  // We don't know if the operator modifies `Exp` because the
+  // operator is type dependent due to the parameter pack.
+  const auto AST = buildASTFromCode(
+      "struct Stream {};"
+      "template <typename T> Stream& operator<<(Stream&, T); "
+      "template <typename... Args> void concatenate(Args... args) "
+      "{ Stream x; (x << ... << args); }");
+  const auto Results =
+      match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
+  EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(x << ... << args)"));
+}
+
 // Section: expression as call argument
 
 TEST(ExprMutationAnalyzerTest, ByValueArgument) {

…sions

The check no longer emits a diagnostic for variables used as the
initializer of C++17 fold expressions.
The operator used is type-dependent because of the parameter pack
and can therefore not be guaranteed to not mutate the variable.

Fixes: llvm#70323
@5chmidti 5chmidti force-pushed the clang_tidy_misc_const_correctness_gh70323 branch from d26970b to 1951630 Compare January 16, 2024 17:53
Copy link
Member

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but i'm not 100% sure about ExprMutationAnalyzer part (if thats a right place).
Leave it open for few days, so others could comment if they have objections.

@@ -382,7 +382,8 @@ Changes in existing checks
using pointer to member function. Additionally, the check no longer emits
a diagnostic when a variable that is not type-dependent is an operand of a
type-dependent binary operator. Improved performance of the check through
optimizations.
optimizations. The check no longer emits a diagnostic for
variables used as the initializer of C++17 fold expressions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure "initializer of C++17 fold expressions" is the correct description for InitExpr in fold expression since I don't find it in https://eel.is/c++draft/expr.prim.fold and https://en.cppreference.com/w/cpp/language/fold.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, what do you think about The check no longer emits a diagnostic for non-parameter-pack variables in C++17 fold expressions.?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@5chmidti
Copy link
Contributor Author

I fixed the clang-tidy test case by separating them and I have added a test case to check that using a variable in the pack side of the fold expression would be detected (that did not change with this patch though, just as a sanity check).

@5chmidti
Copy link
Contributor Author

@PiotrZSL is this a reconfirmation of your previous approval (given the changed tests and release note), or is this an approval for everything?
Specifically

LGTM, but i'm not 100% sure about ExprMutationAnalyzer part (if thats a right place).
Leave it open for few days, so others could comment if they have objections.

(I think it is the right place, just under the binaryOperator which is incredibly similar to the case detected by the cxxFoldExpr matcher)

@PiotrZSL
Copy link
Member

@5chmidti I would say: fell free to merge it. It's not that it would break too much. In worst case we got around ~1 month to fix it on a branch (if someone would complain).

@5chmidti 5chmidti merged commit 9f8ccf5 into llvm:main Jan 22, 2024
@5chmidti 5chmidti deleted the clang_tidy_misc_const_correctness_gh70323 branch November 2, 2024 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:analysis clang Clang issues not falling into any other category clang-tidy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[clang-tidy] incorrect misc-const-correctness warning emitted for C++17 fold expression
4 participants