Skip to content

Commit 3af6ae0

Browse files
authored
[clang-tidy] Fix false-positives in misc-static-assert caused by non-constexpr variables (#77203)
Ignore false-positives when referring to non-constexpr variables in non-unevaluated context (like decltype, sizeof, ...). Moved from https://reviews.llvm.org/D158657 Fixes: #24066
1 parent 8887178 commit 3af6ae0

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "StaticAssertCheck.h"
10+
#include "../utils/Matchers.h"
1011
#include "clang/AST/ASTContext.h"
1112
#include "clang/AST/Expr.h"
1213
#include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -45,13 +46,20 @@ void StaticAssertCheck::registerMatchers(MatchFinder *Finder) {
4546
IsAlwaysFalse);
4647
auto NonConstexprFunctionCall =
4748
callExpr(hasDeclaration(functionDecl(unless(isConstexpr()))));
49+
auto NonConstexprVariableReference =
50+
declRefExpr(to(varDecl(unless(isConstexpr()))),
51+
unless(hasAncestor(expr(matchers::hasUnevaluatedContext()))),
52+
unless(hasAncestor(typeLoc())));
53+
54+
auto NonConstexprCode =
55+
expr(anyOf(NonConstexprFunctionCall, NonConstexprVariableReference));
4856
auto AssertCondition =
4957
expr(
5058
anyOf(expr(ignoringParenCasts(anyOf(
5159
AssertExprRoot, unaryOperator(hasUnaryOperand(
5260
ignoringParenCasts(AssertExprRoot)))))),
5361
anything()),
54-
unless(findAll(NonConstexprFunctionCall)))
62+
unless(NonConstexprCode), unless(hasDescendant(NonConstexprCode)))
5563
.bind("condition");
5664
auto Condition =
5765
anyOf(ignoringParenImpCasts(callExpr(

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Improvements to clang-tidy
119119

120120
- Improved `--dump-config` to print check options in alphabetical order.
121121

122-
- Improved :program:`clang-tidy-diff.py` script.
122+
- Improved :program:`clang-tidy-diff.py` script.
123123
* Return exit code `1` if any :program:`clang-tidy` subprocess exits with
124124
a non-zero code or if exporting fixes fails.
125125

@@ -381,6 +381,10 @@ Changes in existing checks
381381
<clang-tidy/checks/misc/redundant-expression>` check to ignore
382382
false-positives in unevaluated context (e.g., ``decltype``).
383383

384+
- Improved :doc:`misc-static-assert
385+
<clang-tidy/checks/misc/static-assert>` check to ignore false-positives when
386+
referring to non-``constexpr`` variables in non-unevaluated context.
387+
384388
- Improved :doc:`misc-unused-using-decls
385389
<clang-tidy/checks/misc/unused-using-decls>` check to avoid false positive when
386390
using in elaborated type and only check cpp files.

clang-tools-extra/test/clang-tidy/checkers/misc/static-assert.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,48 @@ void print(...);
2020
#define my_macro() assert(0 == 1)
2121
// CHECK-FIXES: #define my_macro() assert(0 == 1)
2222

23+
namespace PR24066 {
24+
25+
void referenceMember() {
26+
struct {
27+
int A;
28+
int B;
29+
} S;
30+
assert(&S.B - &S.A == 1);
31+
}
32+
33+
const int X = 1;
34+
void referenceVariable() {
35+
assert(X > 0);
36+
}
37+
38+
39+
constexpr int Y = 1;
40+
void referenceConstexprVariable() {
41+
assert(Y > 0);
42+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
43+
// CHECK-FIXES-CXX11: {{^ }}static_assert(Y > 0, "");
44+
// CHECK-FIXES-CXX17: {{^ }}static_assert(Y > 0);
45+
}
46+
47+
void useInSizeOf() {
48+
char a = 0;
49+
assert(sizeof(a) == 1U);
50+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
51+
// CHECK-FIXES-CXX11: {{^ }}static_assert(sizeof(a) == 1U, "");
52+
// CHECK-FIXES-CXX17: {{^ }}static_assert(sizeof(a) == 1U);
53+
}
54+
55+
void useInDecltype() {
56+
char a = 0;
57+
assert(static_cast<decltype(a)>(256) == 0);
58+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: found assert() that could be replaced by static_assert() [misc-static-assert]
59+
// CHECK-FIXES-CXX11: {{^ }}static_assert(static_cast<decltype(a)>(256) == 0, "");
60+
// CHECK-FIXES-CXX17: {{^ }}static_assert(static_cast<decltype(a)>(256) == 0);
61+
}
62+
63+
}
64+
2365
constexpr bool myfunc(int a, int b) { return a * b == 0; }
2466

2567
typedef __SIZE_TYPE__ size_t;

0 commit comments

Comments
 (0)