llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Ryosuke Niwa (rniwa) <details> <summary>Changes</summary> Allow address-of operator (&), enum constant, and a reference to constant as well as materializing temporqary expression and an expression with cleanups to appear within a trivial function. --- Full diff: https://github.com/llvm/llvm-project/pull/81829.diff 3 Files Affected: - (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (+20-1) - (modified) clang/test/Analysis/Checkers/WebKit/mock-types.h (+1) - (modified) clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp (+94-1) ``````````diff diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index bf6f9a64877c64..e8295938a855d7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -285,7 +285,7 @@ class TrivialFunctionAnalysisVisitor bool VisitUnaryOperator(const UnaryOperator *UO) { // Operator '*' and '!' are allowed as long as the operand is trivial. - if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_LNot) + if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_LNot) return Visit(UO->getSubExpr()); // Other operators are non-trivial. @@ -306,6 +306,10 @@ class TrivialFunctionAnalysisVisitor if (auto *decl = DRE->getDecl()) { if (isa<ParmVarDecl>(decl)) return true; + if (isa<EnumConstantDecl>(decl)) + return true; + if (auto *VD = dyn_cast<VarDecl>(decl)) + return VD->hasConstantInitialization() && VD->getEvaluatedValue(); } return false; } @@ -377,6 +381,15 @@ class TrivialFunctionAnalysisVisitor return Visit(ECE->getSubExpr()); } + bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) + { + return Visit(VMT->getSubExpr()); + } + + bool VisitExprWithCleanups(const ExprWithCleanups *EWC) { + return Visit(EWC->getSubExpr()); + } + bool VisitParenExpr(const ParenExpr *PE) { return Visit(PE->getSubExpr()); } bool VisitInitListExpr(const InitListExpr *ILE) { @@ -397,6 +410,12 @@ class TrivialFunctionAnalysisVisitor return true; } + bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) + { + // nullptr is trivial. + return true; + } + // Constant literal expressions are always trivial bool VisitIntegerLiteral(const IntegerLiteral *E) { return true; } bool VisitFloatingLiteral(const FloatingLiteral *E) { return true; } diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index cc40487614a83d..d08a997aa8c043 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -19,6 +19,7 @@ template <typename T> struct RefPtr { RefPtr(T *t) : t(t) {} T *get() { return t; } T *operator->() { return t; } + const T *operator->() const { return t; } T &operator*() { return *t; } RefPtr &operator=(T *) { return *this; } operator bool() { return t; } diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp index 156a2480901bf0..83c4414d1d01aa 100644 --- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp @@ -1,7 +1,6 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s #include "mock-types.h" -//#include <type_traits> void WTFBreakpointTrap(); void WTFCrashWithInfo(int, const char*, const char*, int); @@ -60,11 +59,86 @@ NO_RETURN_DUE_TO_CRASH ALWAYS_INLINE void WTFCrashWithInfo(int line, const char* WTFCrashWithInfoImpl(line, file, function, counter, wtfCrashArg(reason)); } +enum class Flags : unsigned short { + Flag1 = 1 << 0, + Flag2 = 1 << 1, + Flag3 = 1 << 2, +}; + +template<typename E> class OptionSet { +public: + using StorageType = unsigned short; + + static constexpr OptionSet fromRaw(StorageType rawValue) { + return OptionSet(static_cast<E>(rawValue), FromRawValue); + } + + constexpr OptionSet() = default; + + constexpr OptionSet(E e) + : m_storage(static_cast<StorageType>(e)) { + } + + constexpr StorageType toRaw() const { return m_storage; } + + constexpr bool isEmpty() const { return !m_storage; } + + constexpr explicit operator bool() const { return !isEmpty(); } + + constexpr bool contains(E option) const { return containsAny(option); } + constexpr bool containsAny(OptionSet optionSet) const { + return !!(*this & optionSet); + } + + constexpr bool containsAll(OptionSet optionSet) const { + return (*this & optionSet) == optionSet; + } + + constexpr void add(OptionSet optionSet) { m_storage |= optionSet.m_storage; } + + constexpr void remove(OptionSet optionSet) + { + m_storage &= ~optionSet.m_storage; + } + + constexpr void set(OptionSet optionSet, bool value) + { + if (value) + add(optionSet); + else + remove(optionSet); + } + + constexpr friend OptionSet operator|(OptionSet lhs, OptionSet rhs) { + return fromRaw(lhs.m_storage | rhs.m_storage); + } + + constexpr friend OptionSet operator&(OptionSet lhs, OptionSet rhs) { + return fromRaw(lhs.m_storage & rhs.m_storage); + } + + constexpr friend OptionSet operator-(OptionSet lhs, OptionSet rhs) { + return fromRaw(lhs.m_storage & ~rhs.m_storage); + } + + constexpr friend OptionSet operator^(OptionSet lhs, OptionSet rhs) { + return fromRaw(lhs.m_storage ^ rhs.m_storage); + } + +private: + enum InitializationTag { FromRawValue }; + constexpr OptionSet(E e, InitializationTag) + : m_storage(static_cast<StorageType>(e)) { + } + StorageType m_storage { 0 }; +}; + class Number { public: Number(int v) : v(v) { } Number(double); Number operator+(const Number&); + const int& value() const { return v; } private: int v; }; @@ -112,6 +186,19 @@ class RefCounted { RefCounted& trivial18() const { RELEASE_ASSERT(this, "this must be not null"); return const_cast<RefCounted&>(*this); } void trivial19() const { return; } + static constexpr unsigned numBits = 4; + int trivial20() { return v >> numBits; } + + const int* trivial21() { return number ? &number->value() : nullptr; } + + enum class Enum : unsigned short { + Value1 = 1, + Value2 = 2, + }; + bool trivial22() { return enumValue == Enum::Value1; } + + bool trivial23() const { return OptionSet<Flags>::fromRaw(v).contains(Flags::Flag1); } + static RefCounted& singleton() { static RefCounted s_RefCounted; s_RefCounted.ref(); @@ -170,6 +257,8 @@ class RefCounted { } unsigned v { 0 }; + Number* number { nullptr }; + Enum enumValue { Enum::Value1 }; }; RefCounted* refCountedObj(); @@ -208,6 +297,10 @@ class UnrelatedClass { getFieldTrivial().trivial17(); // no-warning getFieldTrivial().trivial18(); // no-warning getFieldTrivial().trivial19(); // no-warning + getFieldTrivial().trivial20(); // no-warning + getFieldTrivial().trivial21(); // no-warning + getFieldTrivial().trivial22(); // no-warning + getFieldTrivial().trivial23(); // no-warning RefCounted::singleton().trivial18(); // no-warning RefCounted::singleton().someFunction(); // no-warning `````````` </details> https://github.com/llvm/llvm-project/pull/81829 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits