[clang] 166209c - Fix false match on nullPointerConstant for array indices (#201893)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 30 10:57:13 PDT 2026
Author: Kay Hicketts
Date: 2026-06-30T17:57:07Z
New Revision: 166209c3b05c5e3c3eb930ae0e613b18c43797a9
URL: https://github.com/llvm/llvm-project/commit/166209c3b05c5e3c3eb930ae0e613b18c43797a9
DIFF: https://github.com/llvm/llvm-project/commit/166209c3b05c5e3c3eb930ae0e613b18c43797a9.diff
LOG: Fix false match on nullPointerConstant for array indices (#201893)
# Problem Detail
In the code
```
int *p[1];
(void) p[0];
```
The AST tree for ```p[0]``` looks like
```
|-CStyleCastExpr 0xc0ae6f1d8 <line:3:3, col:13> 'void' <ToVoid>
| `-ArraySubscriptExpr 0xc0ae6f1a8 <col:10, col:13> 'int *' lvalue
| |-ImplicitCastExpr 0xc0ae6f190 <col:10> 'int **' <ArrayToPointerDecay>
| | `-DeclRefExpr 0xc0ae6f118 <col:10> 'int *[1]' lvalue Var 0xc0ae6f098 'p' 'int *[1]'
| `-IntegerLiteral 0xc0ae6f138 <col:12> 'int' 0
```
So the previous matcher was finding the integer literal and then seeing
that the parent was a pointer type and thus we were getting a positive
match for something that should be replaced by a null pointer, even
though the index is just an integer.
# Solution
In a real null pointer scenario in cpp
```int *sausage = 0;```
The AST is like
```
| `-VarDecl 0xc0ae6f218 <col:3, col:18> col:8 sausage 'int *' cinit
| `-ImplicitCastExpr 0xc0ae6f2a0 <col:18> 'int *' <NullToPointer>
| `-IntegerLiteral 0xc0ae6f280 <col:18> 'int' 0
```
In C it's the same but with the exception of explicit casts
e.g.
```char *beans = (char*)0;```
which are represented as
```
| `-DeclStmt 0xacee134e8 <line:11:3, col:25>
| `-VarDecl 0xacee13420 <col:3, col:24> col:9 beans 'char *' cinit
| `-CStyleCastExpr 0xacee134c0 <col:17, col:24> 'char *' <NullToPointer>
| `-IntegerLiteral 0xacee13488 <col:24> 'int' 0
```
So the new matcher looks for an IntegerLiteral with value 0 that has a
parent that does any kind of cast to a null pointer
I used AI tools to help me build and understand the code.
# Original Issue
clang-tidy tools replace 0 with nullptr in index references due to
misinterpreting index numbers as pointers
Fixes: https://github.com/llvm/llvm-project/issues/87008
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 31e7979612a76..26d5d08979391 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -981,6 +981,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
### AST Matchers
+- Fixed `nullPointerConstant` matcher falsely matching integer literal `0`
+ in non-null-pointer contexts such as array subscripts and pointer arithmetic.
- Add `functionTypeLoc` matcher for matching `FunctionTypeLoc`.
- Add missing support for `TraversalKind` in some `addMatcher()` overloads.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index bc0f35898a2c9..8108ee559acea 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -8367,9 +8367,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr>
/// matches the initializer for v1, v2, v3, cp, and ip. Does not match the
/// initializer for i.
AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
- return anyOf(
- gnuNullExpr(), cxxNullPtrLiteralExpr(),
- integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
+ return anyOf(gnuNullExpr(), cxxNullPtrLiteralExpr(),
+ integerLiteral(equals(0), hasParent(castExpr(
+ hasCastKind(CK_NullToPointer)))));
}
/// Matches the DecompositionDecl the binding belongs to.
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index d9647c201fc30..2c27ab0805625 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -4049,6 +4049,12 @@ TEST_P(ASTMatchersTest, NullPointerConstant) {
EXPECT_TRUE(matches("char *cp = (char *)0;", expr(nullPointerConstant())));
EXPECT_TRUE(matches("int *ip = 0;", expr(nullPointerConstant())));
EXPECT_FALSE(matches("int i = 0;", expr(nullPointerConstant())));
+ EXPECT_FALSE(
+ matches("void f(){int *p[1]; (void)p[0];}", expr(nullPointerConstant())));
+ EXPECT_TRUE(matches("void f(){int index; (void)index[(int*)0];}",
+ expr(nullPointerConstant())));
+ EXPECT_FALSE(matches("void f(){int* ptr; (void)(ptr + 0);}",
+ expr(nullPointerConstant())));
}
TEST_P(ASTMatchersTest, NullPointerConstant_GNUNull) {
More information about the cfe-commits
mailing list