[clang] [clang][AArch64] multilib: fix deduction of "-march=" option (PR #81474)
domin144 wrote: @MaskRay @petrhosek @smithp35 @mplatings Looking at previous reviews for multilib related changes you might be interested. (ingore the buildkite failure for now. It seems unrelated.) https://github.com/llvm/llvm-project/pull/81474 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions (PR #81829)
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81829 >From 382ce72e206ca80e3414d5a141afa0f4f8b8 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 23:30:27 -0800 Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions 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. --- .../Checkers/WebKit/PtrTypesSemantics.cpp | 20 +++- .../Analysis/Checkers/WebKit/mock-types.h | 1 + .../Checkers/WebKit/uncounted-obj-arg.cpp | 95 ++- 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index bf6f9a64877c64..6f236db0474079 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -285,7 +285,8 @@ 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 +307,10 @@ class TrivialFunctionAnalysisVisitor if (auto *decl = DRE->getDecl()) { if (isa(decl)) return true; + if (isa(decl)) +return true; + if (auto *VD = dyn_cast(decl)) +return VD->hasConstantInitialization() && VD->getEvaluatedValue(); } return false; } @@ -377,6 +382,14 @@ 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,11 @@ 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 struct RefPtr { RefPtr(T *t) : t(t) {} T *get() { return t; } T *operator->() { return t; } + const T *operator->() const { return t; } T *() { return *t; } RefPtr =(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 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 class OptionSet { +public: + using StorageType = unsigned short; + + static constexpr OptionSet fromRaw(StorageType rawValue) { +return OptionSet(static_cast(rawValue), FromRawValue); + } + + constexpr OptionSet() = default; + + constexpr OptionSet(E e) +: m_storage(static_cast(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) + { +
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions (PR #81829)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff dcbb574cfc3445251ff1c751f27b52ed6503bead 793c72168db3a27ad189e9c95d7701d19cefec1e -- clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp clang/test/Analysis/Checkers/WebKit/mock-types.h clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index e8295938a8..6f236db047 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -285,7 +285,8 @@ public: bool VisitUnaryOperator(const UnaryOperator *UO) { // Operator '*' and '!' are allowed as long as the operand is trivial. -if (UO->getOpcode() == UO_Deref || UO->getOpcode() == UO_AddrOf || 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. @@ -381,8 +382,7 @@ public: return Visit(ECE->getSubExpr()); } - bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) - { + bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) { return Visit(VMT->getSubExpr()); } @@ -410,8 +410,7 @@ public: return true; } - bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) - { + bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) { // nullptr is trivial. return true; } `` 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
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions (PR #81829)
llvmbot wrote: @llvm/pr-subscribers-clang-static-analyzer-1 Author: Ryosuke Niwa (rniwa) Changes 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(decl)) return true; + if (isa(decl)) +return true; + if (auto *VD = dyn_cast(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 struct RefPtr { RefPtr(T *t) : t(t) {} T *get() { return t; } T *operator->() { return t; } + const T *operator->() const { return t; } T *() { return *t; } RefPtr =(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 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 class OptionSet { +public: + using StorageType = unsigned short; + + static constexpr OptionSet fromRaw(StorageType rawValue) { +return OptionSet(static_cast(rawValue), FromRawValue); + } + + constexpr OptionSet() = default; + + constexpr OptionSet(E e) +: m_storage(static_cast(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
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions (PR #81829)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Ryosuke Niwa (rniwa) Changes 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(decl)) return true; + if (isa(decl)) +return true; + if (auto *VD = dyn_cast(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 struct RefPtr { RefPtr(T *t) : t(t) {} T *get() { return t; } T *operator->() { return t; } + const T *operator->() const { return t; } T *() { return *t; } RefPtr =(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 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 class OptionSet { +public: + using StorageType = unsigned short; + + static constexpr OptionSet fromRaw(StorageType rawValue) { +return OptionSet(static_cast(rawValue), FromRawValue); + } + + constexpr OptionSet() = default; + + constexpr OptionSet(E e) +: m_storage(static_cast(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
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions (PR #81829)
https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/81829 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. >From 793c72168db3a27ad189e9c95d7701d19cefec1e Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 23:30:27 -0800 Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect more trivial functions 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. --- .../Checkers/WebKit/PtrTypesSemantics.cpp | 21 +++- .../Analysis/Checkers/WebKit/mock-types.h | 1 + .../Checkers/WebKit/uncounted-obj-arg.cpp | 95 ++- 3 files changed, 115 insertions(+), 2 deletions(-) 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(decl)) return true; + if (isa(decl)) +return true; + if (auto *VD = dyn_cast(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 struct RefPtr { RefPtr(T *t) : t(t) {} T *get() { return t; } T *operator->() { return t; } + const T *operator->() const { return t; } T *() { return *t; } RefPtr =(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 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 class OptionSet { +public: + using StorageType = unsigned short; + + static constexpr OptionSet fromRaw(StorageType rawValue) { +return OptionSet(static_cast(rawValue), FromRawValue); + } + + constexpr OptionSet() = default; + + constexpr OptionSet(E e) +: m_storage(static_cast(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 {
[clang] [RISCV] Disable generation of asynchronous unwind tables for RISCV baremetal (PR #81727)
kito-cheng wrote: RISC-V GCC has enabled `-fasynchronous-unwind-tables` and `-funwind-tables` by default for Linux target, and disabled by default for baremetal, so generally LGTM since it align the behavior with GCC, but I would like to wait @asb's response. NOTE: The patch[1] is come from SUSE folks, so I assume it's necessary from the distro's point of view. Ref: [1] https://github.com/gcc-mirror/gcc/commit/3cd08f7168c196d7a481b9ed9f4289fd1f14eea8 https://github.com/llvm/llvm-project/pull/81727 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [MC/DC] Refactor: Let MCDCConditionID int16_t with zero-origin (PR #81257)
https://github.com/chapuni closed https://github.com/llvm/llvm-project/pull/81257 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] ab76e48 - [MC/DC] Refactor: Let MCDCConditionID int16_t with zero-origin (#81257)
Author: NAKAMURA Takumi Date: 2024-02-15T16:24:37+09:00 New Revision: ab76e48ac2c2dbfc7d6a600b9b0dd0672e6d9439 URL: https://github.com/llvm/llvm-project/commit/ab76e48ac2c2dbfc7d6a600b9b0dd0672e6d9439 DIFF: https://github.com/llvm/llvm-project/commit/ab76e48ac2c2dbfc7d6a600b9b0dd0672e6d9439.diff LOG: [MC/DC] Refactor: Let MCDCConditionID int16_t with zero-origin (#81257) Also, Let `NumConditions` `uint16_t`. It is smarter to handle the ID as signed. Narrowing to `int16_t` will reduce costs of handling byvalue. (See also #81221 and #81227) External behavior doesn't change. They below handle values as internal values plus 1. * `-dump-coverage-mapping` * `CoverageMappingReader.cpp` * `CoverageMappingWriter.cpp` Added: Modified: clang/lib/CodeGen/CodeGenPGO.cpp clang/lib/CodeGen/CodeGenPGO.h clang/lib/CodeGen/CoverageMappingGen.cpp llvm/include/llvm/ProfileData/Coverage/MCDCTypes.h llvm/lib/ProfileData/Coverage/CoverageMapping.cpp llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp llvm/unittests/ProfileData/CoverageMappingTest.cpp Removed: diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index b5ce1aad7ea1e5..48c5e68a3b7ba4 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -1031,7 +1031,7 @@ void CodeGenPGO::emitCounterRegionMapping(const Decl *D) { std::string CoverageMapping; llvm::raw_string_ostream OS(CoverageMapping); - RegionMCDCState->CondIDMap.clear(); + RegionCondIDMap.reset(new llvm::DenseMap); CoverageMappingGen MappingGen( *CGM.getCoverageMapping(), CGM.getContext().getSourceManager(), CGM.getLangOpts(), RegionCounterMap.get(), RegionMCDCState.get()); @@ -1195,8 +1195,8 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy , const Expr *S, return; // Extract the ID of the condition we are setting in the bitmap. - unsigned CondID = ExprMCDCConditionIDMapIterator->second; - assert(CondID > 0 && "Condition has no ID!"); + auto CondID = ExprMCDCConditionIDMapIterator->second; + assert(CondID >= 0 && "Condition has no ID!"); auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext()); @@ -1205,7 +1205,7 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy , const Expr *S, // the resulting value is used to update the boolean expression's bitmap. llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy), Builder.getInt64(FunctionHash), - Builder.getInt32(CondID - 1), + Builder.getInt32(CondID), MCDCCondBitmapAddr.getPointer(), Val}; Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update), diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h index d3c2b277238fc7..369bf05b59a0d2 100644 --- a/clang/lib/CodeGen/CodeGenPGO.h +++ b/clang/lib/CodeGen/CodeGenPGO.h @@ -36,6 +36,8 @@ class CodeGenPGO { unsigned NumRegionCounters; uint64_t FunctionHash; std::unique_ptr> RegionCounterMap; + std::unique_ptr> RegionMCDCBitmapMap; + std::unique_ptr> RegionCondIDMap; std::unique_ptr> StmtCountMap; std::unique_ptr ProfRecord; std::unique_ptr RegionMCDCState; diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 93c3c31e71fa83..fdf821a0eb6928 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -686,11 +686,12 @@ struct MCDCCoverageBuilder { llvm::SmallVector DecisionStack; MCDC::State llvm::DenseMap - mcdc::ConditionID NextID = 1; + mcdc::ConditionID NextID = 0; bool NotMapped = false; - /// Represent a sentinel value of [0,0] for the bottom of DecisionStack. - static constexpr mcdc::ConditionIDs DecisionStackSentinel{0, 0}; + /// Represent a sentinel value as a pair of final decisions for the bottom + // of DecisionStack. + static constexpr mcdc::ConditionIDs DecisionStackSentinel{-1, -1}; /// Is this a logical-AND operation? bool isLAnd(const BinaryOperator *E) const { @@ -705,12 +706,12 @@ struct MCDCCoverageBuilder { /// Return whether the build of the control flow map is at the top-level /// (root) of a logical operator nest in a boolean expression prior to the /// assignment of condition IDs. - bool isIdle() const { return (NextID == 1 && !NotMapped); } + bool isIdle() const { return (NextID == 0 && !NotMapped); } /// Return whether any IDs have been assigned in the build of the control /// flow map, indicating that the map is being generated for this boolean /// expression. - bool isBuilding() const { return (NextID > 1); } + bool isBuilding() const { return (NextID > 0); } /// Set the given condition's ID.
[clang-tools-extra] Add support for renaming objc methods, even those with multiple selector pieces (PR #76466)
@@ -538,11 +564,222 @@ std::optional checkName(const NamedDecl , Conflict->getLocation().printToString(ASTCtx.getSourceManager())}; } } - if (Result) + if (Result) { InvalidNameMetric.record(1, toString(Result->K)); +return makeError(*Result); + } + return llvm::Error::success(); +} + +bool isSelectorLike(const syntax::Token , const syntax::Token ) { + return Cur.kind() == tok::identifier && Next.kind() == tok::colon && + // We require the selector name and : to be contiguous. + // e.g. support `foo:` but not `foo :`. + Cur.endLocation() == Next.location(); +} + +bool isMatchingSelectorName(const syntax::Token , const syntax::Token , +const SourceManager , +llvm::StringRef SelectorName) { + if (SelectorName.empty()) +return Cur.kind() == tok::colon; + return isSelectorLike(Cur, Next) && Cur.text(SM) == SelectorName; +} + +// Scan through Tokens to find ranges for each selector fragment in Sel at the +// top level (not nested in any () or {} or []). The search will terminate upon +// seeing Terminator or a ; at the top level. +std::optional +findAllSelectorPieces(llvm::ArrayRef Tokens, + const SourceManager , Selector Sel, + tok::TokenKind Terminator) { + + unsigned NumArgs = Sel.getNumArgs(); + llvm::SmallVector Closes; + std::vector SelectorPieces; + unsigned Last = Tokens.size() - 1; kadircet wrote: nit: `Last` is not used outside the loop, and it's still confusing me to see loop condition below as `Index < Last`. what about `for (unsigned Index = 0, Last = Tokens.size(); Index < Last - 1; ++Index)` https://github.com/llvm/llvm-project/pull/76466 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add support for renaming objc methods, even those with multiple selector pieces (PR #76466)
@@ -538,11 +564,222 @@ std::optional checkName(const NamedDecl , Conflict->getLocation().printToString(ASTCtx.getSourceManager())}; } } - if (Result) + if (Result) { InvalidNameMetric.record(1, toString(Result->K)); +return makeError(*Result); + } + return llvm::Error::success(); +} + +bool isSelectorLike(const syntax::Token , const syntax::Token ) { + return Cur.kind() == tok::identifier && Next.kind() == tok::colon && + // We require the selector name and : to be contiguous. + // e.g. support `foo:` but not `foo :`. + Cur.endLocation() == Next.location(); +} + +bool isMatchingSelectorName(const syntax::Token , const syntax::Token , +const SourceManager , +llvm::StringRef SelectorName) { + if (SelectorName.empty()) +return Cur.kind() == tok::colon; + return isSelectorLike(Cur, Next) && Cur.text(SM) == SelectorName; +} + +// Scan through Tokens to find ranges for each selector fragment in Sel at the +// top level (not nested in any () or {} or []). The search will terminate upon +// seeing Terminator or a ; at the top level. +std::optional +findAllSelectorPieces(llvm::ArrayRef Tokens, + const SourceManager , Selector Sel, + tok::TokenKind Terminator) { + + unsigned NumArgs = Sel.getNumArgs(); + llvm::SmallVector Closes; + std::vector SelectorPieces; + unsigned Last = Tokens.size() - 1; + for (unsigned Index = 0; Index < Last; ++Index) { +const auto = Tokens[Index]; + +if (Closes.empty()) { + auto PieceCount = SelectorPieces.size(); + if (PieceCount < NumArgs && + isMatchingSelectorName(Tok, Tokens[Index + 1], SM, + Sel.getNameForSlot(PieceCount))) { +// If 'foo:' instead of ':' (empty selector), we need to skip the ':' kadircet wrote: as discussed we aren't actually handling this case probably (we won't have a token for an empty selector name). can you just leave a comment explaining what & why it doesn't work (i don't necessarily see it as a TODO, as utility/complexity ratio is pretty low)? https://github.com/llvm/llvm-project/pull/76466 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add support for renaming objc methods, even those with multiple selector pieces (PR #76466)
@@ -696,7 +982,7 @@ renameOutsideFile(const NamedDecl , llvm::StringRef MainFilePath, FilePath); } auto RenameEdit = -buildRenameEdit(FilePath, AffectedFileCode, *RenameRanges, NewName); +buildRenameEdit(FilePath, AffectedFileCode, *RenameRanges, NewNames); kadircet wrote: as discussed yesterday, i was suggesting to move: ``` llvm::SmallVector NewNames; NewName.split(NewNames, ":"); ``` from lines 928/936 to right before this call to `buildRenameEdit` https://github.com/llvm/llvm-project/pull/76466 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add support for renaming objc methods, even those with multiple selector pieces (PR #76466)
@@ -538,11 +564,222 @@ std::optional checkName(const NamedDecl , Conflict->getLocation().printToString(ASTCtx.getSourceManager())}; } } - if (Result) + if (Result) { InvalidNameMetric.record(1, toString(Result->K)); +return makeError(*Result); + } + return llvm::Error::success(); +} + +bool isSelectorLike(const syntax::Token , const syntax::Token ) { + return Cur.kind() == tok::identifier && Next.kind() == tok::colon && + // We require the selector name and : to be contiguous. + // e.g. support `foo:` but not `foo :`. + Cur.endLocation() == Next.location(); +} + +bool isMatchingSelectorName(const syntax::Token , const syntax::Token , +const SourceManager , +llvm::StringRef SelectorName) { + if (SelectorName.empty()) +return Cur.kind() == tok::colon; + return isSelectorLike(Cur, Next) && Cur.text(SM) == SelectorName; +} + +// Scan through Tokens to find ranges for each selector fragment in Sel at the +// top level (not nested in any () or {} or []). The search will terminate upon +// seeing Terminator or a ; at the top level. +std::optional +findAllSelectorPieces(llvm::ArrayRef Tokens, + const SourceManager , Selector Sel, + tok::TokenKind Terminator) { + kadircet wrote: `assert(!Tokens.empty())` https://github.com/llvm/llvm-project/pull/76466 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add support for renaming objc methods, even those with multiple selector pieces (PR #76466)
https://github.com/kadircet approved this pull request. thanks, lgtm! https://github.com/llvm/llvm-project/pull/76466 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add support for renaming objc methods, even those with multiple selector pieces (PR #76466)
@@ -538,11 +564,222 @@ std::optional checkName(const NamedDecl , Conflict->getLocation().printToString(ASTCtx.getSourceManager())}; } } - if (Result) + if (Result) { InvalidNameMetric.record(1, toString(Result->K)); +return makeError(*Result); + } + return llvm::Error::success(); +} + +bool isSelectorLike(const syntax::Token , const syntax::Token ) { + return Cur.kind() == tok::identifier && Next.kind() == tok::colon && + // We require the selector name and : to be contiguous. + // e.g. support `foo:` but not `foo :`. + Cur.endLocation() == Next.location(); +} + +bool isMatchingSelectorName(const syntax::Token , const syntax::Token , +const SourceManager , +llvm::StringRef SelectorName) { + if (SelectorName.empty()) +return Cur.kind() == tok::colon; + return isSelectorLike(Cur, Next) && Cur.text(SM) == SelectorName; +} + +// Scan through Tokens to find ranges for each selector fragment in Sel at the +// top level (not nested in any () or {} or []). The search will terminate upon kadircet wrote: but that's true for this function, as it's achieved by the outer loop that calls this function in `collectRenameIdentifierRanges`. in here we're only trying to match `Sel` assuming its first segment is located at `Tokens.front()`. https://github.com/llvm/llvm-project/pull/76466 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] Add support for renaming objc methods, even those with multiple selector pieces (PR #76466)
https://github.com/kadircet edited https://github.com/llvm/llvm-project/pull/76466 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][AArch64] multilib: fix deduction of "-march=" option (PR #81474)
https://github.com/domin144 updated https://github.com/llvm/llvm-project/pull/81474 From e25d580c7297071f067200639d8b8fe3be74eec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20W=C3=B3jt?= Date: Mon, 12 Feb 2024 13:38:14 +0100 Subject: [PATCH 1/2] [clang][AArch64] multilib: fix deduction of "-march=" option The deduced "-march=" option always started with aarch64, which is not a valid value. There was also no way to distinguish between armv8-r and armv8-a. After this commit, the deduced "-march=" option will start with greatest available "armv*-a" value or "armv8-r". --- clang/lib/Driver/ToolChain.cpp | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 657577cea6c7d8..623d52e9471f23 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -191,7 +191,11 @@ static void getAArch64MultilibFlags(const Driver , for (const auto : AArch64::Extensions) if (FeatureSet.contains(Ext.NegFeature)) MArch.push_back(("no" + Ext.Name).str()); - MArch.insert(MArch.begin(), ("-march=" + Triple.getArchName()).str()); + StringRef ArchName; + for (const auto : AArch64::ArchInfos) +if (FeatureSet.contains(ArchInfo->ArchFeature)) + ArchName = ArchInfo->Name; + MArch.insert(MArch.begin(), ("-march=" + ArchName).str()); Result.push_back(llvm::join(MArch, "+")); } From e3c59b8e5915881ce34f7b064c31268f8b1a843a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20W=C3=B3jt?= Date: Mon, 12 Feb 2024 14:46:26 +0100 Subject: [PATCH 2/2] fix tests --- clang/test/Driver/print-multi-selection-flags.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/Driver/print-multi-selection-flags.c b/clang/test/Driver/print-multi-selection-flags.c index 248d9a3cdf49b2..06a12db9d97792 100644 --- a/clang/test/Driver/print-multi-selection-flags.c +++ b/clang/test/Driver/print-multi-selection-flags.c @@ -51,9 +51,10 @@ // CHECK-M85_NO_FP_DP: -mfpu=fp-armv8-fullfp16-sp-d16 // RUN: %clang -print-multi-flags-experimental --target=aarch64-none-elf -march=armv8-a+lse | FileCheck --check-prefix=CHECK-LSE %s -// CHECK-LSE: -march=aarch64{{.*}}+lse{{.*}} +// CHECK-LSE: --target=aarch64-none-unknown-elf +// CHECK-LSE: -march=armv8-a{{.*}}+lse{{.*}} // RUN: %clang -print-multi-flags-experimental --target=aarch64-none-elf -march=armv8.5-a+sve+sve2 | FileCheck --check-prefix=CHECK-SVE2 %s // RUN: %clang -print-multi-flags-experimental --target=aarch64-none-elf -march=armv9-a| FileCheck --check-prefix=CHECK-SVE2 %s // CHECK-SVE2: --target=aarch64-none-unknown-elf -// CHECK-SVE2: -march=aarch64{{.*}}+simd{{.*}}+sve{{.*}}+sve2{{.*}} +// CHECK-SVE2: -march=armv{{.*}}-a{{.*}}+simd{{.*}}+sve{{.*}}+sve2{{.*}} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [ASAN] For Asan instrumented global, emit two symbols, one with actual size and other with instrumented size. (PR #70166)
skc7 wrote: Hi @hctim, In this patch, we are identifying globals that are instrumented using an new IR attribute and for them extra symbol with padded size is emitted. This is done only in ASAN pass. Not sure how would that affect HWAsan and MTE-globals. Could you please give an example for this ? At AMD, we have complex HPC/AI applications and libraries and this patch seems to not create any issue as such. Could you please give a concrete example test case where this patch would create an issue? https://github.com/llvm/llvm-project/pull/70166 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 36adfec - Adding support of AMDLIBM vector library (#78560)
Author: Rohit Aggarwal Date: 2024-02-15T12:13:07+05:30 New Revision: 36adfec155de366d722f2bac8ff9162289dcf06c URL: https://github.com/llvm/llvm-project/commit/36adfec155de366d722f2bac8ff9162289dcf06c DIFF: https://github.com/llvm/llvm-project/commit/36adfec155de366d722f2bac8ff9162289dcf06c.diff LOG: Adding support of AMDLIBM vector library (#78560) Hi, AMD has it's own implementation of vector calls. This patch include the changes to enable the use of AMD's math library using -fveclib=AMDLIBM. Please refer https://github.com/amd/aocl-libm-ose - Co-authored-by: Rohit Aggarwal Added: llvm/test/Transforms/LoopVectorize/X86/amdlibm-calls-finite.ll llvm/test/Transforms/LoopVectorize/X86/amdlibm-calls.ll Modified: clang/include/clang/Driver/Options.td clang/test/Driver/autocomplete.c llvm/include/llvm/Analysis/TargetLibraryInfo.h llvm/include/llvm/Analysis/VecFuncs.def llvm/include/llvm/Frontend/Driver/CodeGenOptions.h llvm/lib/Analysis/TargetLibraryInfo.cpp llvm/lib/Frontend/Driver/CodeGenOptions.cpp llvm/test/CodeGen/Generic/replace-intrinsics-with-veclib.ll llvm/test/Transforms/SLPVectorizer/X86/sin-sqrt.ll llvm/test/Transforms/Util/add-TLI-mappings.ll Removed: diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 95b464e7d61834..b302afd65e2811 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3204,10 +3204,10 @@ def fno_experimental_isel : Flag<["-"], "fno-experimental-isel">, Group, - Values<"Accelerate,libmvec,MASSV,SVML,SLEEF,Darwin_libsystem_m,ArmPL,none">, + Values<"Accelerate,libmvec,MASSV,SVML,SLEEF,Darwin_libsystem_m,ArmPL,AMDLIBM,none">, NormalizedValuesScope<"llvm::driver::VectorLibrary">, NormalizedValues<["Accelerate", "LIBMVEC", "MASSV", "SVML", "SLEEF", - "Darwin_libsystem_m", "ArmPL", "NoLibrary"]>, + "Darwin_libsystem_m", "ArmPL", "AMDLIBM", "NoLibrary"]>, MarshallingInfoEnum, "NoLibrary">; def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group, Alias, AliasArgs<["none"]>; diff --git a/clang/test/Driver/autocomplete.c b/clang/test/Driver/autocomplete.c index d6f57708b67eb6..c8ceaaf404672f 100644 --- a/clang/test/Driver/autocomplete.c +++ b/clang/test/Driver/autocomplete.c @@ -80,6 +80,7 @@ // FLTOALL-NEXT: thin // RUN: %clang --autocomplete=-fveclib= | FileCheck %s -check-prefix=FVECLIBALL // FVECLIBALL: Accelerate +// FVECLIBALL-NEXT: AMDLIBM // FVECLIBALL-NEXT: ArmPL // FVECLIBALL-NEXT: Darwin_libsystem_m // FVECLIBALL-NEXT: libmvec diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.h b/llvm/include/llvm/Analysis/TargetLibraryInfo.h index daf1d8e2079f85..46f31f918e7b61 100644 --- a/llvm/include/llvm/Analysis/TargetLibraryInfo.h +++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.h @@ -129,7 +129,8 @@ class TargetLibraryInfoImpl { MASSV,// IBM MASS vector library. SVML, // Intel short vector math library. SLEEFGNUABI, // SLEEF - SIMD Library for Evaluating Elementary Functions. -ArmPL// Arm Performance Libraries. +ArmPL, // Arm Performance Libraries. +AMDLIBM // AMD Math Vector library. }; TargetLibraryInfoImpl(); diff --git a/llvm/include/llvm/Analysis/VecFuncs.def b/llvm/include/llvm/Analysis/VecFuncs.def index 07edf68c667a27..394e4a05fbc0cf 100644 --- a/llvm/include/llvm/Analysis/VecFuncs.def +++ b/llvm/include/llvm/Analysis/VecFuncs.def @@ -1067,6 +1067,199 @@ TLI_DEFINE_VECFUNC("tgammaf", "armpl_vtgammaq_f32", FIXED(4), NOMASK, "_ZGV_LLVM TLI_DEFINE_VECFUNC("tgamma", "armpl_svtgamma_f64_x", SCALABLE(2), MASKED, "_ZGVsMxv") TLI_DEFINE_VECFUNC("tgammaf", "armpl_svtgamma_f32_x", SCALABLE(4), MASKED, "_ZGVsMxv") +#elif defined(TLI_DEFINE_AMDLIBM_VECFUNCS) +TLI_DEFINE_VECFUNC("sinf", "amd_vrs16_sinf", FIXED(16), NOMASK, "_ZGV_LLVM_N16v") +TLI_DEFINE_VECFUNC("sinf", "amd_vrs8_sinf", FIXED(8), NOMASK, "_ZGV_LLVM_N8v") +TLI_DEFINE_VECFUNC("sinf", "amd_vrs4_sinf", FIXED(4), NOMASK, "_ZGV_LLVM_N4v") +TLI_DEFINE_VECFUNC("sin", "amd_vrd8_sin", FIXED(8), NOMASK, "_ZGV_LLVM_N8v") +TLI_DEFINE_VECFUNC("sin", "amd_vrd4_sin", FIXED(4), NOMASK, "_ZGV_LLVM_N4v") +TLI_DEFINE_VECFUNC("sin", "amd_vrd2_sin", FIXED(2), NOMASK, "_ZGV_LLVM_N2v") + +TLI_DEFINE_VECFUNC("llvm.sin.f32", "amd_vrs16_sinf", FIXED(16), NOMASK, "_ZGV_LLVM_N16v") +TLI_DEFINE_VECFUNC("llvm.sin.f32", "amd_vrs8_sinf", FIXED(8), NOMASK, "_ZGV_LLVM_N8v") +TLI_DEFINE_VECFUNC("llvm.sin.f32", "amd_vrs4_sinf", FIXED(4), NOMASK, "_ZGV_LLVM_N4v") +TLI_DEFINE_VECFUNC("llvm.sin.f64", "amd_vrd8_sin", FIXED(8), NOMASK, "_ZGV_LLVM_N8v") +TLI_DEFINE_VECFUNC("llvm.sin.f64", "amd_vrd4_sin", FIXED(4), NOMASK, "_ZGV_LLVM_N4v") +TLI_DEFINE_VECFUNC("llvm.sin.f64", "amd_vrd2_sin", FIXED(2), NOMASK,
[clang] [llvm] Adding support of AMDLIBM vector library (PR #78560)
https://github.com/ganeshgit closed https://github.com/llvm/llvm-project/pull/78560 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] b93916c - [clang][Interp][NFC] Convert test to verify=expected,both style
Author: Timm Bäder Date: 2024-02-15T07:23:35+01:00 New Revision: b93916c9798ea09488e30b9b0aae9e54ef0b1956 URL: https://github.com/llvm/llvm-project/commit/b93916c9798ea09488e30b9b0aae9e54ef0b1956 DIFF: https://github.com/llvm/llvm-project/commit/b93916c9798ea09488e30b9b0aae9e54ef0b1956.diff LOG: [clang][Interp][NFC] Convert test to verify=expected,both style Added: Modified: clang/test/AST/Interp/functions.cpp Removed: diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 34a832c794c75d..320691336bdd99 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -verify=ref %s -// RUN: %clang_cc1 -std=c++14 -verify=ref %s -// RUN: %clang_cc1 -std=c++20 -verify=ref %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -verify=ref,both %s +// RUN: %clang_cc1 -std=c++14 -verify=ref,both %s +// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s constexpr void doNothing() {} constexpr int gimme5() { @@ -23,16 +23,13 @@ static_assert(!identity(false), ""); template constexpr bool sameSize() { - static_assert(sizeof(A) == sizeof(B), ""); // expected-error {{static assertion failed}} \ - // ref-error {{static assertion failed}} \ - // expected-note {{evaluates to}} \ - // ref-note {{evaluates to}} + static_assert(sizeof(A) == sizeof(B), ""); // both-error {{static assertion failed}} \ + // both-note {{evaluates to}} return true; } static_assert(sameSize(), ""); static_assert(sameSize(), ""); -static_assert(sameSize(), ""); // expected-note {{in instantiation of function template specialization}} \ - // ref-note {{in instantiation of function template specialization}} +static_assert(sameSize(), ""); // both-note {{in instantiation of function template specialization}} constexpr auto add(int a, int b) -> int { @@ -92,12 +89,9 @@ static_assert(getNum<-2>() == -2, ""); static_assert(getNum<10>() == 10, ""); static_assert(getNum() == 5, ""); -constexpr int f(); // expected-note {{declared here}} \ - // ref-note {{declared here}} -static_assert(f() == 5, ""); // expected-error {{not an integral constant expression}} \ - // expected-note {{undefined function 'f'}} \ - // ref-error {{not an integral constant expression}} \ - // ref-note {{undefined function 'f'}} +constexpr int f(); // both-note {{declared here}} +static_assert(f() == 5, ""); // both-error {{not an integral constant expression}} \ + // both-note {{undefined function 'f'}} constexpr int a() { return f(); } @@ -108,17 +102,14 @@ static_assert(a() == 5, ""); constexpr int invalid() { // Invalid expression in visit(). - while(huh) {} // expected-error {{use of undeclared identifier}} \ -// ref-error {{use of undeclared identifier}} - + while(huh) {} // both-error {{use of undeclared identifier}} return 0; } constexpr void invalid2() { int i = 0; // Invalid expression in discard(). - huh(); // expected-error {{use of undeclared identifier}} \ - // ref-error {{use of undeclared identifier}} + huh(); // both-error {{use of undeclared identifier}} } namespace FunctionPointers { @@ -160,8 +151,7 @@ namespace FunctionReturnType { constexpr ptr fun() { return } - static_assert(fun() == nullptr, ""); // expected-error {{static assertion failed}} \ - // ref-error {{static assertion failed}} + static_assert(fun() == nullptr, ""); // both-error {{static assertion failed}} constexpr int foo() { int (*f)(int *) = fun(); @@ -188,32 +178,23 @@ namespace FunctionReturnType { constexpr int (*op2)(int, int) = nullptr; static_assert(!op2, ""); - int m() { return 5;} // ref-note {{declared here}} \ - // expected-note {{declared here}} + int m() { return 5;} // both-note {{declared here}} constexpr int (*invalidFnPtr)() = m; - static_assert(invalidFnPtr() == 5, ""); // ref-error {{not an integral constant expression}} \ - //
[clang] [clang][Interp] Do r-to-l conversion immediately when returning (PR #80662)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/80662 >From b93916c9798ea09488e30b9b0aae9e54ef0b1956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Thu, 15 Feb 2024 07:03:58 +0100 Subject: [PATCH 1/2] [clang][Interp][NFC] Convert test to verify=expected,both style --- clang/test/AST/Interp/functions.cpp | 198 ++-- 1 file changed, 68 insertions(+), 130 deletions(-) diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 34a832c794c75d..320691336bdd99 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -1,9 +1,9 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify %s -// RUN: %clang_cc1 -verify=ref %s -// RUN: %clang_cc1 -std=c++14 -verify=ref %s -// RUN: %clang_cc1 -std=c++20 -verify=ref %s +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -verify=ref,both %s +// RUN: %clang_cc1 -std=c++14 -verify=ref,both %s +// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s constexpr void doNothing() {} constexpr int gimme5() { @@ -23,16 +23,13 @@ static_assert(!identity(false), ""); template constexpr bool sameSize() { - static_assert(sizeof(A) == sizeof(B), ""); // expected-error {{static assertion failed}} \ - // ref-error {{static assertion failed}} \ - // expected-note {{evaluates to}} \ - // ref-note {{evaluates to}} + static_assert(sizeof(A) == sizeof(B), ""); // both-error {{static assertion failed}} \ + // both-note {{evaluates to}} return true; } static_assert(sameSize(), ""); static_assert(sameSize(), ""); -static_assert(sameSize(), ""); // expected-note {{in instantiation of function template specialization}} \ - // ref-note {{in instantiation of function template specialization}} +static_assert(sameSize(), ""); // both-note {{in instantiation of function template specialization}} constexpr auto add(int a, int b) -> int { @@ -92,12 +89,9 @@ static_assert(getNum<-2>() == -2, ""); static_assert(getNum<10>() == 10, ""); static_assert(getNum() == 5, ""); -constexpr int f(); // expected-note {{declared here}} \ - // ref-note {{declared here}} -static_assert(f() == 5, ""); // expected-error {{not an integral constant expression}} \ - // expected-note {{undefined function 'f'}} \ - // ref-error {{not an integral constant expression}} \ - // ref-note {{undefined function 'f'}} +constexpr int f(); // both-note {{declared here}} +static_assert(f() == 5, ""); // both-error {{not an integral constant expression}} \ + // both-note {{undefined function 'f'}} constexpr int a() { return f(); } @@ -108,17 +102,14 @@ static_assert(a() == 5, ""); constexpr int invalid() { // Invalid expression in visit(). - while(huh) {} // expected-error {{use of undeclared identifier}} \ -// ref-error {{use of undeclared identifier}} - + while(huh) {} // both-error {{use of undeclared identifier}} return 0; } constexpr void invalid2() { int i = 0; // Invalid expression in discard(). - huh(); // expected-error {{use of undeclared identifier}} \ - // ref-error {{use of undeclared identifier}} + huh(); // both-error {{use of undeclared identifier}} } namespace FunctionPointers { @@ -160,8 +151,7 @@ namespace FunctionReturnType { constexpr ptr fun() { return } - static_assert(fun() == nullptr, ""); // expected-error {{static assertion failed}} \ - // ref-error {{static assertion failed}} + static_assert(fun() == nullptr, ""); // both-error {{static assertion failed}} constexpr int foo() { int (*f)(int *) = fun(); @@ -188,32 +178,23 @@ namespace FunctionReturnType { constexpr int (*op2)(int, int) = nullptr; static_assert(!op2, ""); - int m() { return 5;} // ref-note {{declared here}} \ - // expected-note {{declared here}} + int m() { return 5;} // both-note {{declared here}} constexpr int (*invalidFnPtr)() = m; - static_assert(invalidFnPtr() == 5, ""); // ref-error {{not an integral constant expression}} \ - // ref-note {{non-constexpr function
[clang] b200dfc - [clang][Interp] Fix calling invalid function pointers
Author: Timm Bäder Date: 2024-02-15T07:23:35+01:00 New Revision: b200dfc15904f0f7f19443fd5a399242c80213dc URL: https://github.com/llvm/llvm-project/commit/b200dfc15904f0f7f19443fd5a399242c80213dc DIFF: https://github.com/llvm/llvm-project/commit/b200dfc15904f0f7f19443fd5a399242c80213dc.diff LOG: [clang][Interp] Fix calling invalid function pointers Checking for isConstexpr() is wrong; we need to (try to) call the function and let later code diagnose the failure accordingly. Added: Modified: clang/lib/AST/Interp/Interp.h clang/test/AST/Interp/functions.cpp Removed: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 77c724f08e8eef..5bbb9f169a800e 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2071,8 +2071,7 @@ inline bool CallPtr(InterpState , CodePtr OpPC, uint32_t ArgSize) { const FunctionPointer = S.Stk.pop(); const Function *F = FuncPtr.getFunction(); - if (!F || !F->isConstexpr()) -return false; + assert(F); assert(ArgSize >= F->getWrittenArgSize()); uint32_t VarArgSize = ArgSize - F->getWrittenArgSize(); diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index 7b8278cf13aa88..34a832c794c75d 100644 --- a/clang/test/AST/Interp/functions.cpp +++ b/clang/test/AST/Interp/functions.cpp @@ -187,6 +187,14 @@ namespace FunctionReturnType { static_assert(!!op, ""); constexpr int (*op2)(int, int) = nullptr; static_assert(!op2, ""); + + int m() { return 5;} // ref-note {{declared here}} \ + // expected-note {{declared here}} + constexpr int (*invalidFnPtr)() = m; + static_assert(invalidFnPtr() == 5, ""); // ref-error {{not an integral constant expression}} \ + // ref-note {{non-constexpr function 'm'}} \ + // expected-error {{not an integral constant expression}} \ + // expected-note {{non-constexpr function 'm'}} } namespace Comparison { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang] Use separator for large numeric values in overflow diagnostic (PR #80939)
https://github.com/Atousa updated https://github.com/llvm/llvm-project/pull/80939 >From ac75fc2873fc7b8eec6c24ba97f4673e94457c8e Mon Sep 17 00:00:00 2001 From: Atousa Duprat Date: Tue, 6 Feb 2024 21:02:05 -0800 Subject: [PATCH 1/5] [clang] Use separator for large numeric values in overflow diagnostic Add functionality to APInt::toString() that allows it to insert separators between groups of digits, using the C++ litteral separator ' between groups. Fixes issue #58228 --- clang/lib/AST/ExprConstant.cpp | 6 +- clang/test/AST/Interp/c.c | 4 +- clang/test/C/drs/dr0xx.c| 2 +- clang/test/C/drs/dr2xx.c| 2 +- clang/test/Sema/integer-overflow.c | 100 - clang/test/Sema/switch-1.c | 6 +- clang/test/SemaCXX/enum.cpp | 4 +- clang/test/SemaCXX/integer-overflow.cpp | 112 ++-- clang/test/SemaObjC/integer-overflow.m | 4 +- clang/test/SemaObjC/objc-literal-nsnumber.m | 2 +- llvm/include/llvm/ADT/APInt.h | 3 +- llvm/include/llvm/ADT/StringExtras.h| 5 +- llvm/lib/Support/APInt.cpp | 24 - llvm/unittests/ADT/APIntTest.cpp| 35 ++ 14 files changed, 185 insertions(+), 124 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 089bc2094567f7..d9037072c6767f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2774,7 +2774,8 @@ static bool CheckedIntArithmetic(EvalInfo , const Expr *E, if (Info.checkingForUndefinedBehavior()) Info.Ctx.getDiagnostics().Report(E->getExprLoc(), diag::warn_integer_constant_overflow) - << toString(Result, 10) << E->getType() << E->getSourceRange(); + << toString(Result, 10, Result.isSigned(), false, true, true) + << E->getType() << E->getSourceRange(); return HandleOverflow(Info, E, Value, E->getType()); } return true; @@ -13852,7 +13853,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { if (Info.checkingForUndefinedBehavior()) Info.Ctx.getDiagnostics().Report(E->getExprLoc(), diag::warn_integer_constant_overflow) -<< toString(Value, 10) << E->getType() << E->getSourceRange(); +<< toString(Value, 10, Value.isSigned(), false, true, true) +<< E->getType() << E->getSourceRange(); if (!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), E->getType())) diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 9ab271a82aeef9..aa067b0bc74831 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -109,9 +109,9 @@ int somefunc(int i) { // pedantic-expected-warning {{left operand of comma operator has no effect}} \ // pedantic-expected-warning {{overflow in expression; result is 131073}} \ // ref-warning {{left operand of comma operator has no effect}} \ - // ref-warning {{overflow in expression; result is 131073}} \ + // ref-warning {{overflow in expression; result is 131'073}} \ // pedantic-ref-warning {{left operand of comma operator has no effect}} \ - // pedantic-ref-warning {{overflow in expression; result is 131073}} + // pedantic-ref-warning {{overflow in expression; result is 131'073}} } diff --git a/clang/test/C/drs/dr0xx.c b/clang/test/C/drs/dr0xx.c index d9c1fbe4ee40ab..c93cfb63d604cf 100644 --- a/clang/test/C/drs/dr0xx.c +++ b/clang/test/C/drs/dr0xx.c @@ -214,7 +214,7 @@ _Static_assert(__builtin_types_compatible_p(struct S { int a; }, union U { int a */ void dr031(int i) { switch (i) { - case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */ + case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch" /* Silence the targets which issue: diff --git a/clang/test/C/drs/dr2xx.c b/clang/test/C/drs/dr2xx.c index 9c8d77518ab55e..1b68b65acca6af 100644 --- a/clang/test/C/drs/dr2xx.c +++ b/clang/test/C/drs/dr2xx.c @@ -277,7 +277,7 @@ void dr258(void) { void dr261(void) { /* This is still an integer constant expression despite the overflow. */ enum e1 { -ex1 = __INT_MAX__ + 1 /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */ +ex1 = __INT_MAX__ + 1 /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */ }; /* This is not an integer constant
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
JustinStitt wrote: My original idea was to get the SIO sanitizer working with `-fwrapv`, the issue [here](https://github.com/KSPP/linux/issues/26) even suggests it as a viable option. However, after seeing literal checks like: ```cpp case LangOptions::SOB_Undefined: if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow)) ``` ... I think the best option is to instrument a wrap sanitizer (which this PR does). A wrap sanitizer best captures the language semantics at hand while maintaining existing functionality of the SIO sanitizer. I think Kees can speak first hand about how picky some folks are about the language being used for this arithmetic overflow/wraparound stuff (he linked some gcc threads above my comment but I've also seen some spicy LKML discussions about how OVERFLOW doesn't exist in the Linux Kernel and as such WRAPAROUND instrumentation is needed). I think this PR bridges the gap between folks like Kees (who just want all this suspicious kernel arithmetic to go away) and folks like Linus (who is really particular about language). https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6087d7b - [clang-format][NFC] Sort options in Format.cpp
Author: Owen Pan Date: 2024-02-14T21:40:07-08:00 New Revision: 6087d7bc0a9d7d4ad2c94a131c2bc427b767c9d7 URL: https://github.com/llvm/llvm-project/commit/6087d7bc0a9d7d4ad2c94a131c2bc427b767c9d7 DIFF: https://github.com/llvm/llvm-project/commit/6087d7bc0a9d7d4ad2c94a131c2bc427b767c9d7.diff LOG: [clang-format][NFC] Sort options in Format.cpp Added: Modified: clang/lib/Format/Format.cpp Removed: diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 56cd9495920c7b..e67b2101f5821b 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1406,29 +1406,28 @@ static void expandPresetsSpacesInParens(FormatStyle ) { FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { FormatStyle LLVMStyle; - LLVMStyle.InheritsParentConfig = false; - LLVMStyle.Language = Language; LLVMStyle.AccessModifierOffset = -2; - LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right; LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align; LLVMStyle.AlignArrayOfStructures = FormatStyle::AIAS_None; - LLVMStyle.AlignOperands = FormatStyle::OAS_Align; LLVMStyle.AlignConsecutiveAssignments = {}; - LLVMStyle.AlignConsecutiveAssignments.Enabled = false; - LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false; LLVMStyle.AlignConsecutiveAssignments.AcrossComments = false; + LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false; LLVMStyle.AlignConsecutiveAssignments.AlignCompound = false; LLVMStyle.AlignConsecutiveAssignments.AlignFunctionPointers = false; + LLVMStyle.AlignConsecutiveAssignments.Enabled = false; LLVMStyle.AlignConsecutiveAssignments.PadOperators = true; LLVMStyle.AlignConsecutiveBitFields = {}; LLVMStyle.AlignConsecutiveDeclarations = {}; LLVMStyle.AlignConsecutiveMacros = {}; LLVMStyle.AlignConsecutiveShortCaseStatements = {}; + LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right; + LLVMStyle.AlignOperands = FormatStyle::OAS_Align; LLVMStyle.AlignTrailingComments = {}; LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always; LLVMStyle.AlignTrailingComments.OverEmptyLines = 0; LLVMStyle.AllowAllArgumentsOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; + LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never; LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; LLVMStyle.AllowShortCaseLabelsOnASingleLine = false; LLVMStyle.AllowShortCompoundRequirementOnASingleLine = true; @@ -1439,11 +1438,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AllowShortLoopsOnASingleLine = false; LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; - LLVMStyle.BreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; LLVMStyle.AttributeMacros.push_back("__capability"); - LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both; LLVMStyle.BinPackArguments = true; LLVMStyle.BinPackParameters = true; + LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both; LLVMStyle.BracedInitializerIndentWidth = std::nullopt; LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false, /*AfterClass=*/false, @@ -1472,11 +1470,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always; LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; - LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; LLVMStyle.BreakStringLiterals = true; + LLVMStyle.BreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; LLVMStyle.CompactNamespaces = false; @@ -1493,22 +1491,23 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH"); LLVMStyle.IfMacros.push_back("KJ_IF_MAYBE"); + LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; LLVMStyle.IncludeStyle.IncludeCategories = { {"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0, false}, {"^(<|\"(gtest|gmock|isl|json)/)", 3, 0, false}, {".*", 1, 0, false}}; LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; - LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; LLVMStyle.IncludeStyle.MainIncludeChar = tooling::IncludeStyle::MICD_Quote; LLVMStyle.IndentAccessModifiers = false; - LLVMStyle.IndentCaseLabels = false;
[clang] d53515a - [clang][Interp] Fix variadic member functions
Author: Timm Bäder Date: 2024-02-15T05:59:53+01:00 New Revision: d53515afef57a3abf84daff169fbc7626a306817 URL: https://github.com/llvm/llvm-project/commit/d53515afef57a3abf84daff169fbc7626a306817 DIFF: https://github.com/llvm/llvm-project/commit/d53515afef57a3abf84daff169fbc7626a306817.diff LOG: [clang][Interp] Fix variadic member functions For variadic member functions, the way we calculated the instance pointer and RVO pointer offsts on the stack was incorrect, due to Func->getArgSize() not returning the full size of all the passed arguments. When calling variadic functions, we need to pass the size of the passed (variadic) arguments to the Call* ops, so they can use that information to properly check the instance pointer, etc. This patch adds a bit of code duplication in Interp.h, which I will get rid of in later cleanup NFC patches. Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeStmtGen.cpp clang/lib/AST/Interp/Context.cpp clang/lib/AST/Interp/EvalEmitter.cpp clang/lib/AST/Interp/Function.h clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/InterpFrame.cpp clang/lib/AST/Interp/InterpFrame.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/functions.cpp Removed: diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 91b9985eefbd30..988765972a36e6 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1829,8 +1829,19 @@ bool ByteCodeExprGen::VisitCXXConstructExpr( return false; } -if (!this->emitCall(Func, E)) - return false; +if (Func->isVariadic()) { + uint32_t VarArgSize = 0; + unsigned NumParams = Func->getNumWrittenParams(); + for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I) { +VarArgSize += + align(primSize(classify(E->getArg(I)->getType()).value_or(PT_Ptr))); + } + if (!this->emitCallVar(Func, VarArgSize, E)) +return false; +} else { + if (!this->emitCall(Func, 0, E)) +return false; +} // Immediately call the destructor if we have to. if (DiscardResult) { @@ -1863,7 +1874,7 @@ bool ByteCodeExprGen::VisitCXXConstructExpr( return false; } - if (!this->emitCall(Func, E)) + if (!this->emitCall(Func, 0, E)) return false; } return true; @@ -2049,7 +2060,7 @@ bool ByteCodeExprGen::VisitCXXInheritedCtorInitExpr( Offset += align(primSize(PT)); } - return this->emitCall(F, E); + return this->emitCall(F, 0, E); } template @@ -2846,20 +2857,38 @@ bool ByteCodeExprGen::VisitCallExpr(const CallExpr *E) { // and if the function has RVO, we already have the pointer on the stack to // write the result into. if (IsVirtual && !HasQualifier) { - if (!this->emitCallVirt(Func, E)) + uint32_t VarArgSize = 0; + unsigned NumParams = Func->getNumWrittenParams(); + for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I) +VarArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr))); + + if (!this->emitCallVirt(Func, VarArgSize, E)) +return false; +} else if (Func->isVariadic()) { + uint32_t VarArgSize = 0; + unsigned NumParams = Func->getNumWrittenParams(); + for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I) +VarArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr))); + if (!this->emitCallVar(Func, VarArgSize, E)) return false; } else { - if (!this->emitCall(Func, E)) + if (!this->emitCall(Func, 0, E)) return false; } } else { // Indirect call. Visit the callee, which will leave a FunctionPointer on // the stack. Cleanup of the returned value if necessary will be done after // the function call completed. + +// Sum the size of all args from the call expr. +uint32_t ArgSize = 0; +for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + ArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr))); + if (!this->visit(E->getCallee())) return false; -if (!this->emitCallPtr(E)) +if (!this->emitCallPtr(ArgSize, E)) return false; } @@ -3386,7 +3415,7 @@ bool ByteCodeExprGen::emitRecordDestruction(const Descriptor *Desc) { assert(DtorFunc->getNumParams() == 1); if (!this->emitDupPtr(SourceInfo{})) return false; - if (!this->emitCall(DtorFunc, SourceInfo{})) + if (!this->emitCall(DtorFunc, 0, SourceInfo{})) return false; } } diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index bedcc78dc23555..7e2043f8de90b0 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++
[clang] [llvm] [clang] Use separator for large numeric values in overflow diagnostic (PR #80939)
@@ -2187,6 +2188,12 @@ void APInt::toString(SmallVectorImpl , unsigned Radix, bool Signed, } } + // Number of digits in a group between separators. + unsigned Grouping = (Radix == 8 || Radix == 10) ? 3 : 4; + if (Radix == 8 || Radix == 10) { +Grouping = 3; + } + tbaederr wrote: This code block is now unnecessary. https://github.com/llvm/llvm-project/pull/80939 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Fix behavior of `__is_trivially_relocatable(volatile int)` (PR #77092)
AMP999 wrote: Thanks all for the review! @AaronBallman, Could you please land this patch for me? https://github.com/llvm/llvm-project/pull/77092 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [MC/DC] Refactor: Let MCDCConditionID int16_t with zero-origin (PR #81257)
https://github.com/ornata approved this pull request. https://github.com/llvm/llvm-project/pull/81257 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang] Use separator for large numeric values in overflow diagnostic (PR #80939)
https://github.com/Atousa updated https://github.com/llvm/llvm-project/pull/80939 >From ac75fc2873fc7b8eec6c24ba97f4673e94457c8e Mon Sep 17 00:00:00 2001 From: Atousa Duprat Date: Tue, 6 Feb 2024 21:02:05 -0800 Subject: [PATCH 1/5] [clang] Use separator for large numeric values in overflow diagnostic Add functionality to APInt::toString() that allows it to insert separators between groups of digits, using the C++ litteral separator ' between groups. Fixes issue #58228 --- clang/lib/AST/ExprConstant.cpp | 6 +- clang/test/AST/Interp/c.c | 4 +- clang/test/C/drs/dr0xx.c| 2 +- clang/test/C/drs/dr2xx.c| 2 +- clang/test/Sema/integer-overflow.c | 100 - clang/test/Sema/switch-1.c | 6 +- clang/test/SemaCXX/enum.cpp | 4 +- clang/test/SemaCXX/integer-overflow.cpp | 112 ++-- clang/test/SemaObjC/integer-overflow.m | 4 +- clang/test/SemaObjC/objc-literal-nsnumber.m | 2 +- llvm/include/llvm/ADT/APInt.h | 3 +- llvm/include/llvm/ADT/StringExtras.h| 5 +- llvm/lib/Support/APInt.cpp | 24 - llvm/unittests/ADT/APIntTest.cpp| 35 ++ 14 files changed, 185 insertions(+), 124 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 089bc2094567f7..d9037072c6767f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2774,7 +2774,8 @@ static bool CheckedIntArithmetic(EvalInfo , const Expr *E, if (Info.checkingForUndefinedBehavior()) Info.Ctx.getDiagnostics().Report(E->getExprLoc(), diag::warn_integer_constant_overflow) - << toString(Result, 10) << E->getType() << E->getSourceRange(); + << toString(Result, 10, Result.isSigned(), false, true, true) + << E->getType() << E->getSourceRange(); return HandleOverflow(Info, E, Value, E->getType()); } return true; @@ -13852,7 +13853,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { if (Info.checkingForUndefinedBehavior()) Info.Ctx.getDiagnostics().Report(E->getExprLoc(), diag::warn_integer_constant_overflow) -<< toString(Value, 10) << E->getType() << E->getSourceRange(); +<< toString(Value, 10, Value.isSigned(), false, true, true) +<< E->getType() << E->getSourceRange(); if (!HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), E->getType())) diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index 9ab271a82aeef9..aa067b0bc74831 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -109,9 +109,9 @@ int somefunc(int i) { // pedantic-expected-warning {{left operand of comma operator has no effect}} \ // pedantic-expected-warning {{overflow in expression; result is 131073}} \ // ref-warning {{left operand of comma operator has no effect}} \ - // ref-warning {{overflow in expression; result is 131073}} \ + // ref-warning {{overflow in expression; result is 131'073}} \ // pedantic-ref-warning {{left operand of comma operator has no effect}} \ - // pedantic-ref-warning {{overflow in expression; result is 131073}} + // pedantic-ref-warning {{overflow in expression; result is 131'073}} } diff --git a/clang/test/C/drs/dr0xx.c b/clang/test/C/drs/dr0xx.c index d9c1fbe4ee40ab..c93cfb63d604cf 100644 --- a/clang/test/C/drs/dr0xx.c +++ b/clang/test/C/drs/dr0xx.c @@ -214,7 +214,7 @@ _Static_assert(__builtin_types_compatible_p(struct S { int a; }, union U { int a */ void dr031(int i) { switch (i) { - case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */ + case __INT_MAX__ + 1: break; /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch" /* Silence the targets which issue: diff --git a/clang/test/C/drs/dr2xx.c b/clang/test/C/drs/dr2xx.c index 9c8d77518ab55e..1b68b65acca6af 100644 --- a/clang/test/C/drs/dr2xx.c +++ b/clang/test/C/drs/dr2xx.c @@ -277,7 +277,7 @@ void dr258(void) { void dr261(void) { /* This is still an integer constant expression despite the overflow. */ enum e1 { -ex1 = __INT_MAX__ + 1 /* expected-warning {{overflow in expression; result is -2147483648 with type 'int'}} */ +ex1 = __INT_MAX__ + 1 /* expected-warning {{overflow in expression; result is -2'147'483'648 with type 'int'}} */ }; /* This is not an integer constant
[clang] fa9e297 - [ClangPackager] Fix passing in multiple instances of `file`
Author: Joseph Huber Date: 2024-02-14T22:11:21-06:00 New Revision: fa9e297b8b63dacb962d99814e698658ad71f946 URL: https://github.com/llvm/llvm-project/commit/fa9e297b8b63dacb962d99814e698658ad71f946 DIFF: https://github.com/llvm/llvm-project/commit/fa9e297b8b63dacb962d99814e698658ad71f946.diff LOG: [ClangPackager] Fix passing in multiple instances of `file` Summary: This is necessary because CMake build tools might need to generate several files but are unable to put them in separate images. This patch sipmly moves the file handling out into a separate split iterator. Added: Modified: clang/tools/clang-offload-packager/ClangOffloadPackager.cpp Removed: diff --git a/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp b/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp index 08de3f3a3771c1..c36a5aa58cee50 100644 --- a/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp +++ b/clang/tools/clang-offload-packager/ClangOffloadPackager.cpp @@ -104,33 +104,36 @@ static Error bundleImages() { inconvertibleErrorCode(), "'file' and 'triple' are required image arguments"); -OffloadBinary::OffloadingImage ImageBinary{}; -std::unique_ptr DeviceImage; -for (const auto &[Key, Value] : Args) { - if (Key == "file") { -llvm::ErrorOr> ObjectOrErr = -llvm::MemoryBuffer::getFileOrSTDIN(Value); -if (std::error_code EC = ObjectOrErr.getError()) - return errorCodeToError(EC); - -// Clang uses the '.o' suffix for LTO bitcode. -if (identify_magic((*ObjectOrErr)->getBuffer()) == file_magic::bitcode) - ImageBinary.TheImageKind = object::IMG_Bitcode; -else - ImageBinary.TheImageKind = - getImageKind(sys::path::extension(Value).drop_front()); -ImageBinary.Image = std::move(*ObjectOrErr); - } else if (Key == "kind") { -ImageBinary.TheOffloadKind = getOffloadKind(Value); - } else { -ImageBinary.StringData[Key] = Value; +// Permit using multiple instances of `file` in a single string. +for (auto : llvm::split(Args["file"], ",")) { + OffloadBinary::OffloadingImage ImageBinary{}; + std::unique_ptr DeviceImage; + + llvm::ErrorOr> ObjectOrErr = + llvm::MemoryBuffer::getFileOrSTDIN(File); + if (std::error_code EC = ObjectOrErr.getError()) +return errorCodeToError(EC); + + // Clang uses the '.o' suffix for LTO bitcode. + if (identify_magic((*ObjectOrErr)->getBuffer()) == file_magic::bitcode) +ImageBinary.TheImageKind = object::IMG_Bitcode; + else +ImageBinary.TheImageKind = +getImageKind(sys::path::extension(File).drop_front()); + ImageBinary.Image = std::move(*ObjectOrErr); + for (const auto &[Key, Value] : Args) { +if (Key == "kind") { + ImageBinary.TheOffloadKind = getOffloadKind(Value); +} else if (Key != "file") { + ImageBinary.StringData[Key] = Value; +} } + llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary); + if (Buffer.size() % OffloadBinary::getAlignment() != 0) +return createStringError(inconvertibleErrorCode(), + "Offload binary has invalid size alignment"); + OS << Buffer; } -llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary); -if (Buffer.size() % OffloadBinary::getAlignment() != 0) - return createStringError(inconvertibleErrorCode(), - "Offload binary has invalid size alignment"); -OS << Buffer; } if (Error E = writeFile(OutputFile, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-format][NFC] Drop "Always" in "AlwaysBreakAfterReturnType". (PR #81591)
https://github.com/owenca closed https://github.com/llvm/llvm-project/pull/81591 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] d821650 - [clang-format][NFC] Drop "Always" in "AlwaysBreakAfterReturnType". (#81591)
Author: rmarker Date: 2024-02-14T20:10:56-08:00 New Revision: d821650e13145a1acccd337c9853354ad6531507 URL: https://github.com/llvm/llvm-project/commit/d821650e13145a1acccd337c9853354ad6531507 DIFF: https://github.com/llvm/llvm-project/commit/d821650e13145a1acccd337c9853354ad6531507.diff LOG: [clang-format][NFC] Drop "Always" in "AlwaysBreakAfterReturnType". (#81591) Complete the switch from "AlwaysBreakAfterReturnType" to "BreakAfterReturnType". Added: Modified: clang/include/clang/Format/Format.h clang/lib/Format/ContinuationIndenter.cpp clang/lib/Format/Format.cpp clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/ConfigParseTest.cpp clang/unittests/Format/DefinitionBlockSeparatorTest.cpp clang/unittests/Format/FormatTest.cpp clang/unittests/Format/FormatTestCSharp.cpp Removed: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 737cbfced9e9ce..e9b2160a7b9243 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1013,7 +1013,7 @@ struct FormatStyle { /// This option is renamed to ``BreakAfterReturnType``. /// \version 3.8 /// @deprecated - ReturnTypeBreakingStyle AlwaysBreakAfterReturnType; + // ReturnTypeBreakingStyle AlwaysBreakAfterReturnType; /// If ``true``, always break before multiline string literals. /// @@ -1579,7 +1579,7 @@ struct FormatStyle { /// The function declaration return type breaking style to use. /// \version 19 - // ReturnTypeBreakingStyle BreakAfterReturnType; + ReturnTypeBreakingStyle BreakAfterReturnType; /// If ``true``, clang-format will always break after a Json array ``[`` /// otherwise it will scan until the closing ``]`` to determine if it should @@ -4824,7 +4824,6 @@ struct FormatStyle { R.AllowShortIfStatementsOnASingleLine && AllowShortLambdasOnASingleLine == R.AllowShortLambdasOnASingleLine && AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine && - AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType && AlwaysBreakBeforeMultilineStrings == R.AlwaysBreakBeforeMultilineStrings && AttributeMacros == R.AttributeMacros && @@ -4835,6 +4834,7 @@ struct FormatStyle { BreakAdjacentStringLiterals == R.BreakAdjacentStringLiterals && BreakAfterAttributes == R.BreakAfterAttributes && BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations && + BreakAfterReturnType == R.BreakAfterReturnType && BreakArrays == R.BreakArrays && BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && BreakBeforeBraces == R.BreakBeforeBraces && diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 0b2ef97af44d83..159d130cb67332 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -329,12 +329,12 @@ bool ContinuationIndenter::canBreak(const LineState ) { // Don't break after very short return types (e.g. "void") as that is often // unexpected. if (Current.is(TT_FunctionDeclarationName)) { -if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None && +if (Style.BreakAfterReturnType == FormatStyle::RTBS_None && State.Column < 6) { return false; } -if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_ExceptShortType) { +if (Style.BreakAfterReturnType == FormatStyle::RTBS_ExceptShortType) { assert(State.Column >= State.FirstIndent); if (State.Column - State.FirstIndent < 6) return false; @@ -597,7 +597,7 @@ bool ContinuationIndenter::mustBreak(const LineState ) { !State.Line->ReturnTypeWrapped && // Don't break before a C# function when no break after return type. (!Style.isCSharp() || - Style.AlwaysBreakAfterReturnType > FormatStyle::RTBS_ExceptShortType) && + Style.BreakAfterReturnType > FormatStyle::RTBS_ExceptShortType) && // Don't always break between a JavaScript `function` and the function // name. !Style.isJavaScript() && Previous.isNot(tok::kw_template) && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 8efc42e0576cf9..56cd9495920c7b 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -877,8 +877,7 @@ template <> struct MappingTraits { if (!IO.outputting()) { IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines); IO.mapOptional("AllowAllConstructorInitializersOnNextLine", OnNextLine); - IO.mapOptional("AlwaysBreakAfterReturnType", - Style.AlwaysBreakAfterReturnType); + IO.mapOptional("AlwaysBreakAfterReturnType", Style.BreakAfterReturnType);
[clang] dcbb574 - [analyzer] Teach scan-build to filter reports by file.
Author: Brianna Fan Date: 2024-02-14T19:08:07-08:00 New Revision: dcbb574cfc3445251ff1c751f27b52ed6503bead URL: https://github.com/llvm/llvm-project/commit/dcbb574cfc3445251ff1c751f27b52ed6503bead DIFF: https://github.com/llvm/llvm-project/commit/dcbb574cfc3445251ff1c751f27b52ed6503bead.diff LOG: [analyzer] Teach scan-build to filter reports by file. That's a new GUI bell-and-whistle in the index.html page. Added: Modified: clang/test/Analysis/scan-build/html_output.test clang/tools/scan-build/bin/scan-build clang/tools/scan-build/share/scan-build/sorttable.js Removed: diff --git a/clang/test/Analysis/scan-build/html_output.test b/clang/test/Analysis/scan-build/html_output.test index eed2051d4df627..add35d83b95887 100644 --- a/clang/test/Analysis/scan-build/html_output.test +++ b/clang/test/Analysis/scan-build/html_output.test @@ -19,13 +19,17 @@ CHECK-FILENAMES: report-{{.*}}.html CHECK-FILENAMES: scanview.css CHECK-FILENAMES: sorttable.js - -// The index should have a link to the report for the single issue. +// Tests for the front page. RUN: cat %t.output_dir/*/index.html \ RUN: | FileCheck %s -check-prefix CHECK-INDEX-HTML +// Let's confirm that the new filtering facility is present. +CHECK-INDEX-HTML: Filter Results by File + +// The index should have a link to the report for the single issue. CHECK-INDEX-HTML: + // The report should describe the issue. RUN: cat %t.output_dir/*/report-*.html \ RUN: | FileCheck %s -check-prefix CHECK-REPORT-HTML diff --git a/clang/tools/scan-build/bin/scan-build b/clang/tools/scan-build/bin/scan-build index 04734d9cfa9af6..37241c6d85c5b2 100755 --- a/clang/tools/scan-build/bin/scan-build +++ b/clang/tools/scan-build/bin/scan-build @@ -722,9 +722,18 @@ ENDTEXT print OUT < + +Filter Results by File + + Reports - + Bug Group Bug Type diff --git a/clang/tools/scan-build/share/scan-build/sorttable.js b/clang/tools/scan-build/share/scan-build/sorttable.js index 32faa078d89934..e608daa9e39bc5 100644 --- a/clang/tools/scan-build/share/scan-build/sorttable.js +++ b/clang/tools/scan-build/share/scan-build/sorttable.js @@ -490,3 +490,23 @@ var forEach = function(object, block, context) { resolve.forEach(object, block, context); } }; + +// filter results by filename +const searchFiles = () => { + const columns = [ +{ name: 'Filename', index: 2, isFilter: true }, + ] + const filterColumns = columns.filter(c => c.isFilter).map(c => c.index) + const trs = document.querySelectorAll(`#reports_table tr:not(.header)`) + const filter = document.querySelector('#file_input').value + const regex = new RegExp(escape(filter), 'i') + const isFoundInTds = td => regex.test(td.innerHTML) + const isFound = childrenArr => childrenArr.some(isFoundInTds) + const setTrStyleDisplay = ({ style, children }) => { +style.display = isFound([ + ...filterColumns.map(c => children[c]) +]) ? '' : 'none' + } + + trs.forEach(setTrStyleDisplay) +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
https://github.com/jkorous-apple closed https://github.com/llvm/llvm-project/pull/81343 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6fce42f - [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (#81343)
Author: jkorous-apple Date: 2024-02-14T19:03:37-08:00 New Revision: 6fce42f89a2c3f12b019bd3d7fef3e8db2d4671f URL: https://github.com/llvm/llvm-project/commit/6fce42f89a2c3f12b019bd3d7fef3e8db2d4671f DIFF: https://github.com/llvm/llvm-project/commit/6fce42f89a2c3f12b019bd3d7fef3e8db2d4671f.diff LOG: [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (#81343) Introducing CArrayToPtrAssignment gadget and implementing fixits for some cases of array being assigned to pointer. Key observations: - const size array can be assigned to std::span and bounds are propagated - const size array can't be on LHS of assignment This means array to pointer assignment has no strategy implications. Fixits are implemented for cases where one of the variables in the assignment is safe. For assignment of a safe array to unsafe pointer we know that the RHS will never be transformed since it's safe and can immediately emit the optimal fixit. Similarly for assignment of unsafe array to safe pointer. (Obviously this is not and can't be future-proof in regards to what variables we consider unsafe and that is fine.) Fixits for assignment from unsafe array to unsafe pointer (from Array to Span strategy) are not implemented in this patch as that needs to be properly designed first - we might possibly implement optimal fixits for partially transformed cases, put both variables in a single fixit group or do something else. Added: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-array-assign-to-ptr.cpp Modified: clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def clang/lib/Analysis/UnsafeBufferUsage.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp Removed: diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def index 07f805ebb11013..3273c642eed517 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def @@ -45,7 +45,8 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '[any]' in an Unspecified Poin FIXABLE_GADGET(UPCStandalonePointer) FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified Pointer Context FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified Untyped Context -FIXABLE_GADGET(PointerAssignment) +FIXABLE_GADGET(PtrToPtrAssignment) +FIXABLE_GADGET(CArrayToPtrAssignment) FIXABLE_GADGET(PointerInit) #undef FIXABLE_GADGET diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index a74c113e29f1cf..769c6d9ebefaa5 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -7,11 +7,14 @@ //===--===// #include "clang/Analysis/Analyses/UnsafeBufferUsage.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" @@ -799,7 +802,8 @@ class PointerInitGadget : public FixableGadget { /// \code /// p = q; /// \endcode -class PointerAssignmentGadget : public FixableGadget { +/// where both `p` and `q` are pointers. +class PtrToPtrAssignmentGadget : public FixableGadget { private: static constexpr const char *const PointerAssignLHSTag = "ptrLHS"; static constexpr const char *const PointerAssignRHSTag = "ptrRHS"; @@ -807,13 +811,13 @@ class PointerAssignmentGadget : public FixableGadget { const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA` public: - PointerAssignmentGadget(const MatchFinder::MatchResult ) - : FixableGadget(Kind::PointerAssignment), -PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), -PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} + PtrToPtrAssignmentGadget(const MatchFinder::MatchResult ) + : FixableGadget(Kind::PtrToPtrAssignment), +PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), +PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} static bool classof(const Gadget *G) { -return G->getKind() == Kind::PointerAssignment; +return G->getKind() == Kind::PtrToPtrAssignment; } static Matcher matcher() { @@ -848,6 +852,60 @@ class PointerAssignmentGadget : public FixableGadget { } }; +/// An assignment expression of the form: +/// \code +/// ptr = array; +/// \endcode +/// where `p` is a pointer and `array` is a constant size array. +class CArrayToPtrAssignmentGadget : public FixableGadget { +private: + static constexpr const
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
https://github.com/haoNoQ approved this pull request. LGTM let's land! https://github.com/llvm/llvm-project/pull/81343 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
https://github.com/jkorous-apple updated https://github.com/llvm/llvm-project/pull/81343 >From 791130c5c5de31084c168db33531a5d856104506 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Thu, 8 Feb 2024 14:30:20 -0800 Subject: [PATCH 1/5] [-Wunsafe-buffer-usage][NFC] Factor out .data() fixit to a function --- clang/lib/Analysis/UnsafeBufferUsage.cpp | 24 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index a74c113e29f1cf..cc49876779ece2 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -1490,6 +1490,9 @@ PointerAssignmentGadget::getFixits(const FixitStrategy ) const { return std::nullopt; } +/// \returns fixit that adds .data() call after \DRE. +static inline std::optional createDataFixit(const ASTContext& Ctx, const DeclRefExpr * DRE); + std::optional PointerInitGadget::getFixits(const FixitStrategy ) const { const auto *LeftVD = PtrInitLHS; @@ -1907,6 +1910,18 @@ PointerDereferenceGadget::getFixits(const FixitStrategy ) const { return std::nullopt; } +static inline std::optional createDataFixit(const ASTContext& Ctx, const DeclRefExpr * DRE) { + const SourceManager = Ctx.getSourceManager(); + // Inserts the .data() after the DRE + std::optional EndOfOperand = + getPastLoc(DRE, SM, Ctx.getLangOpts()); + + if (EndOfOperand) +return FixItList{{FixItHint::CreateInsertion(*EndOfOperand, ".data()")}}; + + return std::nullopt; +} + // Generates fix-its replacing an expression of the form UPC(DRE) with // `DRE.data()` std::optional @@ -1915,14 +1930,7 @@ UPCStandalonePointerGadget::getFixits(const FixitStrategy ) const { switch (S.lookup(VD)) { case FixitStrategy::Kind::Array: case FixitStrategy::Kind::Span: { -ASTContext = VD->getASTContext(); -SourceManager = Ctx.getSourceManager(); -// Inserts the .data() after the DRE -std::optional EndOfOperand = -getPastLoc(Node, SM, Ctx.getLangOpts()); - -if (EndOfOperand) - return FixItList{{FixItHint::CreateInsertion(*EndOfOperand, ".data()")}}; +return createDataFixit(VD->getASTContext(), Node); // FIXME: Points inside a macro expansion. break; } >From 1b12f7413288b01d1806b98fb90c2d44e53b7437 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Thu, 8 Feb 2024 14:33:03 -0800 Subject: [PATCH 2/5] [-Wunsafe-buffer-usage][NFC] Rename PointerAssignment gadget to PtrToPtrAssignment --- .../Analysis/Analyses/UnsafeBufferUsageGadgets.def| 2 +- clang/lib/Analysis/UnsafeBufferUsage.cpp | 11 ++- clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def index 07f805ebb11013..2babc1df93d515 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def @@ -45,7 +45,7 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '[any]' in an Unspecified Poin FIXABLE_GADGET(UPCStandalonePointer) FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified Pointer Context FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified Untyped Context -FIXABLE_GADGET(PointerAssignment) +FIXABLE_GADGET(PtrToPtrAssignment) FIXABLE_GADGET(PointerInit) #undef FIXABLE_GADGET diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index cc49876779ece2..927baef2fffa39 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -799,7 +799,8 @@ class PointerInitGadget : public FixableGadget { /// \code /// p = q; /// \endcode -class PointerAssignmentGadget : public FixableGadget { +/// where both `p` and `q` are pointers. +class PtrToPtrAssignmentGadget : public FixableGadget { private: static constexpr const char *const PointerAssignLHSTag = "ptrLHS"; static constexpr const char *const PointerAssignRHSTag = "ptrRHS"; @@ -807,13 +808,13 @@ class PointerAssignmentGadget : public FixableGadget { const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA` public: - PointerAssignmentGadget(const MatchFinder::MatchResult ) - : FixableGadget(Kind::PointerAssignment), + PtrToPtrAssignmentGadget(const MatchFinder::MatchResult ) + : FixableGadget(Kind::PtrToPtrAssignment), PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} static bool classof(const Gadget *G) { -return G->getKind() == Kind::PointerAssignment; +return G->getKind() == Kind::PtrToPtrAssignment; } static Matcher matcher() { @@ -1471,7 +1472,7 @@ bool clang::internal::anyConflict(const SmallVectorImpl , }
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/haoNoQ closed https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] a7982d5 - [analyzer] UncountedCallArgsChecker: Detect & ignore trivial function calls. (#81808)
Author: Ryosuke Niwa Date: 2024-02-14T18:46:30-08:00 New Revision: a7982d5e7a16f681e80891a819bdf14dde928755 URL: https://github.com/llvm/llvm-project/commit/a7982d5e7a16f681e80891a819bdf14dde928755 DIFF: https://github.com/llvm/llvm-project/commit/a7982d5e7a16f681e80891a819bdf14dde928755.diff LOG: [analyzer] UncountedCallArgsChecker: Detect & ignore trivial function calls. (#81808) This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. Added: Modified: clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp clang/test/Analysis/Checkers/WebKit/call-args.cpp clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp Removed: diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..bf6f9a64877c64 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,216 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +if (auto *RV = RS->getRetValue()) + return Visit(RV); +return true; + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/haoNoQ approved this pull request. Looks great now! https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
https://github.com/haoNoQ commented: LGTM! I have a couple minor nitpicks. https://github.com/llvm/llvm-project/pull/81343 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
@@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN:-fsafe-buffer-usage-suggestions \ +// RUN:-fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +void safe_array_assigned_to_safe_ptr(unsigned idx) { + int buffer[10]; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + int* ptr; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + ptr = buffer; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: +} + +void safe_array_assigned_to_unsafe_ptr(unsigned idx) { + int buffer[10]; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + int* ptr; + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span ptr" + ptr = buffer; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + ptr[idx] = 0; +} + +void unsafe_array_assigned_to_safe_ptr(unsigned idx) { + int buffer[10]; + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::array buffer" + int* ptr; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + ptr = buffer; + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:15-[[@LINE-1]]:15}:".data()" + buffer[idx] = 0; +} + +void unsafe_array_assigned_to_unsafe_ptr(unsigned idx) { haoNoQ wrote: Similarly, let's mark this test as a FIXME test, and add a comment explaining why this is hard and the naive fix would be incorrect. https://github.com/llvm/llvm-project/pull/81343 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
@@ -1490,6 +1548,26 @@ PointerAssignmentGadget::getFixits(const FixitStrategy ) const { return std::nullopt; } +/// \returns fixit that adds .data() call after \DRE. +static inline std::optional createDataFixit(const ASTContext , + const DeclRefExpr *DRE); + +std::optional +CArrayToPtrAssignmentGadget::getFixits(const FixitStrategy ) const { haoNoQ wrote: I think there should be a comment explaining why the "both sides are fixed" case is tricky. Otherwise somebody may accidentally implement it https://github.com/llvm/llvm-project/pull/81343 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/81701 >From 9d0da0010f145b23ce2b7e5b6183558609600789 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 13 Feb 2024 18:22:23 -0800 Subject: [PATCH 1/4] [clang][InstallAPI] Add input file support to library This patch adds support for expected InstallAPI inputs. InstallAPI accepts a well defined filelist of headers and how those headers represent a single library. InstallAPI captures header files to determine linkable symbols to then compare against what was compiled in a binary dylib and generate TBD files. --- clang/include/clang/InstallAPI/FileList.h | 53 + clang/include/clang/InstallAPI/HeaderFile.h | 72 +++ clang/lib/ExtractAPI/CMakeLists.txt | 1 + clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 7 +- clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/FileList.cpp | 196 ++ clang/lib/InstallAPI/HeaderFile.cpp | 37 clang/unittests/CMakeLists.txt| 1 + clang/unittests/InstallAPI/CMakeLists.txt | 9 + clang/unittests/InstallAPI/FileListTest.cpp | 140 + clang/unittests/InstallAPI/HeaderFileTest.cpp | 89 11 files changed, 603 insertions(+), 4 deletions(-) create mode 100644 clang/include/clang/InstallAPI/FileList.h create mode 100644 clang/include/clang/InstallAPI/HeaderFile.h create mode 100644 clang/lib/InstallAPI/FileList.cpp create mode 100644 clang/lib/InstallAPI/HeaderFile.cpp create mode 100644 clang/unittests/InstallAPI/CMakeLists.txt create mode 100644 clang/unittests/InstallAPI/FileListTest.cpp create mode 100644 clang/unittests/InstallAPI/HeaderFileTest.cpp diff --git a/clang/include/clang/InstallAPI/FileList.h b/clang/include/clang/InstallAPI/FileList.h new file mode 100644 index 00..01ec9b35e31490 --- /dev/null +++ b/clang/include/clang/InstallAPI/FileList.h @@ -0,0 +1,53 @@ +//===- InstallAPI/FileList.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The JSON file list parser is used to communicate input to InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H +#define LLVM_CLANG_INSTALLAPI_FILELIST_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// JSON decoder for InstallAPI Inputs. +class FileListReader { + + class Implementation; + Implementation + + FileListReader(std::unique_ptr InputBuffer, + llvm::Error ); + +public: + /// Decode JSON input and append header input into destination container. + /// Headers are loaded in the order they appear in the JSON input. + /// + /// \param InputBuffer JSON input data. + /// \param Destination Container to load headers into. + static llvm::Error + loadHeaders(std::unique_ptr InputBuffer, + HeaderSeq ); + + ~FileListReader(); + + FileListReader(const FileListReader &) = delete; + FileListReader =(const FileListReader &) = delete; +}; + +} // namespace installapi +} // namespace clang + +#endif // LLVM_CLANG_INSTALLAPI_FILELIST_H diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h new file mode 100644 index 00..6ccd944f8b01be --- /dev/null +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -0,0 +1,72 @@ +//===- InstallAPI/HeaderFile.h --*- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// Representations of a library's headers for InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H +#define LLVM_CLANG_INSTALLAPI_HEADERFILE_H + +#include "clang/Basic/LangStandard.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Regex.h" +#include +#include + +namespace clang::installapi { +enum class HeaderType { + /// Represents declarations accessible to all clients. + Public, + /// Represents declarations accessible to a disclosed set of clients. + Private, + /// Represents declarations only accessible as implementation details to the + /// input library. + Project, +}; + +class HeaderFile { + /// Full
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
@@ -848,6 +852,60 @@ class PointerAssignmentGadget : public FixableGadget { } }; +/// An assignment expression of the form: +/// \code +/// ptr = array; +/// \endcode +/// where `p` is a pointer and `array` is a constant size array. +class CArrayToPtrAssignmentGadget : public FixableGadget { +private: + static constexpr const char *const PointerAssignLHSTag = "ptrLHS"; + static constexpr const char *const PointerAssignRHSTag = "ptrRHS"; + const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA` + const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA` + +public: + CArrayToPtrAssignmentGadget(const MatchFinder::MatchResult ) + : FixableGadget(Kind::CArrayToPtrAssignment), +PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), +PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} + + static bool classof(const Gadget *G) { +return G->getKind() == Kind::CArrayToPtrAssignment; + } + + static Matcher matcher() { +auto PtrAssignExpr = binaryOperator( +allOf(hasOperatorName("="), + hasRHS(ignoringParenImpCasts( + declRefExpr(hasType(hasCanonicalType(constantArrayType())), + toSupportedVariable()) + .bind(PointerAssignRHSTag))), + hasLHS(declRefExpr(hasPointerType(), toSupportedVariable()) + .bind(PointerAssignLHSTag; + +return stmt(isInUnspecifiedUntypedContext(PtrAssignExpr)); + } + + virtual std::optional + getFixits(const FixitStrategy ) const override; + + virtual const Stmt *getBaseStmt() const override { +// FIXME: This should be the binary operator, assuming that this method +// makes sense at all on a FixableGadget. +return PtrLHS; + } + + virtual DeclUseList getClaimedVarUseSites() const override { +return DeclUseList{PtrLHS, PtrRHS}; + } + + virtual std::optional> + getStrategyImplications() const override { +return {}; + } haoNoQ wrote: This is probably the default behavior 樂 https://github.com/llvm/llvm-project/pull/81343 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81808 >From 857decc27550e2b15938a7846a03561f9ad73f48 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 16:21:33 -0800 Subject: [PATCH 1/5] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- .../Checkers/WebKit/ASTUtils.cpp | 4 + .../Checkers/WebKit/PtrTypesSemantics.cpp | 207 .../Checkers/WebKit/PtrTypesSemantics.h | 21 ++ .../WebKit/UncountedCallArgsChecker.cpp | 8 +- .../Analysis/Checkers/WebKit/call-args.cpp| 33 +-- .../Checkers/WebKit/uncounted-obj-arg.cpp | 231 ++ 6 files changed, 487 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..17f59c2d304ddc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + }
[clang] [compiler-rt] [llvm] [InstrProf] Single byte counters in coverage (PR #75425)
https://github.com/gulfemsavrun updated https://github.com/llvm/llvm-project/pull/75425 >From ee88c6e666759c27587f900c99a4aba23c0d4cf4 Mon Sep 17 00:00:00 2001 From: Gulfem Savrun Yeniceri Date: Thu, 14 Dec 2023 03:40:57 + Subject: [PATCH] [InstrProf] Single byte counters in coverage This patch inserts 1-byte counters instead of an 8-byte counters into llvm profiles for source-based code coverage. The origial idea was proposed as block-cov for PGO, and this patch repurposes that idea for coverage. The current 8-byte counters mechanism add counters to minimal regions, and infer the counters in the remaining regions via adding or subtracting counters. For example, it infers the counter in the if.else region by subtracting the counters between if.entry and if.then regions in an if statement. Whenever there is a control-flow merge, it adds the counters from all the incoming regions. However, we are not going to be able to infer counters by subtracting two execution counts when using single-byte counters. Therefore, this patch conservatively inserts additional counters for the cases where we need to add or subtract counters. RFC: https://discourse.llvm.org/t/rfc-single-byte-counters-for-source-based-code-coverage/75685 --- clang/lib/CodeGen/CGExprAgg.cpp | 13 +- clang/lib/CodeGen/CGExprComplex.cpp | 14 +- clang/lib/CodeGen/CGExprScalar.cpp| 32 ++- clang/lib/CodeGen/CGStmt.cpp | 73 ++- clang/lib/CodeGen/CodeGenFunction.cpp | 9 +- clang/lib/CodeGen/CodeGenFunction.h | 2 +- clang/lib/CodeGen/CodeGenModule.cpp | 1 + clang/lib/CodeGen/CodeGenPGO.cpp | 150 - clang/lib/CodeGen/CodeGenPGO.h| 6 +- clang/lib/CodeGen/CoverageMappingGen.cpp | 206 +- .../CoverageMapping/single-byte-counters.cpp | 169 ++ compiler-rt/lib/profile/InstrProfiling.h | 3 +- .../ProfileData/Coverage/CoverageMapping.h| 20 +- .../llvm/ProfileData/InstrProfWriter.h| 4 + .../ProfileData/Coverage/CoverageMapping.cpp | 13 +- 15 files changed, 623 insertions(+), 92 deletions(-) create mode 100644 clang/test/CoverageMapping/single-byte-counters.cpp diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 22f55fe9aac904..377bf413c857cb 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -33,6 +33,10 @@ using namespace CodeGen; //Aggregate Expression Emitter //===--===// +namespace llvm { +extern cl::opt EnableSingleByteCoverage; +} // namespace llvm + namespace { class AggExprEmitter : public StmtVisitor { CodeGenFunction @@ -1278,7 +1282,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(LHSBlock); - CGF.incrementProfileCounter(E); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E->getTrueExpr()); + else +CGF.incrementProfileCounter(E); Visit(E->getTrueExpr()); eval.end(CGF); @@ -1293,6 +1300,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(RHSBlock); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E->getFalseExpr()); Visit(E->getFalseExpr()); eval.end(CGF); @@ -1301,6 +1310,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { E->getType()); CGF.EmitBlock(ContBlock); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E); } void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) { diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 9ddf0e763f139b..683097eea5e76a 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -28,6 +28,10 @@ using namespace CodeGen; //Complex Expression Emitter //===--===// +namespace llvm { +extern cl::opt EnableSingleByteCoverage; +} // namespace llvm + typedef CodeGenFunction::ComplexPairTy ComplexPairTy; /// Return the complex type that we are meant to emit. @@ -1329,7 +1333,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(LHSBlock); - CGF.incrementProfileCounter(E); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E->getTrueExpr()); + else +CGF.incrementProfileCounter(E); + ComplexPairTy LHS = Visit(E->getTrueExpr()); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); @@ -1337,9 +1345,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(RHSBlock); + if (llvm::EnableSingleByteCoverage) +
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
@@ -406,6 +406,39 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { } return false; } + +AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { + // FIXME: Proper solution: + // - refactor Sema::CheckArrayAccess + //- split safe/OOB/unknown decision logic from diagnostics emitting code + //- e. g. "Try harder to find a NamedDecl to point at in the note." + //already duplicated + // - call both from Sema and from here + + const DeclRefExpr *BaseDRE = + dyn_cast_or_null(Node.getBase()->IgnoreParenImpCasts()); haoNoQ wrote: I don't think `IgnoreParenImpCasts()` can ever return null. ```suggestion const auto *BaseDRE = dyn_cast(Node.getBase()->IgnoreParenImpCasts()); ``` https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81808 >From 857decc27550e2b15938a7846a03561f9ad73f48 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 16:21:33 -0800 Subject: [PATCH 1/4] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- .../Checkers/WebKit/ASTUtils.cpp | 4 + .../Checkers/WebKit/PtrTypesSemantics.cpp | 207 .../Checkers/WebKit/PtrTypesSemantics.h | 21 ++ .../WebKit/UncountedCallArgsChecker.cpp | 8 +- .../Analysis/Checkers/WebKit/call-args.cpp| 33 +-- .../Checkers/WebKit/uncounted-obj-arg.cpp | 231 ++ 6 files changed, 487 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..17f59c2d304ddc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + }
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
llvmbot wrote: @llvm/pr-subscribers-clang Author: None (jkorous-apple) Changes depends on https://github.com/llvm/llvm-project/pull/80347 --- Full diff: https://github.com/llvm/llvm-project/pull/81343.diff 4 Files Affected: - (modified) clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def (+2-1) - (modified) clang/lib/Analysis/UnsafeBufferUsage.cpp (+99-15) - (modified) clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp (+1-1) - (added) clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-array-assign-to-ptr.cpp (+43) ``diff diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def index 07f805ebb11013..3273c642eed517 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def @@ -45,7 +45,8 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '[any]' in an Unspecified Poin FIXABLE_GADGET(UPCStandalonePointer) FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified Pointer Context FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified Untyped Context -FIXABLE_GADGET(PointerAssignment) +FIXABLE_GADGET(PtrToPtrAssignment) +FIXABLE_GADGET(CArrayToPtrAssignment) FIXABLE_GADGET(PointerInit) #undef FIXABLE_GADGET diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index a74c113e29f1cf..8e810876950c81 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -7,11 +7,14 @@ //===--===// #include "clang/Analysis/Analyses/UnsafeBufferUsage.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Lexer.h" @@ -799,7 +802,8 @@ class PointerInitGadget : public FixableGadget { /// \code /// p = q; /// \endcode -class PointerAssignmentGadget : public FixableGadget { +/// where both `p` and `q` are pointers. +class PtrToPtrAssignmentGadget : public FixableGadget { private: static constexpr const char *const PointerAssignLHSTag = "ptrLHS"; static constexpr const char *const PointerAssignRHSTag = "ptrRHS"; @@ -807,13 +811,13 @@ class PointerAssignmentGadget : public FixableGadget { const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA` public: - PointerAssignmentGadget(const MatchFinder::MatchResult ) - : FixableGadget(Kind::PointerAssignment), -PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), -PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} + PtrToPtrAssignmentGadget(const MatchFinder::MatchResult ) + : FixableGadget(Kind::PtrToPtrAssignment), +PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), +PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} static bool classof(const Gadget *G) { -return G->getKind() == Kind::PointerAssignment; +return G->getKind() == Kind::PtrToPtrAssignment; } static Matcher matcher() { @@ -848,6 +852,60 @@ class PointerAssignmentGadget : public FixableGadget { } }; +/// An assignment expression of the form: +/// \code +/// ptr = array; +/// \endcode +/// where `p` is a pointer and `array` is a constant size array. +class CArrayToPtrAssignmentGadget : public FixableGadget { +private: + static constexpr const char *const PointerAssignLHSTag = "ptrLHS"; + static constexpr const char *const PointerAssignRHSTag = "ptrRHS"; + const DeclRefExpr *PtrLHS; // the LHS pointer expression in `PA` + const DeclRefExpr *PtrRHS; // the RHS pointer expression in `PA` + +public: + CArrayToPtrAssignmentGadget(const MatchFinder::MatchResult ) + : FixableGadget(Kind::CArrayToPtrAssignment), +PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), +PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} + + static bool classof(const Gadget *G) { +return G->getKind() == Kind::CArrayToPtrAssignment; + } + + static Matcher matcher() { +auto PtrAssignExpr = binaryOperator( +allOf(hasOperatorName("="), + hasRHS(ignoringParenImpCasts( + declRefExpr(hasType(hasCanonicalType(constantArrayType())), + toSupportedVariable()) + .bind(PointerAssignRHSTag))), + hasLHS(declRefExpr(hasPointerType(), toSupportedVariable()) + .bind(PointerAssignLHSTag; + +return stmt(isInUnspecifiedUntypedContext(PtrAssignExpr)); + } + + virtual std::optional + getFixits(const FixitStrategy ) const override; + +
[clang] [-Wunsafe-buffer-usage] Add fixits for array to pointer assignment (PR #81343)
https://github.com/jkorous-apple updated https://github.com/llvm/llvm-project/pull/81343 >From 791130c5c5de31084c168db33531a5d856104506 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Thu, 8 Feb 2024 14:30:20 -0800 Subject: [PATCH 1/4] [-Wunsafe-buffer-usage][NFC] Factor out .data() fixit to a function --- clang/lib/Analysis/UnsafeBufferUsage.cpp | 24 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index a74c113e29f1cf..cc49876779ece2 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -1490,6 +1490,9 @@ PointerAssignmentGadget::getFixits(const FixitStrategy ) const { return std::nullopt; } +/// \returns fixit that adds .data() call after \DRE. +static inline std::optional createDataFixit(const ASTContext& Ctx, const DeclRefExpr * DRE); + std::optional PointerInitGadget::getFixits(const FixitStrategy ) const { const auto *LeftVD = PtrInitLHS; @@ -1907,6 +1910,18 @@ PointerDereferenceGadget::getFixits(const FixitStrategy ) const { return std::nullopt; } +static inline std::optional createDataFixit(const ASTContext& Ctx, const DeclRefExpr * DRE) { + const SourceManager = Ctx.getSourceManager(); + // Inserts the .data() after the DRE + std::optional EndOfOperand = + getPastLoc(DRE, SM, Ctx.getLangOpts()); + + if (EndOfOperand) +return FixItList{{FixItHint::CreateInsertion(*EndOfOperand, ".data()")}}; + + return std::nullopt; +} + // Generates fix-its replacing an expression of the form UPC(DRE) with // `DRE.data()` std::optional @@ -1915,14 +1930,7 @@ UPCStandalonePointerGadget::getFixits(const FixitStrategy ) const { switch (S.lookup(VD)) { case FixitStrategy::Kind::Array: case FixitStrategy::Kind::Span: { -ASTContext = VD->getASTContext(); -SourceManager = Ctx.getSourceManager(); -// Inserts the .data() after the DRE -std::optional EndOfOperand = -getPastLoc(Node, SM, Ctx.getLangOpts()); - -if (EndOfOperand) - return FixItList{{FixItHint::CreateInsertion(*EndOfOperand, ".data()")}}; +return createDataFixit(VD->getASTContext(), Node); // FIXME: Points inside a macro expansion. break; } >From 1b12f7413288b01d1806b98fb90c2d44e53b7437 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Thu, 8 Feb 2024 14:33:03 -0800 Subject: [PATCH 2/4] [-Wunsafe-buffer-usage][NFC] Rename PointerAssignment gadget to PtrToPtrAssignment --- .../Analysis/Analyses/UnsafeBufferUsageGadgets.def| 2 +- clang/lib/Analysis/UnsafeBufferUsage.cpp | 11 ++- clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def index 07f805ebb11013..2babc1df93d515 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def @@ -45,7 +45,7 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '[any]' in an Unspecified Poin FIXABLE_GADGET(UPCStandalonePointer) FIXABLE_GADGET(UPCPreIncrement)// '++Ptr' in an Unspecified Pointer Context FIXABLE_GADGET(UUCAddAssign)// 'Ptr += n' in an Unspecified Untyped Context -FIXABLE_GADGET(PointerAssignment) +FIXABLE_GADGET(PtrToPtrAssignment) FIXABLE_GADGET(PointerInit) #undef FIXABLE_GADGET diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index cc49876779ece2..927baef2fffa39 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -799,7 +799,8 @@ class PointerInitGadget : public FixableGadget { /// \code /// p = q; /// \endcode -class PointerAssignmentGadget : public FixableGadget { +/// where both `p` and `q` are pointers. +class PtrToPtrAssignmentGadget : public FixableGadget { private: static constexpr const char *const PointerAssignLHSTag = "ptrLHS"; static constexpr const char *const PointerAssignRHSTag = "ptrRHS"; @@ -807,13 +808,13 @@ class PointerAssignmentGadget : public FixableGadget { const DeclRefExpr * PtrRHS; // the RHS pointer expression in `PA` public: - PointerAssignmentGadget(const MatchFinder::MatchResult ) - : FixableGadget(Kind::PointerAssignment), + PtrToPtrAssignmentGadget(const MatchFinder::MatchResult ) + : FixableGadget(Kind::PtrToPtrAssignment), PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), PtrRHS(Result.Nodes.getNodeAs(PointerAssignRHSTag)) {} static bool classof(const Gadget *G) { -return G->getKind() == Kind::PointerAssignment; +return G->getKind() == Kind::PtrToPtrAssignment; } static Matcher matcher() { @@ -1471,7 +1472,7 @@ bool clang::internal::anyConflict(const SmallVectorImpl , }
[clang-tools-extra] 8ce1448 - [clangd][test] Fix -Wmissing-field-initializers in DiagnosticsTests.cpp (NFC)
Author: Jie Fu Date: 2024-02-15T10:17:58+08:00 New Revision: 8ce144800a7ed7c1e42343b3a9ac5e0ffdbfddbf URL: https://github.com/llvm/llvm-project/commit/8ce144800a7ed7c1e42343b3a9ac5e0ffdbfddbf DIFF: https://github.com/llvm/llvm-project/commit/8ce144800a7ed7c1e42343b3a9ac5e0ffdbfddbf.diff LOG: [clangd][test] Fix -Wmissing-field-initializers in DiagnosticsTests.cpp (NFC) llvm-project/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp:921:45: error: missing field 'Annotations' initializer [-Werror,-Wmissing-field-initializers] TextEdit{Main.range("virtual1"), ""}}}; ^ llvm-project/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp:926:45: error: missing field 'Annotations' initializer [-Werror,-Wmissing-field-initializers] TextEdit{Main.range("virtual2"), ""}}}; ^ 2 errors generated. Added: Modified: clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp Removed: diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index 4839879e1b78c8..2f6dd0611b6621 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -918,12 +918,14 @@ TEST(DiagnosticTest, ClangTidySelfContainedDiagsFormatting) { "prefer using 'override' or (rarely) 'final' " "instead of 'virtual'", {TextEdit{Main.range("override1"), " override"}, - TextEdit{Main.range("virtual1"), ""}}}; + TextEdit{Main.range("virtual1"), ""}}, + {}}; clangd::Fix const ExpectedFix2{ "prefer using 'override' or (rarely) 'final' " "instead of 'virtual'", {TextEdit{Main.range("override2"), " override"}, - TextEdit{Main.range("virtual2"), ""}}}; + TextEdit{Main.range("virtual2"), ""}}, + {}}; // Note that in the Fix we expect the "virtual" keyword and the following // whitespace to be deleted EXPECT_THAT(TU.build().getDiagnostics(), ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
https://github.com/jkorous-apple closed https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 9a1e637 - [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (#80504)
Author: jkorous-apple Date: 2024-02-14T18:16:44-08:00 New Revision: 9a1e6373ab3edc38486af504154db2d804e72d3d URL: https://github.com/llvm/llvm-project/commit/9a1e6373ab3edc38486af504154db2d804e72d3d DIFF: https://github.com/llvm/llvm-project/commit/9a1e6373ab3edc38486af504154db2d804e72d3d.diff LOG: [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (#80504) [-Wunsafe-buffer-usage] Ignore safe array subscripts Don't emit warnings for array subscripts on constant size arrays where the index is constant and within bounds. Example: int arr[10]; arr[5] = 0; //safe, no warning This patch recognizes only array indices that are integer literals - it doesn't understand more complex expressions (arithmetic on constants, etc.). -Warray-bounds implemented in Sema::CheckArrayAccess() already solves a similar (opposite) problem, handles complex expressions and is battle-tested. Adding -Wunsafe-buffer-usage diagnostics to Sema is a non-starter as we need to emit both the warnings and fixits and the performance impact of the fixit machine is unacceptable for Sema. CheckArrayAccess() as is doesn't distinguish between "safe" and "unknown" array accesses. It also mixes the analysis that decides if an index is out of bounds with crafting the diagnostics. A refactor of CheckArrayAccess() might serve both the original purpose and help us avoid false-positive with -Wunsafe-buffer-usage on constant size arrrays. Added: Modified: clang/lib/Analysis/UnsafeBufferUsage.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-arg-to-func-ptr-call.cpp clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp Removed: diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index ca346444e047e5..a74c113e29f1cf 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -406,6 +406,39 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { } return false; } + +AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { + // FIXME: Proper solution: + // - refactor Sema::CheckArrayAccess + //- split safe/OOB/unknown decision logic from diagnostics emitting code + //- e. g. "Try harder to find a NamedDecl to point at in the note." + //already duplicated + // - call both from Sema and from here + + const auto *BaseDRE = + dyn_cast(Node.getBase()->IgnoreParenImpCasts()); + if (!BaseDRE) +return false; + if (!BaseDRE->getDecl()) +return false; + const auto *CATy = Finder->getASTContext().getAsConstantArrayType( + BaseDRE->getDecl()->getType()); + if (!CATy) +return false; + const APInt ArrSize = CATy->getSize(); + + if (const auto *IdxLit = dyn_cast(Node.getIdx())) { +const APInt ArrIdx = IdxLit->getValue(); +// FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a +// bug +if (ArrIdx.isNonNegative() && +ArrIdx.getLimitedValue() < ArrSize.getLimitedValue()) + return true; + } + + return false; +} + } // namespace clang::ast_matchers namespace { @@ -598,16 +631,16 @@ class ArraySubscriptGadget : public WarningGadget { } static Matcher matcher() { -// FIXME: What if the index is integer literal 0? Should this be -// a safe gadget in this case? - // clang-format off +// clang-format off return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType(, -unless(hasIndex( -anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) - ))) -.bind(ArraySubscrTag)); +unless(anyOf( + isSafeArraySubscript(), + hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) + ) +))).bind(ArraySubscrTag)); // clang-format on } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp index 90c11b1be95c25..8b2f103ec66708 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: %clang_cc1 -std=c++20 -Wno-everything -Wunsafe-buffer-usage \ // RUN:-fsafe-buffer-usage-suggestions \ // RUN:-verify %s @@ -22,3 +22,19 @@ struct Foo { void foo2(Foo& f, unsigned idx) { f.member_buffer[idx] = 0; // expected-warning{{unsafe buffer access}} } + +void constant_idx_safe(unsigned idx) { + int buffer[10]; + buffer[9] = 0; +} + +void constant_idx_safe0(unsigned idx) { + int buffer[10]; + buffer[0] = 0; +} +
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
https://github.com/jkorous-apple updated https://github.com/llvm/llvm-project/pull/80504 >From e075dc3ac10c0cd2e12b223988ec4821b40b55d2 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Fri, 2 Feb 2024 14:46:59 -0800 Subject: [PATCH 1/7] [-Wunsafe-buffer-usage] Ignore safe array subscripts Don't emit warnings for array subscripts on constant size arrays where the index is constant and within bounds. Example: int arr[10]; arr[5] = 0; //safe, no warning This patch recognizes only array indices that are integer literals - it doesn't understand more complex expressions (arithmetic on constants, etc.). --- clang/lib/Analysis/UnsafeBufferUsage.cpp | 39 +++ .../warn-unsafe-buffer-usage-array.cpp| 18 - 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index ca346444e047e5..d150a679597a92 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -406,6 +406,31 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { } return false; } + +AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { + const DeclRefExpr * BaseDRE = dyn_cast_or_null(Node.getBase()->IgnoreParenImpCasts()); + if (!BaseDRE) +return false; + if (!BaseDRE->getDecl()) +return false; + auto BaseVarDeclTy = BaseDRE->getDecl()->getType(); + if (!BaseVarDeclTy->isConstantArrayType()) +return false; + const auto * CATy = dyn_cast_or_null(BaseVarDeclTy); + if (!CATy) +return false; + const APInt ArrSize = CATy->getSize(); + + if (const auto * IdxLit = dyn_cast(Node.getIdx())) { +const APInt ArrIdx = IdxLit->getValue(); +// FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a bug +if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < ArrSize.getLimitedValue()) + return true; + } + + return false; +} + } // namespace clang::ast_matchers namespace { @@ -598,16 +623,16 @@ class ArraySubscriptGadget : public WarningGadget { } static Matcher matcher() { -// FIXME: What if the index is integer literal 0? Should this be -// a safe gadget in this case? - // clang-format off +// clang-format off return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType(, -unless(hasIndex( -anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) - ))) -.bind(ArraySubscrTag)); +unless(anyOf( + isSafeArraySubscript(), + hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) + ) +))).bind(ArraySubscrTag)); // clang-format on } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp index 90c11b1be95c25..4804223e8be058 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: %clang_cc1 -std=c++20 -Wno-everything -Wunsafe-buffer-usage \ // RUN:-fsafe-buffer-usage-suggestions \ // RUN:-verify %s @@ -22,3 +22,19 @@ struct Foo { void foo2(Foo& f, unsigned idx) { f.member_buffer[idx] = 0; // expected-warning{{unsafe buffer access}} } + +void constant_idx_safe(unsigned idx) { + int buffer[10]; + buffer[9] = 0; +} + +void constant_idx_safe0(unsigned idx) { + int buffer[10]; + buffer[0] = 0; +} + +void constant_idx_unsafe(unsigned idx) { + int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}} +// expected-note@-1{{change type of 'buffer' to 'std::array' to harden it}} + buffer[10] = 0; // expected-note{{used in buffer access here}} +} >From 9f3940e5e1a8555a784521999d296ed46b1ae0c2 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Fri, 2 Feb 2024 14:48:41 -0800 Subject: [PATCH 2/7] [-Wunsafe-buffer-usage][NFC] Update existing tests after constant safe index is ignored --- ...afe-buffer-usage-fixits-pointer-access.cpp | 8 +-- ...ge-fixits-pointer-arg-to-func-ptr-call.cpp | 3 +- .../test/SemaCXX/warn-unsafe-buffer-usage.cpp | 53 ++- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp index f94072015ff87d..b3c64f1b0d085e 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp @@ -83,11 +83,11 @@ void unsafe_method_invocation_single_param() { } -void unsafe_method_invocation_single_param_array() { +void
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
https://github.com/haoNoQ approved this pull request. LGTM! https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
@@ -598,16 +623,16 @@ class ArraySubscriptGadget : public WarningGadget { } static Matcher matcher() { -// FIXME: What if the index is integer literal 0? Should this be -// a safe gadget in this case? - // clang-format off +// clang-format off return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType(, -unless(hasIndex( -anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) - ))) -.bind(ArraySubscrTag)); +unless(anyOf( + isSafeArraySubscript(), + hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) haoNoQ wrote: So you want to suppress the warning here right? In this case yeah makes sense. It's also somewhat covered by ``` warning: zero size arrays are an extension [-Wzero-length-array] ``` https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81808 >From 857decc27550e2b15938a7846a03561f9ad73f48 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 16:21:33 -0800 Subject: [PATCH 1/3] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- .../Checkers/WebKit/ASTUtils.cpp | 4 + .../Checkers/WebKit/PtrTypesSemantics.cpp | 207 .../Checkers/WebKit/PtrTypesSemantics.h | 21 ++ .../WebKit/UncountedCallArgsChecker.cpp | 8 +- .../Analysis/Checkers/WebKit/call-args.cpp| 33 +-- .../Checkers/WebKit/uncounted-obj-arg.cpp | 231 ++ 6 files changed, 487 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..17f59c2d304ddc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + }
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
kees wrote: > Sure -fwrapv makes wraparound defined, but it doesn't prevent us from making > -fsanitize=signed-integer-overflow useful. "-fwrapv => no > signed-integer-overflow" is not a solid argument. > > I think we can try making -fsanitize=signed-integer-overflow effective even > when -fwrapv if specified. -fsanitize=signed-integer-overflow is rare in the > wild, probably rarer when combined with -fwrapv. . In earlier GCC discussions, it seemed very much like the `-fsanitize=signed-integer-overflow` was meant for UB only, but maybe I misunderstood. See replies leading up to this: https://gcc.gnu.org/pipermail/gcc-patches/2023-September/630578.html https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
@@ -598,16 +623,16 @@ class ArraySubscriptGadget : public WarningGadget { } static Matcher matcher() { -// FIXME: What if the index is integer literal 0? Should this be -// a safe gadget in this case? - // clang-format off +// clang-format off return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType(, -unless(hasIndex( -anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) - ))) -.bind(ArraySubscrTag)); +unless(anyOf( + isSafeArraySubscript(), + hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) jkorous-apple wrote: Actually, it is still necessary - we need to somehow cover: ``` int arr[0]; arr[0] = 5; ``` And that has been defined as out of scope for the warning. I don't feel like calling it "safe" and I'd rather have it visible in the top-level matcher. https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
@@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + } + + bool VisitConditionalOperator(const ConditionalOperator *CO) { +// Ternary operators are trivial if their conditions & values are trivial. +return VisitChildren(CO); + } + + bool VisitDeclRefExpr(const DeclRefExpr *DRE) { +if (auto *decl = DRE->getDecl()) { + if (isa(decl)) +return true; +} +return false; + } + + bool VisitStaticAssertDecl(const StaticAssertDecl *SAD) { +// Any static_assert is considered trivial. +return true; + } + + bool VisitCallExpr(const CallExpr *CE) { +if (auto *MCE = dyn_cast(CE)) + return VisitCXXMemberCallExpr(MCE); rniwa wrote: Good point. Refactored. https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
@@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); rniwa wrote: Fixed! This as indeed the cause of the crash. https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
https://github.com/jkorous-apple updated https://github.com/llvm/llvm-project/pull/80504 >From e075dc3ac10c0cd2e12b223988ec4821b40b55d2 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Fri, 2 Feb 2024 14:46:59 -0800 Subject: [PATCH 1/6] [-Wunsafe-buffer-usage] Ignore safe array subscripts Don't emit warnings for array subscripts on constant size arrays where the index is constant and within bounds. Example: int arr[10]; arr[5] = 0; //safe, no warning This patch recognizes only array indices that are integer literals - it doesn't understand more complex expressions (arithmetic on constants, etc.). --- clang/lib/Analysis/UnsafeBufferUsage.cpp | 39 +++ .../warn-unsafe-buffer-usage-array.cpp| 18 - 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index ca346444e047e5..d150a679597a92 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -406,6 +406,31 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { } return false; } + +AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { + const DeclRefExpr * BaseDRE = dyn_cast_or_null(Node.getBase()->IgnoreParenImpCasts()); + if (!BaseDRE) +return false; + if (!BaseDRE->getDecl()) +return false; + auto BaseVarDeclTy = BaseDRE->getDecl()->getType(); + if (!BaseVarDeclTy->isConstantArrayType()) +return false; + const auto * CATy = dyn_cast_or_null(BaseVarDeclTy); + if (!CATy) +return false; + const APInt ArrSize = CATy->getSize(); + + if (const auto * IdxLit = dyn_cast(Node.getIdx())) { +const APInt ArrIdx = IdxLit->getValue(); +// FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a bug +if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < ArrSize.getLimitedValue()) + return true; + } + + return false; +} + } // namespace clang::ast_matchers namespace { @@ -598,16 +623,16 @@ class ArraySubscriptGadget : public WarningGadget { } static Matcher matcher() { -// FIXME: What if the index is integer literal 0? Should this be -// a safe gadget in this case? - // clang-format off +// clang-format off return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType(, -unless(hasIndex( -anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) - ))) -.bind(ArraySubscrTag)); +unless(anyOf( + isSafeArraySubscript(), + hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) + ) +))).bind(ArraySubscrTag)); // clang-format on } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp index 90c11b1be95c25..4804223e8be058 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: %clang_cc1 -std=c++20 -Wno-everything -Wunsafe-buffer-usage \ // RUN:-fsafe-buffer-usage-suggestions \ // RUN:-verify %s @@ -22,3 +22,19 @@ struct Foo { void foo2(Foo& f, unsigned idx) { f.member_buffer[idx] = 0; // expected-warning{{unsafe buffer access}} } + +void constant_idx_safe(unsigned idx) { + int buffer[10]; + buffer[9] = 0; +} + +void constant_idx_safe0(unsigned idx) { + int buffer[10]; + buffer[0] = 0; +} + +void constant_idx_unsafe(unsigned idx) { + int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}} +// expected-note@-1{{change type of 'buffer' to 'std::array' to harden it}} + buffer[10] = 0; // expected-note{{used in buffer access here}} +} >From 9f3940e5e1a8555a784521999d296ed46b1ae0c2 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Fri, 2 Feb 2024 14:48:41 -0800 Subject: [PATCH 2/6] [-Wunsafe-buffer-usage][NFC] Update existing tests after constant safe index is ignored --- ...afe-buffer-usage-fixits-pointer-access.cpp | 8 +-- ...ge-fixits-pointer-arg-to-func-ptr-call.cpp | 3 +- .../test/SemaCXX/warn-unsafe-buffer-usage.cpp | 53 ++- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp index f94072015ff87d..b3c64f1b0d085e 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp @@ -83,11 +83,11 @@ void unsafe_method_invocation_single_param() { } -void unsafe_method_invocation_single_param_array() { +void
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81808 >From 857decc27550e2b15938a7846a03561f9ad73f48 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 16:21:33 -0800 Subject: [PATCH 1/2] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- .../Checkers/WebKit/ASTUtils.cpp | 4 + .../Checkers/WebKit/PtrTypesSemantics.cpp | 207 .../Checkers/WebKit/PtrTypesSemantics.h | 21 ++ .../WebKit/UncountedCallArgsChecker.cpp | 8 +- .../Analysis/Checkers/WebKit/call-args.cpp| 33 +-- .../Checkers/WebKit/uncounted-obj-arg.cpp | 231 ++ 6 files changed, 487 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..17f59c2d304ddc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + }
[clang] [compiler-rt] [llvm] [InstrProf] Single byte counters in coverage (PR #75425)
@@ -821,15 +822,23 @@ void InstrProfRecord::merge(InstrProfRecord , uint64_t Weight, for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) { bool Overflowed; -uint64_t Value = -SaturatingMultiplyAdd(Other.Counts[I], Weight, Counts[I], ); -if (Value > getInstrMaxCountValue()) { - Value = getInstrMaxCountValue(); - Overflowed = true; +uint64_t Value; +// When a profile has single byte coverage, use || to merge counters. +if (HasSingleByteCoverage) + Value = Other.Counts[I] || Counts[I]; gulfemsavrun wrote: Ok, there is a valid use case then. So, I removed this code. https://github.com/llvm/llvm-project/pull/75425 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [llvm] [InstrProf] Single byte counters in coverage (PR #75425)
https://github.com/gulfemsavrun updated https://github.com/llvm/llvm-project/pull/75425 >From 5553825da82306a3bb0b959f4cbfadc624b1d14f Mon Sep 17 00:00:00 2001 From: Gulfem Savrun Yeniceri Date: Thu, 14 Dec 2023 03:40:57 + Subject: [PATCH] [InstrProf] Single byte counters in coverage This patch inserts 1-byte counters instead of an 8-byte counters into llvm profiles for source-based code coverage. The origial idea was proposed as block-cov for PGO, and this patch repurposes that idea for coverage. The current 8-byte counters mechanism add counters to minimal regions, and infer the counters in the remaining regions via adding or subtracting counters. For example, it infers the counter in the if.else region by subtracting the counters between if.entry and if.then regions in an if statement. Whenever there is a control-flow merge, it adds the counters from all the incoming regions. However, we are not going to be able to infer counters by subtracting two execution counts when using single-byte counters. Therefore, this patch conservatively inserts additional counters for the cases where we need to add or subtract counters. RFC: https://discourse.llvm.org/t/rfc-single-byte-counters-for-source-based-code-coverage/75685 --- clang/lib/CodeGen/CGExprAgg.cpp | 13 +- clang/lib/CodeGen/CGExprComplex.cpp | 14 +- clang/lib/CodeGen/CGExprScalar.cpp| 32 ++- clang/lib/CodeGen/CGStmt.cpp | 73 ++- clang/lib/CodeGen/CodeGenFunction.cpp | 9 +- clang/lib/CodeGen/CodeGenFunction.h | 2 +- clang/lib/CodeGen/CodeGenModule.cpp | 1 + clang/lib/CodeGen/CodeGenPGO.cpp | 150 - clang/lib/CodeGen/CodeGenPGO.h| 6 +- clang/lib/CodeGen/CoverageMappingGen.cpp | 206 +- .../CoverageMapping/single-byte-counters.cpp | 169 ++ compiler-rt/lib/profile/InstrProfiling.h | 3 +- .../ProfileData/Coverage/CoverageMapping.h| 20 +- .../llvm/ProfileData/InstrProfWriter.h| 4 + .../ProfileData/Coverage/CoverageMapping.cpp | 13 +- llvm/lib/ProfileData/InstrProf.cpp| 10 +- 16 files changed, 630 insertions(+), 95 deletions(-) create mode 100644 clang/test/CoverageMapping/single-byte-counters.cpp diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 22f55fe9aac904..377bf413c857cb 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -33,6 +33,10 @@ using namespace CodeGen; //Aggregate Expression Emitter //===--===// +namespace llvm { +extern cl::opt EnableSingleByteCoverage; +} // namespace llvm + namespace { class AggExprEmitter : public StmtVisitor { CodeGenFunction @@ -1278,7 +1282,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(LHSBlock); - CGF.incrementProfileCounter(E); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E->getTrueExpr()); + else +CGF.incrementProfileCounter(E); Visit(E->getTrueExpr()); eval.end(CGF); @@ -1293,6 +1300,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(RHSBlock); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E->getFalseExpr()); Visit(E->getFalseExpr()); eval.end(CGF); @@ -1301,6 +1310,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { E->getType()); CGF.EmitBlock(ContBlock); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E); } void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) { diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 9ddf0e763f139b..683097eea5e76a 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -28,6 +28,10 @@ using namespace CodeGen; //Complex Expression Emitter //===--===// +namespace llvm { +extern cl::opt EnableSingleByteCoverage; +} // namespace llvm + typedef CodeGenFunction::ComplexPairTy ComplexPairTy; /// Return the complex type that we are meant to emit. @@ -1329,7 +1333,11 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF); CGF.EmitBlock(LHSBlock); - CGF.incrementProfileCounter(E); + if (llvm::EnableSingleByteCoverage) +CGF.incrementProfileCounter(E->getTrueExpr()); + else +CGF.incrementProfileCounter(E); + ComplexPairTy LHS = Visit(E->getTrueExpr()); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); @@ -1337,9 +1345,13 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.begin(CGF);
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
kees wrote: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102317 https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] bad error message on incorrect string literal #18079 (PR #81670)
@@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -E -fsyntax-only -verify %s + +// expected-error@+2{{invalid character ')' character in raw string delimiter; use PREFIX( )PREFIX to delimit raw string}} jroelofs wrote: This has the old spelling of that diagnostic. Also, might be a little nicer to combine the two tests in one file, since they're testing _almost_ the same thing. https://github.com/llvm/llvm-project/pull/81670 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
@@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); haoNoQ wrote: This probably needs a null check. (But I don't think it's the root cause of the crash you mentioned offline.) https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [llvm] [InstrProf] Single byte counters in coverage (PR #75425)
https://github.com/gulfemsavrun edited https://github.com/llvm/llvm-project/pull/75425 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
https://github.com/jkorous-apple updated https://github.com/llvm/llvm-project/pull/80504 >From e075dc3ac10c0cd2e12b223988ec4821b40b55d2 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Fri, 2 Feb 2024 14:46:59 -0800 Subject: [PATCH 1/4] [-Wunsafe-buffer-usage] Ignore safe array subscripts Don't emit warnings for array subscripts on constant size arrays where the index is constant and within bounds. Example: int arr[10]; arr[5] = 0; //safe, no warning This patch recognizes only array indices that are integer literals - it doesn't understand more complex expressions (arithmetic on constants, etc.). --- clang/lib/Analysis/UnsafeBufferUsage.cpp | 39 +++ .../warn-unsafe-buffer-usage-array.cpp| 18 - 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index ca346444e047e5..d150a679597a92 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -406,6 +406,31 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { } return false; } + +AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { + const DeclRefExpr * BaseDRE = dyn_cast_or_null(Node.getBase()->IgnoreParenImpCasts()); + if (!BaseDRE) +return false; + if (!BaseDRE->getDecl()) +return false; + auto BaseVarDeclTy = BaseDRE->getDecl()->getType(); + if (!BaseVarDeclTy->isConstantArrayType()) +return false; + const auto * CATy = dyn_cast_or_null(BaseVarDeclTy); + if (!CATy) +return false; + const APInt ArrSize = CATy->getSize(); + + if (const auto * IdxLit = dyn_cast(Node.getIdx())) { +const APInt ArrIdx = IdxLit->getValue(); +// FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a bug +if (ArrIdx.isNonNegative() && ArrIdx.getLimitedValue() < ArrSize.getLimitedValue()) + return true; + } + + return false; +} + } // namespace clang::ast_matchers namespace { @@ -598,16 +623,16 @@ class ArraySubscriptGadget : public WarningGadget { } static Matcher matcher() { -// FIXME: What if the index is integer literal 0? Should this be -// a safe gadget in this case? - // clang-format off +// clang-format off return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType(, -unless(hasIndex( -anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) - ))) -.bind(ArraySubscrTag)); +unless(anyOf( + isSafeArraySubscript(), + hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) + ) +))).bind(ArraySubscrTag)); // clang-format on } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp index 90c11b1be95c25..4804223e8be058 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-array.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: %clang_cc1 -std=c++20 -Wno-everything -Wunsafe-buffer-usage \ // RUN:-fsafe-buffer-usage-suggestions \ // RUN:-verify %s @@ -22,3 +22,19 @@ struct Foo { void foo2(Foo& f, unsigned idx) { f.member_buffer[idx] = 0; // expected-warning{{unsafe buffer access}} } + +void constant_idx_safe(unsigned idx) { + int buffer[10]; + buffer[9] = 0; +} + +void constant_idx_safe0(unsigned idx) { + int buffer[10]; + buffer[0] = 0; +} + +void constant_idx_unsafe(unsigned idx) { + int buffer[10]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}} +// expected-note@-1{{change type of 'buffer' to 'std::array' to harden it}} + buffer[10] = 0; // expected-note{{used in buffer access here}} +} >From 9f3940e5e1a8555a784521999d296ed46b1ae0c2 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Fri, 2 Feb 2024 14:48:41 -0800 Subject: [PATCH 2/4] [-Wunsafe-buffer-usage][NFC] Update existing tests after constant safe index is ignored --- ...afe-buffer-usage-fixits-pointer-access.cpp | 8 +-- ...ge-fixits-pointer-arg-to-func-ptr-call.cpp | 3 +- .../test/SemaCXX/warn-unsafe-buffer-usage.cpp | 53 ++- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp index f94072015ff87d..b3c64f1b0d085e 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp @@ -83,11 +83,11 @@ void unsafe_method_invocation_single_param() { } -void unsafe_method_invocation_single_param_array() { +void
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
@@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + } + + bool VisitConditionalOperator(const ConditionalOperator *CO) { +// Ternary operators are trivial if their conditions & values are trivial. +return VisitChildren(CO); + } + + bool VisitDeclRefExpr(const DeclRefExpr *DRE) { +if (auto *decl = DRE->getDecl()) { + if (isa(decl)) +return true; +} +return false; + } + + bool VisitStaticAssertDecl(const StaticAssertDecl *SAD) { +// Any static_assert is considered trivial. +return true; + } + + bool VisitCallExpr(const CallExpr *CE) { +if (auto *MCE = dyn_cast(CE)) + return VisitCXXMemberCallExpr(MCE); haoNoQ wrote: This happens automatically, you don't need to do that manually. The visitor calls the most specialized user-defined method. (If it's not user-defined, it's defined by default to call the slightly less specialized method.) On the other hand, it might make sense to call `VisitCallExpr()` from inside `VisitCXXMemberCallExpr()` to reuse some code. (Or you can define a common method called by both.) https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/haoNoQ commented: LGTM! Just one nitpick. https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/haoNoQ edited https://github.com/llvm/llvm-project/pull/81808 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Fixits for unsafe arguments of function pointer calls (PR #80358)
https://github.com/jkorous-apple closed https://github.com/llvm/llvm-project/pull/80358 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 4cd7616 - [-Wunsafe-buffer-usage] Fixits for array args of func-ptr calls (#80358)
Author: jkorous-apple Date: 2024-02-14T17:19:39-08:00 New Revision: 4cd7616f6b13513bb13f2b6dd14d140a4c62c937 URL: https://github.com/llvm/llvm-project/commit/4cd7616f6b13513bb13f2b6dd14d140a4c62c937 DIFF: https://github.com/llvm/llvm-project/commit/4cd7616f6b13513bb13f2b6dd14d140a4c62c937.diff LOG: [-Wunsafe-buffer-usage] Fixits for array args of func-ptr calls (#80358) Currently we ignore calls on function pointers (unlike direct calls of functions and class methods). This patch adds support for function pointers as well. The change is to simply replace use of forEachArgumentWithParam matcher in UPC gadget with forEachArgumentWithParamType. from the documentation of forEachArgumentWithParamType: /// Matches all arguments and their respective types for a \c CallExpr or /// \c CXXConstructExpr. It is very similar to \c forEachArgumentWithParam but /// it works on calls through function pointers as well. Currently the matcher also uses hasPointerType() which checks that the canonical type of an argument is pointer and won't match on arrays decayed to pointer. Replacing hasPointerType() with isAnyPointerType() which allows implicit casts allows for the arrays to be matched as well and this way we get fixits for array arguments to function pointer calls too. Added: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-arg-to-func-ptr-call.cpp Modified: clang/lib/Analysis/UnsafeBufferUsage.cpp Removed: diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index d00c598c4b9de3..ca346444e047e5 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -281,10 +281,13 @@ isInUnspecifiedPointerContext(internal::Matcher InnerMatcher) { // 4. the operand of a pointer subtraction operation //(i.e., computing the distance between two pointers); or ... - auto CallArgMatcher = - callExpr(forEachArgumentWithParam(InnerMatcher, - hasPointerType() /* array also decays to pointer type*/), - unless(callee(functionDecl(hasAttr(attr::UnsafeBufferUsage); + // clang-format off + auto CallArgMatcher = callExpr( +forEachArgumentWithParamType( + InnerMatcher, + isAnyPointer() /* array also decays to pointer type*/), +unless(callee( + functionDecl(hasAttr(attr::UnsafeBufferUsage); auto CastOperandMatcher = castExpr(anyOf(hasCastKind(CastKind::CK_PointerToIntegral), @@ -306,6 +309,7 @@ isInUnspecifiedPointerContext(internal::Matcher InnerMatcher) { hasRHS(hasPointerType())), eachOf(hasLHS(InnerMatcher), hasRHS(InnerMatcher))); + // clang-format on return stmt(anyOf(CallArgMatcher, CastOperandMatcher, CompOperandMatcher, PtrSubtractionMatcher)); diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-arg-to-func-ptr-call.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-arg-to-func-ptr-call.cpp new file mode 100644 index 00..0459d6549fd86f --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-arg-to-func-ptr-call.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN:-fsafe-buffer-usage-suggestions \ +// RUN:-fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +void unsafe_array_func_ptr_call(void (*fn_ptr)(int *param)) { + int p[32]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::array p" + + p[5] = 10; + fn_ptr(p); + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:11}:".data()" +} + +void unsafe_ptr_func_ptr_call(void (*fn_ptr)(int *param)) { + int *p; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span p" + + p[5] = 10; + fn_ptr(p); + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:11}:".data()" +} + +void addr_of_unsafe_ptr_func_ptr_call(void (*fn_ptr)(int *param)) { + int *p; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span p" + + p[5] = 10; + fn_ptr([0]); + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:15}:"p.data()" +} + +void addr_of_unsafe_ptr_w_offset_func_ptr_call(void (*fn_ptr)(int *param)) { + int *p; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span p" + + p[5] = 10; + fn_ptr([3]); + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:15}:"()[3]" +} + +void preincrement_unsafe_ptr_func_ptr_call(void (*fn_ptr)(int *param)) { + int *p; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span p" + + p[5] = 10; + fn_ptr(++p); + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:13}:"(p = p.subspan(1)).data()" +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org
[clang] [-Wunsafe-buffer-usage] Fixits for unsafe arguments of function pointer calls (PR #80358)
jkorous-apple wrote: Currently we ignore calls on function pointers (unlike direct calls of functions and class methods). This patch adds support for function pointers as well. The change is to simply replace use of forEachArgumentWithParam matcher in UPC gadget with forEachArgumentWithParamType. from the documentation of forEachArgumentWithParamType: /// Matches all arguments and their respective types for a \c CallExpr or /// \c CXXConstructExpr. It is very similar to \c forEachArgumentWithParam but /// it works on calls through function pointers as well. Currently the matcher also uses hasPointerType() which checks that the canonical type of an argument is pointer and won't match on arrays decayed to pointer. Replacing hasPointerType() with isAnyPointerType() which allows implicit casts allows for the arrays to be matched as well and this way we get fixits for array arguments to function pointer calls too. https://github.com/llvm/llvm-project/pull/80358 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Fixits for unsafe arguments of function pointer calls (PR #80358)
@@ -282,8 +282,8 @@ isInUnspecifiedPointerContext(internal::Matcher InnerMatcher) { //(i.e., computing the distance between two pointers); or ... auto CallArgMatcher = - callExpr(forEachArgumentWithParam(InnerMatcher, - hasPointerType() /* array also decays to pointer type*/), + callExpr(forEachArgumentWithParamType(InnerMatcher, + isAnyPointer() /* array also decays to pointer type*/), jkorous-apple wrote: Summary of an offline discussion: Actually, the above is wrong because we're talking about the parameter type, not argument type but it also voids the concern. https://github.com/llvm/llvm-project/pull/80358 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [Sanitizer] add signed-integer-wrap sanitizer (PR #80089)
MaskRay wrote: This is a UI discussion about how command line options should behave. Some folks prefer simpler rules while some prefer smart rules (guessing what the user intends). A [-fwrapv](https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fwrapv) user may either: * rely on the wraparound behavior * or prevent certain optimizations that would raise security concerns Our -fsanitize=signed-integer-overflow design have been assuming that -fwrapv users don't need the check. This PR suggests that an important user does want overflow checks. It seems very confusing to have two options doing the same thing. I think we can try -fsanitize=signed-integer-overflow effective when -fwrapv. There is a precedent that -fsanitize=undefined enables different checks for different targets. We could make -fsanitize=undefined not imply -fsanitize=signed-integer-overflow when -fwrapv is specified, if we do want to guess the user intention. Personally I'd prefer moving away from such behaviors and be more orthogonal. https://github.com/llvm/llvm-project/pull/80089 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81808 >From 857decc27550e2b15938a7846a03561f9ad73f48 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 16:21:33 -0800 Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- .../Checkers/WebKit/ASTUtils.cpp | 4 + .../Checkers/WebKit/PtrTypesSemantics.cpp | 207 .../Checkers/WebKit/PtrTypesSemantics.h | 21 ++ .../WebKit/UncountedCallArgsChecker.cpp | 8 +- .../Analysis/Checkers/WebKit/call-args.cpp| 33 +-- .../Checkers/WebKit/uncounted-obj-arg.cpp | 231 ++ 6 files changed, 487 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..17f59c2d304ddc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,210 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + } + +
[clang] bad error message on incorrect string literal #18079 (PR #81670)
https://github.com/akshaykumars614 updated https://github.com/llvm/llvm-project/pull/81670 >From c2f716ee5f787ec3df63511fd5f565a3deee4d6e Mon Sep 17 00:00:00 2001 From: akshaykumars614 Date: Tue, 13 Feb 2024 16:29:51 -0500 Subject: [PATCH 1/6] issue: #18079 (bad errwqor message on incorrect string literal) Fixed the error message for incorrect string literal --- clang/include/clang/Basic/DiagnosticLexKinds.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 75ca2fa16d3485..c5a2096d02b39d 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -100,7 +100,7 @@ def err_raw_delim_too_long : Error< "raw string delimiter longer than 16 characters" "; use PREFIX( )PREFIX to delimit raw string">; def err_invalid_char_raw_delim : Error< - "invalid character '%0' character in raw string delimiter" + "invalid newline character in raw string delimiter" "; use PREFIX( )PREFIX to delimit raw string">; def err_unterminated_raw_string : Error< "raw string missing terminating delimiter )%0\"">; >From ac8b99309b07b6c7114dfbf784a46d2fb5d9dcc4 Mon Sep 17 00:00:00 2001 From: akshaykumars614 Date: Wed, 14 Feb 2024 14:04:52 -0500 Subject: [PATCH 2/6] bad error message on incorrect string literal #18079 Introduced new error code for \n delimiter in raw string delimiter. Added testcase to test the same. --- clang/include/clang/Basic/DiagnosticLexKinds.td | 3 +++ clang/lib/Lex/Lexer.cpp | 6 -- clang/test/Lexer/raw-string-dlim-newline.cpp| 5 + 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 clang/test/Lexer/raw-string-dlim-newline.cpp diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index c5a2096d02b39d..0bc684a9db5793 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -102,6 +102,9 @@ def err_raw_delim_too_long : Error< def err_invalid_char_raw_delim : Error< "invalid newline character in raw string delimiter" "; use PREFIX( )PREFIX to delimit raw string">; +def err_invalid_nexline_raw_delim : Error< + "invalid newline character in raw string delimiter" + "; use PREFIX( )PREFIX to delimit raw string">; def err_unterminated_raw_string : Error< "raw string missing terminating delimiter )%0\"">; def warn_cxx98_compat_raw_string_literal : Warning< diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index d927f28b47c270..95f39df7a4628a 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -2270,10 +2270,12 @@ bool Lexer::LexRawStringLiteral(Token , const char *CurPtr, const char *PrefixEnd = [PrefixLen]; if (PrefixLen == 16) { Diag(PrefixEnd, diag::err_raw_delim_too_long); - } else { + } else if (*PrefixEnd != '\n') { Diag(PrefixEnd, diag::err_invalid_char_raw_delim) << StringRef(PrefixEnd, 1); - } + } else { +Diag(PrefixEnd, diag::err_invalid_nexline_raw_delim); + } } // Search for the next '"' in hopes of salvaging the lexer. Unfortunately, diff --git a/clang/test/Lexer/raw-string-dlim-newline.cpp b/clang/test/Lexer/raw-string-dlim-newline.cpp new file mode 100644 index 00..36939ed864ecae --- /dev/null +++ b/clang/test/Lexer/raw-string-dlim-newline.cpp @@ -0,0 +1,5 @@ +// RUN: not %clang_cc1 -E %s 2>&1 | grep 'error: invalid newline character in raw string delimiter; use PREFIX( )PREFIX to delimit raw string' + +// Introduced new error code err_invalid_nexline_raw_delim for code which has \n as delimiter. +char const* str1 = R" +"; >From f8ede1571c5678aa6cdbce7cc0d5b30f191b4e92 Mon Sep 17 00:00:00 2001 From: akshaykumars614 <88362922+akshaykumars...@users.noreply.github.com> Date: Wed, 14 Feb 2024 14:15:34 -0500 Subject: [PATCH 3/6] Update clang/include/clang/Basic/DiagnosticLexKinds.td Co-authored-by: Jon Roelofs --- clang/include/clang/Basic/DiagnosticLexKinds.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 0bc684a9db5793..1db34adf6bee61 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -102,7 +102,7 @@ def err_raw_delim_too_long : Error< def err_invalid_char_raw_delim : Error< "invalid newline character in raw string delimiter" "; use PREFIX( )PREFIX to delimit raw string">; -def err_invalid_nexline_raw_delim : Error< +def err_invalid_newline_raw_delim : Error< "invalid newline character in raw string delimiter" "; use PREFIX( )PREFIX to delimit raw string">; def err_unterminated_raw_string : Error< >From baa768ebc8f5a5359a8921c110a39d3ff8739747 Mon Sep 17 00:00:00 2001 From:
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/81808 >From 5a5b26fc3ed2c1c263cd3495b8844e2daeb2e54b Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 16:21:33 -0800 Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- .../Checkers/WebKit/ASTUtils.cpp | 4 + .../Checkers/WebKit/PtrTypesSemantics.cpp | 208 .../Checkers/WebKit/PtrTypesSemantics.h | 21 ++ .../WebKit/UncountedCallArgsChecker.cpp | 8 +- .../Analysis/Checkers/WebKit/call-args.cpp| 33 +-- .../Checkers/WebKit/uncounted-obj-arg.cpp | 231 ++ 6 files changed, 488 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..ba02c7a786871d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,211 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); +} + + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return Visit(BO->getLHS()) && Visit(BO->getRHS()); + } +
[clang] [RISCV] Disable generation of asynchronous unwind tables for RISCV baremetal (PR #81727)
MaskRay wrote: I wonder whether GCC considers using `-fno-asynchronous-unwind-tables` for all RISC-V configurations. https://github.com/llvm/llvm-project/pull/81727 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
https://github.com/ributzka approved this pull request. LGTM https://github.com/llvm/llvm-project/pull/81701 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/81701 >From 9d0da0010f145b23ce2b7e5b6183558609600789 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 13 Feb 2024 18:22:23 -0800 Subject: [PATCH 1/3] [clang][InstallAPI] Add input file support to library This patch adds support for expected InstallAPI inputs. InstallAPI accepts a well defined filelist of headers and how those headers represent a single library. InstallAPI captures header files to determine linkable symbols to then compare against what was compiled in a binary dylib and generate TBD files. --- clang/include/clang/InstallAPI/FileList.h | 53 + clang/include/clang/InstallAPI/HeaderFile.h | 72 +++ clang/lib/ExtractAPI/CMakeLists.txt | 1 + clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 7 +- clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/FileList.cpp | 196 ++ clang/lib/InstallAPI/HeaderFile.cpp | 37 clang/unittests/CMakeLists.txt| 1 + clang/unittests/InstallAPI/CMakeLists.txt | 9 + clang/unittests/InstallAPI/FileListTest.cpp | 140 + clang/unittests/InstallAPI/HeaderFileTest.cpp | 89 11 files changed, 603 insertions(+), 4 deletions(-) create mode 100644 clang/include/clang/InstallAPI/FileList.h create mode 100644 clang/include/clang/InstallAPI/HeaderFile.h create mode 100644 clang/lib/InstallAPI/FileList.cpp create mode 100644 clang/lib/InstallAPI/HeaderFile.cpp create mode 100644 clang/unittests/InstallAPI/CMakeLists.txt create mode 100644 clang/unittests/InstallAPI/FileListTest.cpp create mode 100644 clang/unittests/InstallAPI/HeaderFileTest.cpp diff --git a/clang/include/clang/InstallAPI/FileList.h b/clang/include/clang/InstallAPI/FileList.h new file mode 100644 index 00..01ec9b35e31490 --- /dev/null +++ b/clang/include/clang/InstallAPI/FileList.h @@ -0,0 +1,53 @@ +//===- InstallAPI/FileList.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The JSON file list parser is used to communicate input to InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H +#define LLVM_CLANG_INSTALLAPI_FILELIST_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// JSON decoder for InstallAPI Inputs. +class FileListReader { + + class Implementation; + Implementation + + FileListReader(std::unique_ptr InputBuffer, + llvm::Error ); + +public: + /// Decode JSON input and append header input into destination container. + /// Headers are loaded in the order they appear in the JSON input. + /// + /// \param InputBuffer JSON input data. + /// \param Destination Container to load headers into. + static llvm::Error + loadHeaders(std::unique_ptr InputBuffer, + HeaderSeq ); + + ~FileListReader(); + + FileListReader(const FileListReader &) = delete; + FileListReader =(const FileListReader &) = delete; +}; + +} // namespace installapi +} // namespace clang + +#endif // LLVM_CLANG_INSTALLAPI_FILELIST_H diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h new file mode 100644 index 00..6ccd944f8b01be --- /dev/null +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -0,0 +1,72 @@ +//===- InstallAPI/HeaderFile.h --*- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// Representations of a library's headers for InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H +#define LLVM_CLANG_INSTALLAPI_HEADERFILE_H + +#include "clang/Basic/LangStandard.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Regex.h" +#include +#include + +namespace clang::installapi { +enum class HeaderType { + /// Represents declarations accessible to all clients. + Public, + /// Represents declarations accessible to a disclosed set of clients. + Private, + /// Represents declarations only accessible as implementation details to the + /// input library. + Project, +}; + +class HeaderFile { + /// Full
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff fe20a759fcd20e1755ea1b34c5e6447a787925dc 26f7904095ddd54ab54a94b3ae84db61d2135833 -- clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp clang/test/Analysis/Checkers/WebKit/call-args.cpp clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index b2169bf023..528ca77c49 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -233,10 +233,10 @@ bool isSingleton(const FunctionDecl *F) { const auto = safeGetName(F); std::string SingletonStr = "singleton"; auto index = Name.find(SingletonStr); - return index != std::string::npos && index == Name.size() - SingletonStr.size(); + return index != std::string::npos && + index == Name.size() - SingletonStr.size(); } - // We only care about statements so let's use the simple // (non-recursive) visitor. class TrivialFunctionAnalysisVisitor @@ -255,7 +255,7 @@ class TrivialFunctionAnalysisVisitor public: using CacheTy = TrivialFunctionAnalysis::CacheTy; - TrivialFunctionAnalysisVisitor(CacheTy ): Cache(Cache) {} + TrivialFunctionAnalysisVisitor(CacheTy ) : Cache(Cache) {} bool VisitStmt(const Stmt *S) { // All statements are non-trivial unless overriden later. @@ -263,9 +263,7 @@ public: return false; } - bool VisitDeclStmt(const DeclStmt *DS) { -return VisitChildren(DS); - } + bool VisitDeclStmt(const DeclStmt *DS) { return VisitChildren(DS); } bool VisitCompoundStmt(const CompoundStmt *CS) { // A compound statement is allowed as long each individual sub-statement @@ -278,25 +276,15 @@ public: return Visit(RS->getRetValue()); } - bool VisitDoStmt(const DoStmt *DS) { -return VisitChildren(DS); - } + bool VisitDoStmt(const DoStmt *DS) { return VisitChildren(DS); } - bool VisitIfStmt(const IfStmt *IS) { -return VisitChildren(IS); - } + bool VisitIfStmt(const IfStmt *IS) { return VisitChildren(IS); } - bool VisitSwitchStmt(const SwitchStmt *SS) { -return VisitChildren(SS); - } - - bool VisitCaseStmt(const CaseStmt* CS) { -return VisitChildren(CS); - } + bool VisitSwitchStmt(const SwitchStmt *SS) { return VisitChildren(SS); } - bool VisitDefaultStmt(const DefaultStmt* DS) { -return VisitChildren(DS); - } + bool VisitCaseStmt(const CaseStmt *CS) { return VisitChildren(CS); } + + bool VisitDefaultStmt(const DefaultStmt *DS) { return VisitChildren(DS); } bool VisitUnaryOperator(const UnaryOperator *UO) { // Operator '*' and '!' are allowed as long as the operand is trivial. @@ -316,7 +304,7 @@ public: // Ternary operators are trivial if their conditions & values are trivial. return VisitChildren(CO); } - + bool VisitDeclRefExpr(const DeclRefExpr *DRE) { if (auto *decl = DRE->getDecl()) { if (isa(decl)) @@ -336,7 +324,7 @@ public: for (const Expr *Arg : CE->arguments()) { if (Arg && !Visit(Arg)) -return false; +return false; } auto *Callee = CE->getDirectCallee(); @@ -344,8 +332,8 @@ public: return false; const auto = safeGetName(Callee); -if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" -|| Name == "compilerFenceForCrash" || Name == "__builtin_unreachable") +if (Name == "WTFCrashWithInfo" || Name == "WTFBreakpointTrap" || +Name == "compilerFenceForCrash" || Name == "__builtin_unreachable") return true; return TrivialFunctionAnalysis::isTrivialImpl(Callee, Cache); @@ -354,7 +342,7 @@ public: bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE) { for (const Expr *Arg : MCE->arguments()) { if (Arg && !Visit(Arg)) -return false; +return false; } bool TrivialThis = Visit(MCE->getImplicitObjectArgument()); @@ -366,7 +354,6 @@ public: if (IsGetterOfRefCounted && *IsGetterOfRefCounted) return true; - // Recursively descend into the callee to confirm that it's trivial as well. return TrivialFunctionAnalysis::isTrivialImpl(MCE->getDirectCallee(), Cache); @@ -378,27 +365,20 @@ public: return false; // Recursively descend into the callee to confirm that it's trivial. -return TrivialFunctionAnalysis::isTrivialImpl(CE->getConstructor(), -
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Ryosuke Niwa (rniwa) Changes This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- Patch is 21.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81808.diff 6 Files Affected: - (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp (+4) - (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (+246) - (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+23) - (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp (+7-1) - (modified) clang/test/Analysis/Checkers/WebKit/call-args.cpp (+17-16) - (modified) clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp (+231) ``diff diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..b2169bf023c6e9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,249 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && index == Name.size() - SingletonStr.size(); +} + + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ): Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitDeclStmt(const DeclStmt *DS) { +return VisitChildren(DS); + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDoStmt(const DoStmt *DS) { +return VisitChildren(DS); + } + + bool VisitIfStmt(const IfStmt *IS) { +return VisitChildren(IS); + } + + bool VisitSwitchStmt(const SwitchStmt *SS) { +return VisitChildren(SS); + } + + bool VisitCaseStmt(const CaseStmt* CS) { +return VisitChildren(CS); + } + + bool VisitDefaultStmt(const DefaultStmt* DS) { +return VisitChildren(DS); + } + + 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) + return Visit(UO->getSubExpr()); + +// Other operators are non-trivial. +return false; + } + + bool VisitBinaryOperator(const BinaryOperator *BO) { +// Binary operators are trivial if their operands are trivial. +return
[clang] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. (PR #81808)
https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/81808 This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. >From 26f7904095ddd54ab54a94b3ae84db61d2135833 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 14 Feb 2024 16:21:33 -0800 Subject: [PATCH] [alpha.webkit.UncountedCallArgsChecker] Detect & ignore trivial function calls. This PR introduces the concept of a "trivial function" which applies to a function that only calls other trivial functions and contain literals and expressions that don't result in heap mutations (specifically it does not call deref). This is implemented using ConstStmtVisitor and checking each statement and expression's trivialness. This PR also introduces the concept of a "ingleton function", which is a static member function or a free standing function which ends with the suffix "singleton". Such a function's return value is understood to be safe to call any function with. --- .../Checkers/WebKit/ASTUtils.cpp | 4 + .../Checkers/WebKit/PtrTypesSemantics.cpp | 246 ++ .../Checkers/WebKit/PtrTypesSemantics.h | 23 ++ .../WebKit/UncountedCallArgsChecker.cpp | 8 +- .../Analysis/Checkers/WebKit/call-args.cpp| 33 +-- .../Checkers/WebKit/uncounted-obj-arg.cpp | 231 6 files changed, 528 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp index b76c0551c77bb0..94eaa81af51772 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp @@ -66,9 +66,13 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) { E = call->getArg(0); continue; } + if (isReturnValueRefCounted(callee)) return {E, true}; +if (isSingleton(callee)) + return {E, true}; + if (isPtrConversion(callee)) { E = call->getArg(0); continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index 907244013d0871..b2169bf023c6e9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -12,6 +12,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" #include using namespace clang; @@ -222,4 +223,249 @@ bool isPtrConversion(const FunctionDecl *F) { return false; } +bool isSingleton(const FunctionDecl *F) { + assert(F); + // FIXME: check # of params == 1 + if (auto *MethodDecl = dyn_cast(F)) { +if (!MethodDecl->isStatic()) + return false; + } + const auto = safeGetName(F); + std::string SingletonStr = "singleton"; + auto index = Name.find(SingletonStr); + return index != std::string::npos && index == Name.size() - SingletonStr.size(); +} + + +// We only care about statements so let's use the simple +// (non-recursive) visitor. +class TrivialFunctionAnalysisVisitor +: public ConstStmtVisitor { + + // Returns false if at least one child is non-trivial. + bool VisitChildren(const Stmt *S) { +for (const Stmt *Child : S->children()) { + if (Child && !Visit(Child)) +return false; +} + +return true; + } + +public: + using CacheTy = TrivialFunctionAnalysis::CacheTy; + + TrivialFunctionAnalysisVisitor(CacheTy ): Cache(Cache) {} + + bool VisitStmt(const Stmt *S) { +// All statements are non-trivial unless overriden later. +// Don't even recurse into children by default. +return false; + } + + bool VisitDeclStmt(const DeclStmt *DS) { +return VisitChildren(DS); + } + + bool VisitCompoundStmt(const CompoundStmt *CS) { +// A compound statement is allowed as long each individual sub-statement +// is trivial. +return VisitChildren(CS); + } + + bool VisitReturnStmt(const ReturnStmt *RS) { +// A return statement is allowed as long as the return value is trivial. +return Visit(RS->getRetValue()); + } + + bool VisitDoStmt(const DoStmt *DS) { +return VisitChildren(DS); + } + + bool VisitIfStmt(const IfStmt *IS) { +return VisitChildren(IS); + } + + bool VisitSwitchStmt(const SwitchStmt *SS) { +return VisitChildren(SS); + } + + bool
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
@@ -0,0 +1,53 @@ +//===- InstallAPI/FileList.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The JSON file list parser is used to communicate input to InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H +#define LLVM_CLANG_INSTALLAPI_FILELIST_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// JSON decoder for InstallAPI Inputs. +class FileListReader { + + class Implementation; + Implementation + + FileListReader(std::unique_ptr InputBuffer, + llvm::Error ); + +public: + /// Decode JSON input and append header input into destination container. + /// Headers are loaded in the order they appear in the JSON input. + /// + /// \param InputBuffer JSON input data. + /// \param Destination Container to load headers into. + static llvm::Error + loadHeaders(std::unique_ptr InputBuffer, cyndyishida wrote: I want to keep the signature because the driver will accept multiple file lists but hold a single `HeaderSeq` and it's easier to handle continuous insertion. https://github.com/llvm/llvm-project/pull/81701 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [llvm] [IRPGO][ValueProfile] Instrument virtual table address that could be used to do virtual table address comparision for indirect-call-promotion. (PR #66825)
https://github.com/minglotus-6 edited https://github.com/llvm/llvm-project/pull/66825 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [compiler-rt] [llvm] [IRPGO][ValueProfile] Instrument virtual table address that could be used to do virtual table address comparision for indirect-call-promotion. (PR #66825)
https://github.com/minglotus-6 edited https://github.com/llvm/llvm-project/pull/66825 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
@@ -0,0 +1,53 @@ +//===- InstallAPI/FileList.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The JSON file list parser is used to communicate input to InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H +#define LLVM_CLANG_INSTALLAPI_FILELIST_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// JSON decoder for InstallAPI Inputs. +class FileListReader { + + class Implementation; + Implementation + + FileListReader(std::unique_ptr InputBuffer, + llvm::Error ); + +public: + /// Decode JSON input and append header input into destination container. + /// Headers are loaded in the order they appear in the JSON input. + /// + /// \param InputBuffer JSON input data. + /// \param Destination Container to load headers into. + static llvm::Error + loadHeaders(std::unique_ptr InputBuffer, ributzka wrote: This could be now changed to `Expected` and return the `HeaderSeq`. https://github.com/llvm/llvm-project/pull/81701 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
@@ -0,0 +1,53 @@ +//===- InstallAPI/FileList.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The JSON file list parser is used to communicate input to InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H +#define LLVM_CLANG_INSTALLAPI_FILELIST_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// JSON decoder for InstallAPI Inputs. +class FileListReader { + + class Implementation; + Implementation ributzka wrote: Since everything has now moved into the `loadHeaders` method, you can now even remove `Impl`. https://github.com/llvm/llvm-project/pull/81701 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/81701 >From 9d0da0010f145b23ce2b7e5b6183558609600789 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 13 Feb 2024 18:22:23 -0800 Subject: [PATCH 1/2] [clang][InstallAPI] Add input file support to library This patch adds support for expected InstallAPI inputs. InstallAPI accepts a well defined filelist of headers and how those headers represent a single library. InstallAPI captures header files to determine linkable symbols to then compare against what was compiled in a binary dylib and generate TBD files. --- clang/include/clang/InstallAPI/FileList.h | 53 + clang/include/clang/InstallAPI/HeaderFile.h | 72 +++ clang/lib/ExtractAPI/CMakeLists.txt | 1 + clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 7 +- clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/FileList.cpp | 196 ++ clang/lib/InstallAPI/HeaderFile.cpp | 37 clang/unittests/CMakeLists.txt| 1 + clang/unittests/InstallAPI/CMakeLists.txt | 9 + clang/unittests/InstallAPI/FileListTest.cpp | 140 + clang/unittests/InstallAPI/HeaderFileTest.cpp | 89 11 files changed, 603 insertions(+), 4 deletions(-) create mode 100644 clang/include/clang/InstallAPI/FileList.h create mode 100644 clang/include/clang/InstallAPI/HeaderFile.h create mode 100644 clang/lib/InstallAPI/FileList.cpp create mode 100644 clang/lib/InstallAPI/HeaderFile.cpp create mode 100644 clang/unittests/InstallAPI/CMakeLists.txt create mode 100644 clang/unittests/InstallAPI/FileListTest.cpp create mode 100644 clang/unittests/InstallAPI/HeaderFileTest.cpp diff --git a/clang/include/clang/InstallAPI/FileList.h b/clang/include/clang/InstallAPI/FileList.h new file mode 100644 index 00..01ec9b35e31490 --- /dev/null +++ b/clang/include/clang/InstallAPI/FileList.h @@ -0,0 +1,53 @@ +//===- InstallAPI/FileList.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The JSON file list parser is used to communicate input to InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H +#define LLVM_CLANG_INSTALLAPI_FILELIST_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// JSON decoder for InstallAPI Inputs. +class FileListReader { + + class Implementation; + Implementation + + FileListReader(std::unique_ptr InputBuffer, + llvm::Error ); + +public: + /// Decode JSON input and append header input into destination container. + /// Headers are loaded in the order they appear in the JSON input. + /// + /// \param InputBuffer JSON input data. + /// \param Destination Container to load headers into. + static llvm::Error + loadHeaders(std::unique_ptr InputBuffer, + HeaderSeq ); + + ~FileListReader(); + + FileListReader(const FileListReader &) = delete; + FileListReader =(const FileListReader &) = delete; +}; + +} // namespace installapi +} // namespace clang + +#endif // LLVM_CLANG_INSTALLAPI_FILELIST_H diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h new file mode 100644 index 00..6ccd944f8b01be --- /dev/null +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -0,0 +1,72 @@ +//===- InstallAPI/HeaderFile.h --*- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// Representations of a library's headers for InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H +#define LLVM_CLANG_INSTALLAPI_HEADERFILE_H + +#include "clang/Basic/LangStandard.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Regex.h" +#include +#include + +namespace clang::installapi { +enum class HeaderType { + /// Represents declarations accessible to all clients. + Public, + /// Represents declarations accessible to a disclosed set of clients. + Private, + /// Represents declarations only accessible as implementation details to the + /// input library. + Project, +}; + +class HeaderFile { + /// Full
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
@@ -406,6 +406,31 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { } return false; } + +AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { + const DeclRefExpr * BaseDRE = dyn_cast_or_null(Node.getBase()->IgnoreParenImpCasts()); + if (!BaseDRE) +return false; + if (!BaseDRE->getDecl()) +return false; + auto BaseVarDeclTy = BaseDRE->getDecl()->getType(); + if (!BaseVarDeclTy->isConstantArrayType()) +return false; + const auto * CATy = dyn_cast_or_null(BaseVarDeclTy); jkorous-apple wrote: Use `getAsArrayType` instead of `dyn_cast`. https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
@@ -406,6 +406,31 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { } return false; } + +AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { + const DeclRefExpr * BaseDRE = dyn_cast_or_null(Node.getBase()->IgnoreParenImpCasts()); + if (!BaseDRE) +return false; + if (!BaseDRE->getDecl()) +return false; + auto BaseVarDeclTy = BaseDRE->getDecl()->getType(); + if (!BaseVarDeclTy->isConstantArrayType()) +return false; + const auto * CATy = dyn_cast_or_null(BaseVarDeclTy); jkorous-apple wrote: Take a look getAsConstantArrayType(). https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [-Wunsafe-buffer-usage] Ignore constant safe indices in array subscripts (PR #80504)
@@ -598,16 +623,16 @@ class ArraySubscriptGadget : public WarningGadget { } static Matcher matcher() { -// FIXME: What if the index is integer literal 0? Should this be -// a safe gadget in this case? - // clang-format off +// clang-format off return stmt(arraySubscriptExpr( hasBase(ignoringParenImpCasts( anyOf(hasPointerType(), hasArrayType(, -unless(hasIndex( -anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) - ))) -.bind(ArraySubscrTag)); +unless(anyOf( + isSafeArraySubscript(), + hasIndex( + anyOf(integerLiteral(equals(0)), arrayInitIndexExpr()) jkorous-apple wrote: This is unnecessary now. https://github.com/llvm/llvm-project/pull/80504 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][InstallAPI] Add input file support to library (PR #81701)
https://github.com/cyndyishida updated https://github.com/llvm/llvm-project/pull/81701 >From 9d0da0010f145b23ce2b7e5b6183558609600789 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Tue, 13 Feb 2024 18:22:23 -0800 Subject: [PATCH] [clang][InstallAPI] Add input file support to library This patch adds support for expected InstallAPI inputs. InstallAPI accepts a well defined filelist of headers and how those headers represent a single library. InstallAPI captures header files to determine linkable symbols to then compare against what was compiled in a binary dylib and generate TBD files. --- clang/include/clang/InstallAPI/FileList.h | 53 + clang/include/clang/InstallAPI/HeaderFile.h | 72 +++ clang/lib/ExtractAPI/CMakeLists.txt | 1 + clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 7 +- clang/lib/InstallAPI/CMakeLists.txt | 2 + clang/lib/InstallAPI/FileList.cpp | 196 ++ clang/lib/InstallAPI/HeaderFile.cpp | 37 clang/unittests/CMakeLists.txt| 1 + clang/unittests/InstallAPI/CMakeLists.txt | 9 + clang/unittests/InstallAPI/FileListTest.cpp | 140 + clang/unittests/InstallAPI/HeaderFileTest.cpp | 89 11 files changed, 603 insertions(+), 4 deletions(-) create mode 100644 clang/include/clang/InstallAPI/FileList.h create mode 100644 clang/include/clang/InstallAPI/HeaderFile.h create mode 100644 clang/lib/InstallAPI/FileList.cpp create mode 100644 clang/lib/InstallAPI/HeaderFile.cpp create mode 100644 clang/unittests/InstallAPI/CMakeLists.txt create mode 100644 clang/unittests/InstallAPI/FileListTest.cpp create mode 100644 clang/unittests/InstallAPI/HeaderFileTest.cpp diff --git a/clang/include/clang/InstallAPI/FileList.h b/clang/include/clang/InstallAPI/FileList.h new file mode 100644 index 00..01ec9b35e31490 --- /dev/null +++ b/clang/include/clang/InstallAPI/FileList.h @@ -0,0 +1,53 @@ +//===- InstallAPI/FileList.h *- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// The JSON file list parser is used to communicate input to InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_FILELIST_H +#define LLVM_CLANG_INSTALLAPI_FILELIST_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/InstallAPI/HeaderFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace clang { +namespace installapi { + +/// JSON decoder for InstallAPI Inputs. +class FileListReader { + + class Implementation; + Implementation + + FileListReader(std::unique_ptr InputBuffer, + llvm::Error ); + +public: + /// Decode JSON input and append header input into destination container. + /// Headers are loaded in the order they appear in the JSON input. + /// + /// \param InputBuffer JSON input data. + /// \param Destination Container to load headers into. + static llvm::Error + loadHeaders(std::unique_ptr InputBuffer, + HeaderSeq ); + + ~FileListReader(); + + FileListReader(const FileListReader &) = delete; + FileListReader =(const FileListReader &) = delete; +}; + +} // namespace installapi +} // namespace clang + +#endif // LLVM_CLANG_INSTALLAPI_FILELIST_H diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h new file mode 100644 index 00..6ccd944f8b01be --- /dev/null +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -0,0 +1,72 @@ +//===- InstallAPI/HeaderFile.h --*- C++ -*-===// +// +// 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 +// +//===--===// +/// +/// Representations of a library's headers for InstallAPI. +/// +//===--===// + +#ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H +#define LLVM_CLANG_INSTALLAPI_HEADERFILE_H + +#include "clang/Basic/LangStandard.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Regex.h" +#include +#include + +namespace clang::installapi { +enum class HeaderType { + /// Represents declarations accessible to all clients. + Public, + /// Represents declarations accessible to a disclosed set of clients. + Private, + /// Represents declarations only accessible as implementation details to the + /// input library. + Project, +}; + +class HeaderFile { + /// Full input