https://github.com/geoffreygaren updated https://github.com/llvm/llvm-project/pull/229843
>From 6dd124e309a92a7c3abf235c93edd77b0327af27 Mon Sep 17 00:00:00 2001 From: Geoff Garen <[email protected]> Date: Mon, 14 Sep 2026 10:03:52 -0700 Subject: [PATCH] [WebKit Checkers] Allow a view into a const CanBorrow object without a Borrow<T> Example: const Vector<char> vector = copyToVector(x); use(vector.span()); A const object can never be mutated, so it can never invalidate a view into its interior. This applies to a const-declared object only, not a const reference or const pointer -- which might refer to a non-const object. A const object also makes the values it contains const, so a view into a CanBorrow object held in a const std::optional qualifies too: const std::optional<Vector<char>> vector = copyToVector(x); use(vector->span()); Whether const propagates is decided by the type that dereferencing the const object yields, so a wrapper that vends a mutable value through a const overload -- a smart pointer, for instance -- does not qualify. A Vector that is built by appending can still reach this exemption by moving into a const local once it is complete. An escaping lambda only qualifies when it borrows from a const global; borrowing from a const local, and then escaping, is a use after free. Also: updated warning messages to mention that const is a possible solution. Assisted-by: Claude --- .../clang/StaticAnalyzer/Checkers/Checkers.td | 6 +- .../WebKit/RawPtrRefCallArgsChecker.cpp | 6 +- .../WebKit/RawPtrRefLambdaCapturesChecker.cpp | 16 +- .../WebKit/RawPtrRefLocalVarsChecker.cpp | 4 +- .../Checkers/WebKit/RawPtrRefSafetyModel.cpp | 57 +++++- .../Checkers/WebKit/RawPtrRefSafetyModel.h | 17 +- .../Analysis/Checkers/WebKit/mock-canborrow.h | 13 ++ .../Checkers/WebKit/unborrowed-call-args.cpp | 39 ++-- .../WebKit/unborrowed-lambda-captures.cpp | 39 +++- .../WebKit/unborrowed-local-vars-cxx23.cpp | 30 +-- .../Checkers/WebKit/unborrowed-local-vars.cpp | 189 +++++++++++++----- 11 files changed, 293 insertions(+), 123 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index e1a1046efab4305..9905649801e85bc 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1787,7 +1787,7 @@ def UnretainedCallArgsChecker : Checker<"UnretainedCallArgsChecker">, Documentation<HasDocumentation>; def UnborrowedCallArgsChecker : Checker<"UnborrowedCallArgsChecker">, - HelpText<"Check call arguments holding a loan on a CanBorrow object that is not guarded by a Borrow.">, + HelpText<"Check call arguments holding a loan on a CanBorrow object that is not guarded by const or a Borrow.">, Documentation<HasDocumentation>; def UncountedLocalVarsChecker : Checker<"UncountedLocalVarsChecker">, @@ -1807,11 +1807,11 @@ def UnretainedLocalVarsChecker : Checker<"UnretainedLocalVarsChecker">, Documentation<HasDocumentation>; def UnborrowedLocalVarsChecker : Checker<"UnborrowedLocalVarsChecker">, - HelpText<"Check local variables holding a loan on a CanBorrow object that is not guarded by a Borrow.">, + HelpText<"Check local variables holding a loan on a CanBorrow object that is not guarded by const or a Borrow.">, Documentation<HasDocumentation>; def UnborrowedLambdaCapturesChecker : Checker<"UnborrowedLambdaCapturesChecker">, - HelpText<"Check lambda captures holding a loan on a CanBorrow object that is not guarded by a Borrow.">, + HelpText<"Check lambda captures holding a loan on a CanBorrow object that is not guarded by const or a Borrow.">, Documentation<HasDocumentation>; def RetainPtrCtorAdoptChecker : Checker<"RetainPtrCtorAdoptChecker">, diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp index 19e5fd37d5cc0da..06848eecc536e50 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp @@ -323,8 +323,8 @@ class RawPtrRefCallArgsChecker if (isPtrOriginSafe(MCE->getImplicitObjectArgument())) return true; } - if (Model->isSafeExpr(ArgOrigin, PtrIsLifetimeBoundToOrigin, - SinkType)) + if (Model->isSafeExpr(ArgOrigin, PtrIsLifetimeBoundToOrigin, SinkType, + /*SinkMayEscape=*/false)) return true; if (Origin && !*Origin) *Origin = ArgOrigin; @@ -575,7 +575,7 @@ class UnborrowedCallArgsChecker final : public RawPtrRefCallArgsChecker { public: UnborrowedCallArgsChecker() : RawPtrRefCallArgsChecker("Loan on a CanBorrow object not guarded by " - "a Borrow", + "const or a Borrow", makeBorrowSafetyModel()) {} }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp index 6789071606a0deb..1e1beb10a828b92 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp @@ -609,10 +609,8 @@ class RawPtrRefLambdaCapturesChecker return tryToFindPtrOrigin( CaptureInit, /*StopAtFirstRefCountedObj=*/false, Model->checksForInteriorDestruction(), - [&](const clang::CXXRecordDecl *Record) { - return Model->isSafePtr(Record); - }, - [&](const clang::QualType Type) { return Model->isSafePtrType(Type); }, + [](const clang::CXXRecordDecl *) { return false; }, + [](const clang::QualType) { return false; }, [&](const clang::Decl *D) { return Model->isSafeDecl(D, BR->getSourceManager()); }, @@ -623,18 +621,10 @@ class RawPtrRefLambdaCapturesChecker return true; if (isa<CXXThisExpr>(CaptureOrigin)) return true; - // A Borrow in the enclosing scope does not travel with the lambda, - // so a loan taken through it is unguarded once the lambda escapes. - QualType OriginType = pointeeType(CaptureOrigin->getType()); - if (!OriginType.isNull() && isBorrowType(OriginType)) { - if (!Origin) - Origin = CaptureOrigin; - return false; - } if (IsSafe) return true; if (Model->isSafeExpr(CaptureOrigin, PtrIsLifetimeBoundToOrigin, - SinkType)) + SinkType, /*SinkMayEscape=*/true)) return true; if (!Origin) Origin = CaptureOrigin; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp index cb48b26ec3987fd..6ba7e95b23df46b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp @@ -478,7 +478,7 @@ class RawPtrRefLocalVarsChecker return true; if (Model->isSafeExpr(InitArgOrigin, PtrIsLifetimeBoundToOrigin, - SinkType)) + SinkType, /*SinkMayEscape=*/false)) return true; if (!Model->checksForInteriorDestruction() && @@ -606,7 +606,7 @@ class UnborrowedLocalVarsChecker final : public RawPtrRefLocalVarsChecker { public: UnborrowedLocalVarsChecker() : RawPtrRefLocalVarsChecker("Loan on a CanBorrow object not guarded by " - "a Borrow", + "const or a Borrow", makeBorrowSafetyModel()) {} }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.cpp index 0f3ca015e2aa28a..9aa60f3df2b466c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.cpp @@ -11,6 +11,7 @@ #include "DiagOutputUtils.h" #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/Type.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" @@ -58,7 +59,7 @@ class CheckedPtrSafetyModel : public PtrRefSafetyModel { bool isPtrType(const std::string &Name) const override { return isCheckedPtr(Name); } - bool isSafeExpr(const Expr *E, bool, QualType) const override { + bool isSafeExpr(const Expr *E, bool, QualType, bool) const override { return isExprToGetCheckedPtrCapableMember(E); } const char *typeName() const override { return "CheckedPtr-capable type"; } @@ -83,7 +84,7 @@ class RetainPtrSafetyModel : public PtrRefSafetyModel { bool isPtrType(const std::string &Name) const override { return isRetainPtrOrOSPtr(Name); } - bool isSafeExpr(const Expr *E, bool, QualType) const override { + bool isSafeExpr(const Expr *E, bool, QualType, bool) const override { return ento::cocoa::isCocoaObjectRef(E->getType()) && isa<ObjCMessageExpr>(E); } @@ -125,6 +126,38 @@ static bool isSameRecord(QualType A, QualType B) { RecordA->getCanonicalDecl() == RecordB->getCanonicalDecl(); } +static const ValueDecl *declaredObject(const Expr *E) { + const Expr *Stripped = E->IgnoreParenImpCasts(); + if (auto *DeclRef = dyn_cast<DeclRefExpr>(Stripped)) + return DeclRef->getDecl(); + if (auto *Member = dyn_cast<MemberExpr>(Stripped)) + return Member->getMemberDecl(); + return nullptr; +} + +// Returns the const-declared variable or member that E denotes, directly or +// through a dereference that vends it as const, or nullptr. +static const ValueDecl *constDeclaredObject(const Expr *E) { + const Expr *Stripped = E->IgnoreParenImpCasts(); + + if (auto *Op = dyn_cast<CXXOperatorCallExpr>(Stripped)) { + OverloadedOperatorKind Kind = Op->getOperator(); + if ((Kind != OO_Star && Kind != OO_Arrow) || Op->getNumArgs() != 1) + return nullptr; + if (!pointeeType(Op->getType()).isConstQualified()) + return nullptr; + return constDeclaredObject(Op->getArg(0)); + } + + const ValueDecl *Decl = declaredObject(Stripped); + if (!isa_and_nonnull<VarDecl>(Decl) && !isa_and_nonnull<FieldDecl>(Decl)) + return nullptr; + QualType T = Decl->getType(); + if (!T.isConstQualified() || T->isReferenceType() || T->isPointerType()) + return nullptr; + return Decl; +} + static bool mayHoldPointerTo(QualType ViewType, QualType CanBorrowType) { if (ViewType.isNull() || CanBorrowType.isNull()) return false; @@ -168,18 +201,26 @@ class BorrowSafetyModel : public PtrRefSafetyModel { } bool isSafeExpr(const Expr *Origin, bool PtrIsLifetimeBoundToOrigin, - QualType SinkType) const override { - if (!PtrIsLifetimeBoundToOrigin) - return true; - + QualType SinkType, bool SinkMayEscape) const override { QualType OriginType = pointeeType(Origin->getType()); - if (OriginType.isNull()) return true; + // A Borrow or a non-global const object guards a loan only within its own + // scope, so neither vouches for a sink that may outlive that scope. This + // holds for a reference to the Borrow itself, not just a loan through it. if (isBorrowType(OriginType)) + return !SinkMayEscape; + + if (!PtrIsLifetimeBoundToOrigin) return true; + if (const ValueDecl *ConstObject = constDeclaredObject(Origin)) { + auto *ConstVar = dyn_cast<VarDecl>(ConstObject); + if (!SinkMayEscape || (ConstVar && ConstVar->hasGlobalStorage())) + return true; + } + if (Origin->isPRValue() && isCanBorrowType(Origin->getType()).value_or(false) && !SinkType.isNull() && !mayHoldPointerTo(SinkType, Origin->getType())) @@ -218,7 +259,7 @@ class BorrowSafetyModel : public PtrRefSafetyModel { printTypeName(Os, OriginType); } else Os << "a CanBorrow object"; - Os << " that is not guarded by a Borrow"; + Os << " that is not guarded by const or a Borrow"; } }; diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.h index b0afbfb676b3956..46b05fb3a20bf22 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefSafetyModel.h @@ -56,12 +56,15 @@ class PtrRefSafetyModel { /// this policy. virtual bool isPtrType(const std::string &Name) const = 0; - /// \returns whether \p E is known to produce a safe value for this policy. - /// \p PtrIsLifetimeBoundToOrigin is whether the traversal that reached \p E - /// followed at least one [[clang::lifetimebound]] edge. \p SinkType is the - /// type of the variable or parameter that receives the value, if known. - virtual bool isSafeExpr(const Expr *, bool PtrIsLifetimeBoundToOrigin, - QualType SinkType) const { + /// \returns whether \p Origin is known to produce a safe value for this + /// policy. \p PtrIsLifetimeBoundToOrigin is whether the traversal that + /// reached \p Origin followed at least one [[clang::lifetimebound]] edge. + /// \p SinkType is the type of the variable or parameter that receives the + /// value, if known. \p SinkMayEscape is whether the receiving location may + /// outlive the scope that encloses \p Origin, as an escaping lambda capture + /// does. + virtual bool isSafeExpr(const Expr *Origin, bool PtrIsLifetimeBoundToOrigin, + QualType SinkType, bool SinkMayEscape) const { return false; } @@ -123,7 +126,7 @@ std::unique_ptr<PtrRefSafetyModel> makeCheckedPtrSafetyModel(); std::unique_ptr<PtrRefSafetyModel> makeRetainPtrSafetyModel(); /// \returns a policy that treats a loan on a CanBorrow object's interior as -/// safe only when it is guarded by a Borrow<T>. +/// safe only when it is guarded by const or a Borrow<T>. std::unique_ptr<PtrRefSafetyModel> makeBorrowSafetyModel(); } // namespace clang diff --git a/clang/test/Analysis/Checkers/WebKit/mock-canborrow.h b/clang/test/Analysis/Checkers/WebKit/mock-canborrow.h index fc756714dc4c1e1..99b4265f2b1d688 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-canborrow.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-canborrow.h @@ -282,6 +282,19 @@ template <typename A, typename B> struct pair { template <size_t I, typename A, typename B> A &get(pair<A, B> &); template <typename T> T *data(Vector<T> &); + +template <typename T> class optional { +public: + optional(); + optional(T); + const T &operator*() const { return m_value; } + T &operator*() { return m_value; } + const T *operator->() const { return &m_value; } + T *operator->() { return &m_value; } + +private: + T m_value; +}; } // namespace __1 } // namespace std diff --git a/clang/test/Analysis/Checkers/WebKit/unborrowed-call-args.cpp b/clang/test/Analysis/Checkers/WebKit/unborrowed-call-args.cpp index 53210272029e7a0..77227eb693b1d35 100644 --- a/clang/test/Analysis/Checkers/WebKit/unborrowed-call-args.cpp +++ b/clang/test/Analysis/Checkers/WebKit/unborrowed-call-args.cpp @@ -21,30 +21,30 @@ namespace arg_origins { void from_local() { Vector<char> vec; process(vec[0]); - // expected-warning@-1{{Function argument 'vec[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'vec[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } void from_parameter(Vector<char> &vec) { process(vec[0]); - // expected-warning@-1{{Function argument 'vec[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'vec[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } void from_global() { process(globalVector[0]); - // expected-warning@-1{{Function argument 'globalVector[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'globalVector[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } void from_static_local() { static Vector<char> cache; process(cache[0]); - // expected-warning@-1{{Function argument 'cache[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'cache[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } class Holder { public: void from_member() { process(m_vector[0]); - // expected-warning@-1{{Function argument 'this->m_vector[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'this->m_vector[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } private: @@ -55,21 +55,26 @@ void from_call_result() { process(makeVector()[0]); } +void from_const_local() { + const Vector<char> vec = makeVector(); + processConst(vec[0]); +} + void from_returned_reference() { process(getVectorRef()[0]); - // expected-warning@-1{{Function argument 'getVectorRef()[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'getVectorRef()[0]' (to 'process') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } void buffer_pointer() { Vector<char> vec; takePtr(vec.data()); - // expected-warning@-1{{Function argument 'vec.data()' (to 'takePtr') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'vec.data()' (to 'takePtr') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } void const_parameter() { Vector<char> vec; processConst(vec[0]); - // expected-warning@-1{{Function argument 'vec[0]' (to 'processConst') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'vec[0]' (to 'processConst') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } } // namespace arg_origins @@ -79,20 +84,20 @@ namespace implicit_object_arg { void mutating_method() { Vector<Element> vec; vec[0].mutate(); - // expected-warning@-1{{Function argument 'vec[0]' (parameter 'this' to 'Element::mutate') is a loan on CanBorrow type 'Vector<Element>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'vec[0]' (parameter 'this' to 'Element::mutate') is a loan on CanBorrow type 'Vector<Element>' that is not guarded by const or a Borrow}} } void const_method() { Vector<Element> vec; vec[0].inspect(); - // expected-warning@-1{{Function argument 'vec[0]' (parameter 'this' to 'Element::inspect') is a loan on CanBorrow type 'Vector<Element>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'vec[0]' (parameter 'this' to 'Element::inspect') is a loan on CanBorrow type 'Vector<Element>' that is not guarded by const or a Borrow}} } class Holder { public: void from_member() { m_elements[0].mutate(); - // expected-warning@-1{{Function argument 'this->m_elements[0]' (parameter 'this' to 'Element::mutate') is a loan on CanBorrow type 'Vector<Element>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'this->m_elements[0]' (parameter 'this' to 'Element::mutate') is a loan on CanBorrow type 'Vector<Element>' that is not guarded by const or a Borrow}} } private: @@ -102,7 +107,7 @@ class Holder { void nested_container() { Vector<Vector<char>> outer; outer[0].append('x'); - // expected-warning@-1{{Function argument 'outer[0]' (parameter 'this' to 'Vector<char>::append') is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'outer[0]' (parameter 'this' to 'Vector<char>::append') is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by const or a Borrow}} } } // namespace implicit_object_arg @@ -173,15 +178,15 @@ namespace nested_calls { void annotated_intermediate() { Vector<char> vec; takeView(makeView(vec.data())); - // expected-warning@-1{{Function argument 'makeView(vec.data())' (to 'takeView') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} - // expected-warning@-2{{Function argument 'vec.data()' (parameter 'data' to 'makeView') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'makeView(vec.data())' (to 'takeView') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} + // expected-warning@-2{{Function argument 'vec.data()' (parameter 'data' to 'makeView') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } void two_loans_one_call() { Vector<char> vec; pick(vec.data(), vec.data()); - // expected-warning@-1{{Function argument 'vec.data()' (parameter 'a' to 'pick') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} - // expected-warning@-2{{Function argument 'vec.data()' (parameter 'b' to 'pick') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Function argument 'vec.data()' (parameter 'a' to 'pick') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} + // expected-warning@-2{{Function argument 'vec.data()' (parameter 'b' to 'pick') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } } // namespace nested_calls @@ -191,7 +196,7 @@ namespace known_gaps { void unannotated_intermediate() { Vector<char> vec; takeSpan(makeSpanUnannotated(vec)); - // expected-warning@-1{{Function argument 'makeSpanUnannotated(vec)' (to 'takeSpan') is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedCallArgsChecker]}} + // expected-warning@-1{{Function argument 'makeSpanUnannotated(vec)' (to 'takeSpan') is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedCallArgsChecker]}} } inline void trivialSink(char &c) {} diff --git a/clang/test/Analysis/Checkers/WebKit/unborrowed-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/unborrowed-lambda-captures.cpp index 25e37ac155461bd..c4556b927f248e1 100644 --- a/clang/test/Analysis/Checkers/WebKit/unborrowed-lambda-captures.cpp +++ b/clang/test/Analysis/Checkers/WebKit/unborrowed-lambda-captures.cpp @@ -10,26 +10,49 @@ namespace loan_shapes { void init_capture_computing_a_loan() { Vector<char> vec; callEscaping([q = vec.data()] { someFunction(); }); - // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} } void reference_to_an_element() { Vector<char> vec; callEscaping([&c = vec[0]] { someFunction(); }); - // expected-warning@-1{{Captured variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + // expected-warning@-1{{Captured variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} } void loan_on_a_parameter(Vector<char> ¶meter) { callEscaping([q = parameter.data()] { someFunction(); }); - // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} } void loan_on_a_nested_container() { Vector<Vector<char>> outer; callEscaping([&inner = outer[0]] { someFunction(); }); - // expected-warning@-1{{Captured variable 'inner' is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + // expected-warning@-1{{Captured variable 'inner' is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} } +void loan_on_a_const_local() { + const Vector<char> vec; + callEscaping([q = vec.data()] { someFunction(); }); + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} +} + +void loan_through_a_const_local_wrapper() { + const std::optional<Vector<char>> opt; + callEscaping([q = opt->data()] { someFunction(); }); + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} +} + +class ConstMemberHolder { +public: + void loan_on_a_const_member() { + callEscaping([q = m_vec.data()] { someFunction(); }); + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + } + +private: + const Vector<char> m_vec; +}; + } // namespace loan_shapes namespace borrow_does_not_travel { @@ -38,20 +61,20 @@ void loan_through_a_borrow() { Vector<char> vec; Borrow<Vector<char>> b(vec); callEscaping([q = b.get().data()] { someFunction(); }); - // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} } void element_through_a_borrow() { Vector<char> vec; Borrow<Vector<char>> b(vec); callEscaping([&c = b.get()[0]] { someFunction(); }); - // expected-warning@-1{{Captured variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + // expected-warning@-1{{Captured variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} } void loan_through_a_borrow_temporary() { Vector<char> vec; callEscaping([q = borrow(vec).get().data()] { someFunction(); }); - // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLambdaCapturesChecker]}} } void capture_of_the_borrow_by_reference() { @@ -165,7 +188,7 @@ void alongside_a_loan(unsigned n) { Vector<char> vec; typedef char VLA[n]; callEscaping([q = vec.data()] { someFunction(); use(q); (void)sizeof(VLA); }); - // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow}} + // expected-warning@-1{{Captured variable 'q' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow}} } void alone(unsigned n) { diff --git a/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars-cxx23.cpp b/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars-cxx23.cpp index 3fc233b0c0abbeb..c0abba3c4a54e94 100644 --- a/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars-cxx23.cpp +++ b/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars-cxx23.cpp @@ -29,7 +29,7 @@ ReversedChars operator|(ReversedChars &&, const ReverseAdaptor &); void unguarded_global_adaptor_pipe_loop(Vector<char> &vec) { for (char &c : vec | reversed) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -44,7 +44,7 @@ void borrowed_global_adaptor_pipe_loop(Vector<char> &vec) { void chained_pipe_unguarded(Vector<char> &vec) { ReversedChars rv = vec | reversed | reversed; - // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)rv; } @@ -58,7 +58,7 @@ void chained_pipe_borrowed(Vector<char> &vec) { void unguarded_pipe_loop(Vector<char> &vec) { for (char &c : vec | ReverseAdaptor()) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -73,7 +73,7 @@ void borrow_get_pipe_loop(Vector<char> &vec) { void named_view(Vector<char> &vec) { ReversedChars rv = vec | ReverseAdaptor(); - // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)rv; } @@ -87,7 +87,7 @@ void named_view_borrowed(Vector<char> &vec) { void constructed_view(Vector<char> &vec) { ReversedChars rv(vec); - // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)rv; } @@ -100,7 +100,7 @@ struct PlainReversed : std::ranges::view_interface<PlainReversed> { void std_reverse_iterator_loop(Vector<char> &vec) { for (char &c : PlainReversed(vec)) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -116,7 +116,7 @@ void std_reverse_iterator_borrowed(Vector<char> &vec) { void data_from_vector(Vector<char> &vec) { char *p = std::data(vec); - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)p; } @@ -130,7 +130,7 @@ void data_from_borrow(Vector<char> &vec) { void get_from_element(Vector<std::pair<int, int>> &vec) { auto &first = std::get<0>(vec[0]); - // expected-warning@-1{{Local variable 'first' is a loan on CanBorrow type 'Vector<std::pair<int, int>>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'first' is a loan on CanBorrow type 'Vector<std::pair<int, int>>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)first; } @@ -156,7 +156,7 @@ void trusted_annotations(Vector<char> &tracked, Vector<char> &untracked) { void member_arg_unguarded(Vector<char> &vec, Vector<int> &ints) { Borrow<Vector<char>> b(vec); ReversedChars rv = (b.get() | reversed).zipWith(ints); - // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<int>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<int>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)rv; } @@ -164,7 +164,7 @@ void member_arg_unguarded(Vector<char> &vec, Vector<int> &ints) { void member_object_unguarded(Vector<char> &vec, Vector<int> &ints) { Borrow<Vector<int>> b(ints); ReversedChars rv = (vec | reversed).zipWith(b.get()); - // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'rv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)rv; } @@ -194,7 +194,7 @@ inline constexpr ZipAdaptor zip{}; void zip_unguarded(Vector<char> &vec, Vector<int> &ints) { for (char &c : zip(vec, ints)) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -203,7 +203,7 @@ void zip_unguarded(Vector<char> &vec, Vector<int> &ints) { void zip_first_borrowed(Vector<char> &vec, Vector<int> &ints) { Borrow<Vector<char>> b(vec); for (char &c : zip(b.get(), ints)) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<int>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<int>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -212,7 +212,7 @@ void zip_first_borrowed(Vector<char> &vec, Vector<int> &ints) { void zip_second_borrowed(Vector<char> &vec, Vector<int> &ints) { Borrow<Vector<int>> b(ints); for (char &c : zip(vec, b.get())) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -230,7 +230,7 @@ void zip_both_borrowed(Vector<char> &vec, Vector<int> &ints) { void zip_constructed_second_borrowed(Vector<char> &vec, Vector<int> &ints) { Borrow<Vector<int>> b(ints); ZipView z(vec, b.get()); - // expected-warning@-1{{Local variable 'z' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'z' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)z; } @@ -261,7 +261,7 @@ void non_std_pipe_loop(Vector<char> &vec) { void reference_loop(Vector<char> &vec) { for (char &c : vec) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } diff --git a/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars.cpp b/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars.cpp index 7f21b68ab943a55..db2c63c641f33c3 100644 --- a/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars.cpp +++ b/clang/test/Analysis/Checkers/WebKit/unborrowed-local-vars.cpp @@ -12,37 +12,37 @@ Vector<char> &getVectorRef(); namespace loan_shapes { void reference_loan(Vector<char> &vec) { char &c = vec[0]; - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void pointer_loan(Vector<char> &vec) { char *p = vec.data(); - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void view_loan(Vector<char> &vec) { StringView sv = vec.data(); - // expected-warning@-1{{Local variable 'sv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'sv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void gsl_pointer_loan(Vector<char> &vec) { CharSpan s = makeSpan(vec); - // expected-warning@-1{{Local variable 's' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 's' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void simple_container(SimpleContainer<char> &container) { char &c = container[0]; - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'SimpleContainer<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'SimpleContainer<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void two_hops(Vector<char> &vec) { StringView sv = makeView(vec.data()); - // expected-warning@-1{{Local variable 'sv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'sv' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } } // namespace loan_shapes @@ -100,19 +100,19 @@ void no_initializer() { namespace lifetimebound_edge { void forwarded_reference(Vector<char> &someVec) { Vector<char> &a = forwardRef(someVec); - // expected-warning@-1{{Local variable 'a' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'a' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void forwarded_pointer(Vector<char> &someVec) { Vector<char> *a = forwardPtr(someVec); - // expected-warning@-1{{Local variable 'a' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'a' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void self_similar_container(Node &node) { Node &child = node.firstChild(); - // expected-warning@-1{{Local variable 'child' is a loan on CanBorrow type 'Node' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'child' is a loan on CanBorrow type 'Node' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} node.appendChild(); (void)child; } @@ -173,27 +173,27 @@ void borrow_in_enclosing_scope(Vector<char> &vec) { Borrow<Vector<char>> b(vec); { char &c = vec[0]; - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } } void const_reference_parameter(const Vector<char> &vec) { const char &c = vec[0]; - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void const_pointer_parameter(const Vector<char> *vec) { const char *p = vec->data(); - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void local_container() { Vector<char> vec; char &c = vec[0]; - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); vec.append('x'); } @@ -202,7 +202,7 @@ void local_container() { namespace nested_containers { void loan_on_outer(Vector<Vector<char>> &outer) { Vector<char> &inner = outer[0]; - // expected-warning@-1{{Local variable 'inner' is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'inner' is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } @@ -232,7 +232,7 @@ void alias_on_outer(Vector<Vector<char>> &outer) { namespace assignment_sink { void assign_loan(Vector<char> &vec) { char *p = nullptr; - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} p = vec.data(); someFunction(); } @@ -256,7 +256,7 @@ namespace conditional_origin { void one_unguarded_arm(Vector<char> &vec, bool flag) { Borrow<Vector<char>> b(vec); char *p = flag ? b.get().data() : vec.data(); - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } @@ -272,7 +272,7 @@ void both_arms_guarded(Vector<char> &vec, Vector<char> &other, bool flag) { namespace forked_trace { void call_one_unguarded(Vector<char> &vec, Borrow<Vector<char>> &b) { const char *p = pick(b.get().data(), vec.data()); - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } @@ -284,7 +284,7 @@ void call_both_guarded(Borrow<Vector<char>> &b, Borrow<Vector<char>> &c) { void construct_one_unguarded(Vector<char> &vec, Borrow<Vector<char>> &b) { TwoStringViews v(b.get().data(), vec.data()); - // expected-warning@-1{{Local variable 'v' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'v' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } @@ -298,13 +298,13 @@ void construct_both_guarded(Borrow<Vector<char>> &b, Borrow<Vector<char>> &c) { namespace escape_paths { void out_parameter_by_reference(Vector<char> &vec, char *&out) { out = vec.data(); - // expected-warning@-1{{Parameter 'out' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Parameter 'out' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void outer_scope_local(Vector<char> &vec) { char *p = nullptr; - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} { p = vec.data(); someFunction(); @@ -326,14 +326,14 @@ void borrow_outlives_assignment(Vector<char> &vec) { void store_through_out_pointer(Vector<char> &vec, char **out) { *out = vec.data(); - // expected-warning@-1{{Parameter 'out' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Parameter 'out' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void store_through_local_pointer(Vector<char> &vec) { char *p = nullptr; char **pp = &p; - // expected-warning@-1{{Local variable 'pp' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'pp' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} *pp = vec.data(); someFunction(); (void)p; @@ -341,13 +341,13 @@ void store_through_local_pointer(Vector<char> &vec) { void store_into_pointer_array(Vector<char> &vec, char *arr[]) { arr[0] = vec.data(); - // expected-warning@-1{{Parameter 'arr' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Parameter 'arr' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } void store_through_double_indirection(Vector<char> &vec, char ***out) { **out = vec.data(); - // expected-warning@-1{{Parameter 'out' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Parameter 'out' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } @@ -391,7 +391,7 @@ void owning_temporary_from_borrow(Vector<char> &vec) { void owning_temporary_from_unguarded(Vector<char> &vec) { char *p = makeOwningBuffer(vec).data(); - // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} // expected-warning@-2{{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}} someFunction(); (void)p; @@ -399,7 +399,7 @@ void owning_temporary_from_unguarded(Vector<char> &vec) { void extended_owning_from_unguarded(Vector<char> &vec) { const OwningBuffer &buf = makeOwningBuffer(vec); - // expected-warning@-1{{Local variable 'buf' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'buf' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)buf; } @@ -414,14 +414,14 @@ void extended_owning_from_borrow(Vector<char> &vec) { namespace known_gaps { void unannotated_view_constructor(Vector<char> &vec) { CharSpan s(vec.data()); - // expected-warning@-1{{Local variable 's' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 's' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)s; } void unannotated_function_parameter(Vector<char> &vec) { CharSpan s = makeSpanUnannotated(vec); - // expected-warning@-1{{Local variable 's' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 's' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)s; } @@ -452,7 +452,7 @@ void borrow_escapes_via_out_pointer(Vector<char> &vec, char **out) { namespace range_for { void reference_loop(Vector<char> &vec) { for (char &c : vec) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -460,7 +460,7 @@ void reference_loop(Vector<char> &vec) { void auto_reference_loop(Vector<char> &vec) { for (auto &c : vec) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -468,7 +468,7 @@ void auto_reference_loop(Vector<char> &vec) { void const_reference_loop(const Vector<char> &vec) { for (const char &c : vec) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -476,7 +476,7 @@ void const_reference_loop(const Vector<char> &vec) { void nested_loop(Vector<Vector<char>> &outer) { for (Vector<char> &inner : outer) { - // expected-warning@-1{{Local variable 'inner' is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'inner' is a loan on CanBorrow type 'Vector<Vector<char>>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)inner; } @@ -485,7 +485,7 @@ void nested_loop(Vector<Vector<char>> &outer) { void local_container_loop() { Vector<char> vec; for (char &c : vec) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -531,7 +531,7 @@ void temporary_range_loop() { void named_temporary_loop() { Vector<char> &&r = makeVector(); for (char &c : r) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -539,7 +539,7 @@ void named_temporary_loop() { void returned_pointer_loop() { for (char &c : *getVectorPtr()) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -547,7 +547,7 @@ void returned_pointer_loop() { void returned_reference_loop() { for (char &c : getVectorRef()) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -555,7 +555,7 @@ void returned_reference_loop() { void manual_iterator_loop(Vector<char> &vec) { for (char *it = vec.begin(); it != vec.end(); ++it) { - // expected-warning@-1{{Local variable 'it' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'it' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)*it; } @@ -563,7 +563,7 @@ void manual_iterator_loop(Vector<char> &vec) { void copy_into_local(Vector<char> &vec) { char *first = vec.data(); - // expected-warning@-1{{Local variable 'first' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'first' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} char *second = first; someFunction(); (void)second; @@ -579,8 +579,8 @@ PointerPair getPair(Vector<char> &vec LIFETIME_BOUND); void from_lifetimebound_call(Vector<char> &vec) { auto [a, b] = getPair(vec); - // expected-warning@-1{{Local variable 'a' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} - // expected-warning@-2{{Local variable 'b' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'a' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-2{{Local variable 'b' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } @@ -596,7 +596,7 @@ void per_element_sources(Vector<char> &vec, Vector<char> &other) { Borrow<Vector<char>> b(other); PointerPair p{b.get().data(), vec.data()}; auto [guarded, unguarded] = PointerPair{b.get().data(), vec.data()}; - // expected-warning@-1{{Local variable 'unguarded' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'unguarded' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)p; (void)guarded; @@ -608,7 +608,7 @@ void non_view_binding(Vector<char> &vec) { char *data; }; auto [size, data] = SizeAndData{vec.size(), vec.data()}; - // expected-warning@-1{{Local variable 'data' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'data' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)size; } @@ -622,7 +622,7 @@ void use(char); void interior_destroyed_through_cursor() { for (Cursor<char> c : makeRegistry()) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Registry<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Registry<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} char &name = c.value(); c.remove(); use(name); @@ -631,7 +631,7 @@ void interior_destroyed_through_cursor() { void interior_destroyed_named_container() { for (Cursor<char> c : namedRegistry()) { - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Registry<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Registry<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} char &name = c.value(); c.remove(); use(name); @@ -664,7 +664,7 @@ namespace dependent_initializers { template <typename T> void view_from_dependent_paren_init(T &source) { StringView view(source.data()); - // expected-warning@-1{{Local variable 'view' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'view' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); } @@ -689,7 +689,7 @@ unsigned indexFor(const Key &); void unrelated_temporary_is_still_a_loan(Vector<char> &vec) { char &c = vec[indexFor(makeKey())]; - // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-1{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -704,7 +704,7 @@ void unrelated_temporary_through_borrow(Vector<char> &vec) { void borrow_temporary_dies_with_the_statement(Vector<char> &vec) { char &c = borrow(vec).get()[0]; // expected-warning@-1{{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}} - // expected-warning@-2{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + // expected-warning@-2{{Local variable 'c' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} someFunction(); (void)c; } @@ -721,3 +721,98 @@ void loan_outliving_temporary() { } } // namespace prvalue_temporary + +namespace const_object { + +class Holder { +public: + void use_const_member() const { + const char *p = m_vector.data(); + someFunction(); + (void)p; + } + +private: + const Vector<char> m_vector; +}; + +void const_local() { + const Vector<char> vec = makeVector(); + const char *p = vec.data(); + someFunction(); + (void)p; +} + +void const_local_range_loop() { + const Vector<char> vec = makeVector(); + for (const char &c : vec) { + someFunction(); + (void)c; + } +} + +void const_value_parameter(const Vector<char> vec) { + const char *p = vec.data(); + someFunction(); + (void)p; +} + +void const_local_moved_from_builder() { + Vector<char> builder; + builder.append('x'); + const Vector<char> vec = static_cast<Vector<char> &&>(builder); + const char *p = vec.data(); + someFunction(); + (void)p; +} + +void const_pointer_to_mutable_container(const Vector<char> *const vec) { + const char *p = vec->data(); + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + someFunction(); + (void)p; +} + +std::optional<Vector<char>> makeOptionalVector(); + +template <typename T> class MutableThroughConst { +public: + T &operator*() const { return *m_ptr; } + T *operator->() const { return m_ptr; } + +private: + T *m_ptr { nullptr }; +}; + +void const_wrapper_propagates_const() { + const std::optional<Vector<char>> opt = makeOptionalVector(); + const char *p = opt->data(); + someFunction(); + (void)p; +} + +void const_wrapper_propagates_const_deref() { + const std::optional<Vector<char>> opt = makeOptionalVector(); + for (const char &c : *opt) { + someFunction(); + (void)c; + } +} + +void const_wrapper_does_not_propagate_const() { + const MutableThroughConst<Vector<char>> handle; + char *p = handle->data(); + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + someFunction(); + (void)p; +} + +void non_const_wrapper() { + std::optional<Vector<char>> opt = makeOptionalVector(); + const char *p = opt->data(); + // expected-warning@-1{{Local variable 'p' is a loan on CanBorrow type 'Vector<char>' that is not guarded by const or a Borrow [alpha.webkit.UnborrowedLocalVarsChecker]}} + someFunction(); + (void)p; +} + +} // namespace const_object _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
