steakhal updated this revision to Diff 283936.
steakhal added a comment.

- Moved the FIXME closer to the subject.
- Added tests for covering incomplete enums as well.
- Added `REQUIRES: z3`. This will mark the test case `unsupported` on every 
buildbots. See my notes about this behavior at D83677 
<https://reviews.llvm.org/D83677>.
- Refined test file.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D85528/new/

https://reviews.llvm.org/D85528

Files:
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/test/Analysis/z3-refute-enum-crash.cpp

Index: clang/test/Analysis/z3-refute-enum-crash.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/z3-refute-enum-crash.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config crosscheck-with-z3=true -verify %s
+// REQUIRES: z3
+//
+// Requires z3 only for refutation. Works with both constraint managers.
+
+void clang_analyzer_warnIfReached();
+
+using sugar_t = unsigned char;
+
+// Complete enum types
+enum class ScopedSugaredComplete : sugar_t {};
+enum class ScopedPrimitiveComplete : unsigned char {};
+enum UnscopedSugaredComplete : sugar_t {};
+enum UnscopedPrimitiveComplete : unsigned char {};
+
+// Incomplete enum types
+enum class ScopedSugaredIncomplete : sugar_t;
+enum class ScopedPrimitiveIncomplete : unsigned char;
+enum UnscopedSugaredIncomplete : sugar_t;
+enum UnscopedPrimitiveIncomplete : unsigned char;
+
+template <typename T>
+T conjure();
+
+void test_complete_enum_types() {
+  auto var1 = conjure<ScopedSugaredComplete>();
+  auto var2 = conjure<ScopedPrimitiveComplete>();
+  auto var3 = conjure<UnscopedSugaredComplete>();
+  auto var4 = conjure<UnscopedPrimitiveComplete>();
+
+  int sym1 = static_cast<unsigned char>(var1) & 0x0F;
+  if (sym1)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+
+  int sym2 = static_cast<unsigned char>(var2) & 0x0F;
+  if (sym2)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+
+  int sym3 = static_cast<unsigned char>(var3) & 0x0F;
+  if (sym3)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+
+  int sym4 = static_cast<unsigned char>(var4) & 0x0F;
+  if (sym4)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+}
+
+void test_incomplete_enum_types() {
+  auto var1 = conjure<ScopedSugaredIncomplete>();
+  auto var2 = conjure<ScopedPrimitiveIncomplete>();
+  auto var3 = conjure<UnscopedSugaredIncomplete>();
+  auto var4 = conjure<UnscopedPrimitiveIncomplete>();
+
+  int sym1 = static_cast<unsigned char>(var1) & 0x0F;
+  if (sym1)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+
+  int sym2 = static_cast<unsigned char>(var2) & 0x0F;
+  if (sym2)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+
+  int sym3 = static_cast<unsigned char>(var3) & 0x0F;
+  if (sym3)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+
+  int sym4 = static_cast<unsigned char>(var4) & 0x0F;
+  if (sym4)
+    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} no-crash
+}
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -95,11 +95,22 @@
   }
 
   bool haveSameType(QualType Ty1, QualType Ty2) {
+    const auto IsIntegralOrUnscopedCompleteEnumerationType = [](QualType Ty) {
+      const Type *CanonicalType = Ty.getCanonicalType().getTypePtr();
+      if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
+        return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
+      return Ty->isIntegralOrEnumerationType();
+    };
+
+    const bool BothHaveSameCanonicalTypes =
+        Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2);
+    const bool BothHaveIntegralLikeTypes =
+        IsIntegralOrUnscopedCompleteEnumerationType(Ty1) &&
+        IsIntegralOrUnscopedCompleteEnumerationType(Ty2);
+
     // FIXME: Remove the second disjunct when we support symbolic
     // truncation/extension.
-    return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) ||
-            (Ty1->isIntegralOrEnumerationType() &&
-             Ty2->isIntegralOrEnumerationType()));
+    return BothHaveSameCanonicalTypes || BothHaveIntegralLikeTypes;
   }
 
   SVal evalCast(SVal val, QualType castTy, QualType originalType);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to