Skip to content

Reland [clang][dataflow] Fix unsupported types always being equal #131575

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
merged 1 commit into from
Mar 26, 2025

Conversation

Discookie
Copy link
Contributor

Relands #129502.

Previously when the framework encountered unsupported values (such as enum classes), they were always treated as equal when comparing with ==, regardless of their actual values being different.
Now the two sides are only equal if there's a Value assigned to them.

Added handling for the special case of nullptr == nullptr, to preserve the behavior of untyped nullptr having no value.

Previously when the framework encountered unsupported values, they were always treated as equal when comparing with `==`, regardless of their actual values being different.
Now the two sides are only equal if there's a Value assigned to them.
Added handling for the special case of `nullptr == nullptr`, and preserved untyped `nullptr` having no value.
@Discookie Discookie requested review from Xazax-hun and jvoung March 17, 2025 07:13
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang:analysis labels Mar 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 17, 2025

@llvm/pr-subscribers-clang-analysis

@llvm/pr-subscribers-clang

Author: Discookie (Discookie)

Changes

Relands #129502.

Previously when the framework encountered unsupported values (such as enum classes), they were always treated as equal when comparing with ==, regardless of their actual values being different.
Now the two sides are only equal if there's a Value assigned to them.

Added handling for the special case of nullptr == nullptr, to preserve the behavior of untyped nullptr having no value.


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

2 Files Affected:

  • (modified) clang/lib/Analysis/FlowSensitive/Transfer.cpp (+8-1)
  • (modified) clang/unittests/Analysis/FlowSensitive/TransferTest.cpp (+35)
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 9c54eb16d2224..6403190723e69 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -60,7 +60,14 @@ static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
   Value *LHSValue = Env.getValue(LHS);
   Value *RHSValue = Env.getValue(RHS);
 
-  if (LHSValue == RHSValue)
+  // When two unsupported values are compared, both are nullptr. Only supported
+  // values should evaluate to equal.
+  if (LHSValue == RHSValue && LHSValue)
+    return Env.getBoolLiteralValue(true);
+
+  // Special case: `NullPtrLiteralExpr == itself`. When both sides are untyped
+  // nullptr, they do not have an assigned Value, but they compare equal.
+  if (LHS.getType()->isNullPtrType() && RHS.getType()->isNullPtrType())
     return Env.getBoolLiteralValue(true);
 
   if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 0f731f4532535..f52b73dbbdc57 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -4974,6 +4974,41 @@ TEST(TransferTest, IntegerLiteralEquality) {
       });
 }
 
+TEST(TransferTest, UnsupportedValueEquality) {
+  std::string Code = R"(
+    // An explicitly unsupported type by the framework.
+    enum class EC {
+      A,
+      B
+    };
+  
+    void target() {
+      EC ec = EC::A;
+
+      bool unsupported_eq_same = (EC::A == EC::A);
+      bool unsupported_eq_other = (EC::A == EC::B);
+      bool unsupported_eq_var = (ec == EC::B);
+
+      (void)0; // [[p]]
+    }
+  )";
+  runDataflow(
+      Code,
+      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+         ASTContext &ASTCtx) {
+        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+
+        // We do not model the values of unsupported types, so this
+        // seemingly-trivial case will not be true either.
+        EXPECT_TRUE(isa<AtomicBoolValue>(
+            getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_same")));
+        EXPECT_TRUE(isa<AtomicBoolValue>(
+            getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_other")));
+        EXPECT_TRUE(isa<AtomicBoolValue>(
+            getValueForDecl<BoolValue>(ASTCtx, Env, "unsupported_eq_var")));
+      });
+}
+
 TEST(TransferTest, CorrelatedBranches) {
   std::string Code = R"(
     void target(bool B, bool C) {

Copy link
Contributor

@jvoung jvoung left a comment

Choose a reason for hiding this comment

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

Thanks!

@jvoung
Copy link
Contributor

jvoung commented Mar 25, 2025

Hi, just checking if you wanted to merge this, or if there were any other issues. Thanks!

@Discookie
Copy link
Contributor Author

No other issues, thanks for checking!

@Discookie Discookie merged commit a9a8338 into llvm:main Mar 26, 2025
15 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Mar 26, 2025

LLVM Buildbot has detected a new failure on builder lldb-x86_64-debian running on lldb-x86_64-debian while building clang at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/162/builds/18905

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: commands/gui/spawn-threads/TestGuiSpawnThreads.py (34 of 2802)
PASS: lldb-api :: commands/expression/expr-in-syscall/TestExpressionInSyscall.py (35 of 2802)
PASS: lldb-unit :: Process/gdb-remote/./ProcessGdbRemoteTests/8/35 (36 of 2802)
PASS: lldb-api :: functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py (37 of 2802)
PASS: lldb-api :: tools/lldb-dap/variables/TestDAP_variables.py (38 of 2802)
PASS: lldb-api :: commands/watchpoints/hello_watchlocation/TestWatchLocation.py (39 of 2802)
PASS: lldb-api :: functionalities/inferior-crashing/TestInferiorCrashingStep.py (40 of 2802)
PASS: lldb-api :: functionalities/gdb_remote_client/TestRegDefinitionInParts.py (41 of 2802)
PASS: lldb-api :: lang/cpp/stl/TestSTL.py (42 of 2802)
PASS: lldb-api :: lang/cpp/namespace/TestNamespace.py (43 of 2802)
FAIL: lldb-api :: tools/lldb-dap/launch/TestDAP_launch.py (44 of 2802)
******************** TEST 'lldb-api :: tools/lldb-dap/launch/TestDAP_launch.py' FAILED ********************
Script:
--
/usr/bin/python3 /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/./lib --env LLVM_INCLUDE_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/include --env LLVM_TOOLS_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/./bin --arch x86_64 --build-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex --lldb-module-cache-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/lldb --compiler /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/clang --dsymutil /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/worker/2.0.1/lldb-x86_64-debian/build/./bin --lldb-obj-root /home/worker/2.0.1/lldb-x86_64-debian/build/tools/lldb --lldb-libs-dir /home/worker/2.0.1/lldb-x86_64-debian/build/./lib -t /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/tools/lldb-dap/launch -p TestDAP_launch.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision a9a83387979a6c6dc0f508fe0b26c8d8fa7f5361)
  clang revision a9a83387979a6c6dc0f508fe0b26c8d8fa7f5361
  llvm revision a9a83387979a6c6dc0f508fe0b26c8d8fa7f5361
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
Change dir to: /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/tools/lldb-dap/launch
runCmd: settings clear -all

output: 

runCmd: settings set symbols.enable-external-lookup false

output: 

runCmd: settings set target.inherit-tcc true

output: 

runCmd: settings set target.disable-aslr false

output: 

runCmd: settings set target.detach-on-error false

output: 


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:analysis clang:dataflow Clang Dataflow Analysis framework - https://clang.llvm.org/docs/DataFlowAnalysisIntro.html clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants