[clang] [llvm] [clang][nullability] Don't return null fields from `getReferencedDecls()`. (PR #94983)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 10 07:14:51 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: None (martinboehme)
<details>
<summary>Changes</summary>
The patch includes a repro for a case where we were returning a null `FieldDecl`
when calling `getReferencedDecls()` on the `InitListExpr` for a union.
Also, I noticed while working on this that `RecordInitListHelper` has a bug
where it doesn't work correctly for empty unions. This patch also includes a
repro and fix for this bug.
---
Full diff: https://github.com/llvm/llvm-project/pull/94983.diff
5 Files Affected:
- (modified) clang/docs/tools/clang-formatted-files.txt (+1)
- (modified) clang/lib/Analysis/FlowSensitive/ASTOps.cpp (+7-4)
- (added) clang/unittests/Analysis/FlowSensitive/ASTOpsTest.cpp (+88)
- (modified) clang/unittests/Analysis/FlowSensitive/CMakeLists.txt (+1)
- (modified) llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn (+1)
``````````diff
diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt
index dee51e402b687..4866bd4aee634 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -622,6 +622,7 @@ clang/tools/libclang/CXCursor.h
clang/tools/scan-build-py/tests/functional/src/include/clean-one.h
clang/unittests/Analysis/CFGBuildResult.h
clang/unittests/Analysis/MacroExpansionContextTest.cpp
+clang/unittests/Analysis/FlowSensitive/ASTOpsTest.cpp
clang/unittests/Analysis/FlowSensitive/CNFFormula.cpp
clang/unittests/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp
clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp
diff --git a/clang/lib/Analysis/FlowSensitive/ASTOps.cpp b/clang/lib/Analysis/FlowSensitive/ASTOps.cpp
index 38b5f51b7b2f0..27d42a7b50856 100644
--- a/clang/lib/Analysis/FlowSensitive/ASTOps.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ASTOps.cpp
@@ -100,7 +100,8 @@ getFieldsForInitListExpr(const InitListT *InitList) {
std::vector<const FieldDecl *> Fields;
if (InitList->getType()->isUnionType()) {
- Fields.push_back(InitList->getInitializedFieldInUnion());
+ if (const FieldDecl *Field = InitList->getInitializedFieldInUnion())
+ Fields.push_back(Field);
return Fields;
}
@@ -137,9 +138,11 @@ RecordInitListHelper::RecordInitListHelper(
// it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves.
SmallVector<Expr *> InitsForUnion;
if (Ty->isUnionType() && Inits.empty()) {
- assert(Fields.size() == 1);
- ImplicitValueInitForUnion.emplace(Fields.front()->getType());
- InitsForUnion.push_back(&*ImplicitValueInitForUnion);
+ assert(Fields.size() <= 1);
+ if (!Fields.empty()) {
+ ImplicitValueInitForUnion.emplace(Fields.front()->getType());
+ InitsForUnion.push_back(&*ImplicitValueInitForUnion);
+ }
Inits = InitsForUnion;
}
diff --git a/clang/unittests/Analysis/FlowSensitive/ASTOpsTest.cpp b/clang/unittests/Analysis/FlowSensitive/ASTOpsTest.cpp
new file mode 100644
index 0000000000000..cd1c076ab09e6
--- /dev/null
+++ b/clang/unittests/Analysis/FlowSensitive/ASTOpsTest.cpp
@@ -0,0 +1,88 @@
+//===- unittests/Analysis/FlowSensitive/ASTOpsTest.cpp --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/FlowSensitive/ASTOps.h"
+#include "TestingSupport.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <memory>
+
+namespace {
+
+using namespace clang;
+using namespace dataflow;
+
+using ast_matchers::cxxRecordDecl;
+using ast_matchers::hasName;
+using ast_matchers::hasType;
+using ast_matchers::initListExpr;
+using ast_matchers::match;
+using ast_matchers::selectFirst;
+using test::findValueDecl;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
+
+TEST(ASTOpsTest, RecordInitListHelperOnEmptyUnionInitList) {
+ // This is a regression test: The `RecordInitListHelper` used to assert-fail
+ // when called for the `InitListExpr` of an empty union.
+ std::string Code = R"cc(
+ struct S {
+ S() : UField{} {};
+
+ union U {} UField;
+ };
+ )cc";
+ std::unique_ptr<ASTUnit> Unit =
+ tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"});
+ auto &ASTCtx = Unit->getASTContext();
+
+ ASSERT_EQ(ASTCtx.getDiagnostics().getClient()->getNumErrors(), 0U);
+
+ auto *InitList = selectFirst<InitListExpr>(
+ "init",
+ match(initListExpr(hasType(cxxRecordDecl(hasName("U")))).bind("init"),
+ ASTCtx));
+ ASSERT_NE(InitList, nullptr);
+
+ RecordInitListHelper Helper(InitList);
+ EXPECT_THAT(Helper.base_inits(), IsEmpty());
+ EXPECT_THAT(Helper.field_inits(), IsEmpty());
+}
+
+TEST(ASTOpsTest, ReferencedDeclsOnUnionInitList) {
+ // This is a regression test: `getReferencedDecls()` used to return a null
+ // `FieldDecl` in this case (in addition to the correct non-null `FieldDecl`)
+ // because `getInitializedFieldInUnion()` returns null for the syntactic form
+ // of the `InitListExpr`.
+ std::string Code = R"cc(
+ struct S {
+ S() : UField{0} {};
+
+ union U {
+ int I;
+ } UField;
+ };
+ )cc";
+ std::unique_ptr<ASTUnit> Unit =
+ tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++17"});
+ auto &ASTCtx = Unit->getASTContext();
+
+ ASSERT_EQ(ASTCtx.getDiagnostics().getClient()->getNumErrors(), 0U);
+
+ auto *InitList = selectFirst<InitListExpr>(
+ "init",
+ match(initListExpr(hasType(cxxRecordDecl(hasName("U")))).bind("init"),
+ ASTCtx));
+ ASSERT_NE(InitList, nullptr);
+ auto *IDecl = cast<FieldDecl>(findValueDecl(ASTCtx, "I"));
+
+ EXPECT_THAT(getReferencedDecls(*InitList).Fields,
+ UnorderedElementsAre(IDecl));
+}
+
+} // namespace
diff --git a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
index cfabb80576bc1..12fee5dc2789c 100644
--- a/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
+++ b/clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_unittest(ClangAnalysisFlowSensitiveTests
ArenaTest.cpp
+ ASTOpsTest.cpp
CFGMatchSwitchTest.cpp
ChromiumCheckModelTest.cpp
DataflowAnalysisContextTest.cpp
diff --git a/llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn b/llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
index e16ca31b81a8d..780a69f1f3299 100644
--- a/llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
+++ b/llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
@@ -18,6 +18,7 @@ unittest("ClangAnalysisFlowSensitiveTests") {
"//llvm/lib/Testing/Support",
]
sources = [
+ "ASTOpsTest.cpp",
"ArenaTest.cpp",
"CFGMatchSwitchTest.cpp",
"ChromiumCheckModelTest.cpp",
``````````
</details>
https://github.com/llvm/llvm-project/pull/94983
More information about the cfe-commits
mailing list