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> &parameter) {
   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

Reply via email to