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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits