Skip to content

Commit 1951630

Browse files
committed
[clang-tidy] fix misc-const-correctnes false-positive for fold expressions
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
1 parent 127fc79 commit 1951630

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ Changes in existing checks
382382
using pointer to member function. Additionally, the check no longer emits
383383
a diagnostic when a variable that is not type-dependent is an operand of a
384384
type-dependent binary operator. Improved performance of the check through
385-
optimizations.
385+
optimizations. The check no longer emits a diagnostic for
386+
variables used as the initializer of C++17 fold expressions.
386387

387388
- Improved :doc:`misc-include-cleaner
388389
<clang-tidy/checks/misc/include-cleaner>` check by adding option
@@ -502,7 +503,7 @@ Changes in existing checks
502503
<clang-tidy/checks/readability/implicit-bool-conversion>` check to take
503504
do-while loops into account for the `AllowIntegerConditions` and
504505
`AllowPointerConditions` options. It also now provides more consistent
505-
suggestions when parentheses are added to the return value or expressions.
506+
suggestions when parentheses are added to the return value or expressions.
506507
It also ignores false-positives for comparison containing bool bitfield.
507508

508509
- Improved :doc:`readability-misleading-indentation

clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,20 @@ namespace gh57297{
3030
struct Stream { };
3131
template <typename T> void f() { T t; Stream x; x << t; }
3232
} // namespace gh57297
33+
34+
namespace gh70323{
35+
// A fold expression may contain the checked variable as it's initializer.
36+
// We don't know if the operator modifies that variable because the
37+
// operator is type dependent due to the parameter pack.
38+
39+
struct Stream {};
40+
template <typename T>
41+
Stream& operator<<(Stream&, T);
42+
template <typename... Args>
43+
void concatenate(Args... args)
44+
{
45+
Stream stream;
46+
(stream << ... << args);
47+
(args << ... << stream);
48+
}
49+
} // namespace gh70323

clang/lib/Analysis/ExprMutationAnalyzer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
343343
// in different instantiations of the template.
344344
binaryOperator(isTypeDependent(),
345345
hasEitherOperand(ignoringImpCasts(canResolveToExpr(Exp)))),
346+
// A fold expression may contain `Exp` as it's initializer.
347+
// We don't know if the operator modifies `Exp` because the
348+
// operator is type dependent due to the parameter pack.
349+
cxxFoldExpr(hasFoldInit(ignoringImpCasts(canResolveToExpr(Exp)))),
346350
// Within class templates and member functions the member expression might
347351
// not be resolved. In that case, the `callExpr` is considered to be a
348352
// modification.

clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,21 @@ TEST(ExprMutationAnalyzerTest, DependentOperatorWithNonDependentOperand) {
359359
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("x << t"));
360360
}
361361

362+
TEST(ExprMutationAnalyzerTest, FoldExpression) {
363+
// gh70323
364+
// A fold expression may contain `Exp` as it's initializer.
365+
// We don't know if the operator modifies `Exp` because the
366+
// operator is type dependent due to the parameter pack.
367+
const auto AST = buildASTFromCode(
368+
"struct Stream {};"
369+
"template <typename T> Stream& operator<<(Stream&, T); "
370+
"template <typename... Args> void concatenate(Args... args) "
371+
"{ Stream x; (x << ... << args); }");
372+
const auto Results =
373+
match(withEnclosingCompound(declRefTo("x")), AST->getASTContext());
374+
EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("(x << ... << args)"));
375+
}
376+
362377
// Section: expression as call argument
363378

364379
TEST(ExprMutationAnalyzerTest, ByValueArgument) {

0 commit comments

Comments
 (0)