[clang] db3dced - [-Wunsafe-buffer-usage] Handle pointer initializations for grouping related variables

Rashmi Mudduluru via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 21 15:54:26 PDT 2023


Author: Rashmi Mudduluru
Date: 2023-06-21T15:54:09-07:00
New Revision: db3dcedb9cedcec4a9570fda7406490c642df8ae

URL: https://github.com/llvm/llvm-project/commit/db3dcedb9cedcec4a9570fda7406490c642df8ae
DIFF: https://github.com/llvm/llvm-project/commit/db3dcedb9cedcec4a9570fda7406490c642df8ae.diff

LOG: [-Wunsafe-buffer-usage] Handle pointer initializations for grouping related variables

Differential Revision: https://reviews.llvm.org/D150489

Added: 
    clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp
    clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp

Modified: 
    clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
    clang/lib/Analysis/UnsafeBufferUsage.cpp
    clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
    clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
    clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index 57d9dcc5bdcb7..ff687a0d178bd 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -37,6 +37,7 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified Poin
 FIXABLE_GADGET(UPCStandalonePointer)
 FIXABLE_GADGET(UPCPreIncrement)            // '++Ptr' in an Unspecified Pointer Context
 FIXABLE_GADGET(PointerAssignment)
+FIXABLE_GADGET(PointerInit)
 
 #undef FIXABLE_GADGET
 #undef WARNING_GADGET

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 49229a6b56c1c..aa29fb45726a8 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -533,23 +533,66 @@ class PointerArithmeticGadget : public WarningGadget {
   // FIXME: this gadge will need a fix-it
 };
 
+/// A pointer initialization expression of the form:
+///  \code
+///  int *p = q;
+///  \endcode
+class PointerInitGadget : public FixableGadget {
+private:
+  static constexpr const char *const PointerInitLHSTag = "ptrInitLHS";
+  static constexpr const char *const PointerInitRHSTag = "ptrInitRHS";
+  const VarDecl * PtrInitLHS;         // the LHS pointer expression in `PI`
+  const DeclRefExpr * PtrInitRHS;         // the RHS pointer expression in `PI`
+
+public:
+  PointerInitGadget(const MatchFinder::MatchResult &Result)
+      : FixableGadget(Kind::PointerInit),
+    PtrInitLHS(Result.Nodes.getNodeAs<VarDecl>(PointerInitLHSTag)),
+    PtrInitRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerInitRHSTag)) {}
+
+  static bool classof(const Gadget *G) {
+    return G->getKind() == Kind::PointerInit;
+  }
+
+  static Matcher matcher() {
+    auto PtrInitStmt = declStmt(hasSingleDecl(varDecl(
+                                 hasInitializer(ignoringImpCasts(declRefExpr(
+                                                  hasPointerType()).
+                                                  bind(PointerInitRHSTag)))).
+                                              bind(PointerInitLHSTag)));
+
+    return stmt(PtrInitStmt);
+  }
+
+  virtual std::optional<FixItList> getFixits(const Strategy &S) const override;
+
+  virtual const Stmt *getBaseStmt() const override { return nullptr; }
+
+  virtual DeclUseList getClaimedVarUseSites() const override {
+    return DeclUseList{PtrInitRHS};
+  }
+
+  virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
+  getStrategyImplications() const override {
+      return std::make_pair(PtrInitLHS,
+                            cast<VarDecl>(PtrInitRHS->getDecl()));
+  }
+};
+
 /// A pointer assignment expression of the form:
 ///  \code
 ///  p = q;
 ///  \endcode
 class PointerAssignmentGadget : public FixableGadget {
 private:
-  static constexpr const char *const PointerAssignmentTag = "ptrAssign";
   static constexpr const char *const PointerAssignLHSTag = "ptrLHS";
   static constexpr const char *const PointerAssignRHSTag = "ptrRHS";
-  const BinaryOperator *PA;    // pointer arithmetic expression
   const DeclRefExpr * PtrLHS;         // the LHS pointer expression in `PA`
   const DeclRefExpr * PtrRHS;         // the RHS pointer expression in `PA`
 
 public:
   PointerAssignmentGadget(const MatchFinder::MatchResult &Result)
       : FixableGadget(Kind::PointerAssignment),
-    PA(Result.Nodes.getNodeAs<BinaryOperator>(PointerAssignmentTag)),
     PtrLHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignLHSTag)),
     PtrRHS(Result.Nodes.getNodeAs<DeclRefExpr>(PointerAssignRHSTag)) {}
 
@@ -566,13 +609,12 @@ class PointerAssignmentGadget : public FixableGadget {
                                                       to(varDecl())).
                                           bind(PointerAssignLHSTag))));
     
-    //FIXME: Handle declarations at assignments
     return stmt(isInUnspecifiedUntypedContext(PtrAssignExpr));
   }
   
   virtual std::optional<FixItList> getFixits(const Strategy &S) const override;
 
-  virtual const Stmt *getBaseStmt() const override { return PA; }
+  virtual const Stmt *getBaseStmt() const override { return nullptr; }
 
   virtual DeclUseList getClaimedVarUseSites() const override {
     return DeclUseList{PtrLHS, PtrRHS};
@@ -769,8 +811,8 @@ class UPCAddressofArraySubscriptGadget : public FixableGadget {
 
 namespace {
 // An auxiliary tracking facility for the fixit analysis. It helps connect
-// declarations to its and make sure we've covered all uses with our analysis
-// before we try to fix the declaration.
+// declarations to its uses and make sure we've covered all uses with our
+// analysis before we try to fix the declaration.
 class DeclUseTracker {
   using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
   using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
@@ -1174,6 +1216,24 @@ PointerAssignmentGadget::getFixits(const Strategy &S) const {
   return std::nullopt;
 }
 
+std::optional<FixItList>
+PointerInitGadget::getFixits(const Strategy &S) const {
+  const auto *LeftVD = PtrInitLHS;
+  const auto *RightVD = cast<VarDecl>(PtrInitRHS->getDecl());
+  switch (S.lookup(LeftVD)) {
+    case Strategy::Kind::Span:
+      if (S.lookup(RightVD) == Strategy::Kind::Span)
+        return FixItList{};
+      return std::nullopt;
+    case Strategy::Kind::Wontfix:
+      return std::nullopt;
+    case Strategy::Kind::Iterator:
+    case Strategy::Kind::Array:
+    case Strategy::Kind::Vector:
+    llvm_unreachable("unsupported strategies for FixableGadgets");
+  }
+  return std::nullopt;
+}
 
 std::optional<FixItList>
 ULCArraySubscriptGadget::getFixits(const Strategy &S) const {
@@ -2020,10 +2080,10 @@ static bool overlapWithMacro(const FixItList &FixIts) {
   });
 }
 
-static bool impossibleToFixForVar(const FixableGadgetSets &FixablesForUnsafeVars,
+static bool impossibleToFixForVar(const FixableGadgetSets &FixablesForAllVars,
                                   const Strategy &S,
                                   const VarDecl * Var) {
-  for (const auto &F : FixablesForUnsafeVars.byVar.find(Var)->second) {
+  for (const auto &F : FixablesForAllVars.byVar.find(Var)->second) {
     std::optional<FixItList> Fixits = F->getFixits(S);
     if (!Fixits) {
       return true;
@@ -2033,13 +2093,13 @@ static bool impossibleToFixForVar(const FixableGadgetSets &FixablesForUnsafeVars
 }
 
 static std::map<const VarDecl *, FixItList>
-getFixIts(FixableGadgetSets &FixablesForUnsafeVars, const Strategy &S,
+getFixIts(FixableGadgetSets &FixablesForAllVars, const Strategy &S,
 	  ASTContext &Ctx,
           /* The function decl under analysis */ const Decl *D,
     const DeclUseTracker &Tracker, UnsafeBufferUsageHandler &Handler,
 	  const DefMapTy &VarGrpMap) {
   std::map<const VarDecl *, FixItList> FixItsForVariable;
-  for (const auto &[VD, Fixables] : FixablesForUnsafeVars.byVar) {
+  for (const auto &[VD, Fixables] : FixablesForAllVars.byVar) {
     FixItsForVariable[VD] =
         fixVariable(VD, S.lookup(VD), D, Tracker, Ctx, Handler);
     // If we fail to produce Fix-It for the declaration we have to skip the
@@ -2073,7 +2133,7 @@ getFixIts(FixableGadgetSets &FixablesForUnsafeVars, const Strategy &S,
         if (V == VD) {
           continue;
         }
-        if (impossibleToFixForVar(FixablesForUnsafeVars, S, V)) {
+        if (impossibleToFixForVar(FixablesForAllVars, S, V)) {
           ImpossibleToFix = true;
           break;
         }

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp
new file mode 100644
index 0000000000000..e29ac7fa8fcb3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// RUN:            -fsafe-buffer-usage-suggestions \
+// RUN:            -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+void lhs_span_multi_assign() {
+  int *a = new int[2];
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> a"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 2}"
+  int *b = a;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> b"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
+  int *c = b;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> c"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
+  int *d = c;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> d"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
+  int tmp = d[2];  // expected-note{{used in buffer access here}}
+}
+
+void rhs_span1() {
+  int *q = new int[12];
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 12}"
+  int *p = q;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
+  p[5] = 10;
+  int *r = q;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
+  r[10] = 5;  // expected-note{{used in buffer access here}}
+}
+
+void rhs_span2() {
+  int *q = new int[6];
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 6}"
+  int *p = q;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
+  p[5] = 10;  // expected-note{{used in buffer access here}}
+}
+
+void rhs_span3() {
+  int *q = new int[6];
+  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
+  p[5] = 10;  // expected-note{{used in buffer access here}}
+  int *r = q;
+}
+
+void test_grouping() {
+  int *z = new int[8];
+  int tmp;
+  int *y = new int[10];
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> y"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}"
+  tmp = y[5];
+
+  int *x = new int[10];
+  x = y;
+
+  int *w = z;
+}
+
+void test_crash() {
+  int *r = new int[8];
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 8}"
+  int *q = r;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:13}:", <# placeholder #>}"
+  int *p;
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:9}:"std::span<int> p"
+  p = q;
+  int tmp = p[9];  // expected-note{{used in buffer access here}}
+}

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp
new file mode 100644
index 0000000000000..2fec417aafa8c
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fsafe-buffer-usage-suggestions -verify %s
+
+void lhs_span_multi_assign() {
+  int *a = new int[2];
+  int *b = a;
+  int *c = b;
+  int *d = c;  // expected-warning{{'d' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'd' to 'std::span' to preserve bounds information, and change ('a', 'b', and 'c'|'a', 'c', and 'b'|'b', 'a', and 'c'|'b', 'c', and 'a'|'c', 'a', and 'b'|'c', 'b', and 'a') to 'std::span' to propagate bounds information between them$}}}}
+  int tmp = d[2];  // expected-note{{used in buffer access here}}
+}
+
+void rhs_span1() {
+  int *q = new int[12];
+  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information, and change ('q' and 'r'|'r' and 'q') to 'std::span' to propagate bounds information between them$}}}}
+  p[5] = 10;  // expected-note{{used in buffer access here}}
+  int *r = q;  // expected-warning{{'r' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'r' to 'std::span' to preserve bounds information, and change ('p' and 'q'|'q' and 'p') to 'std::span' to propagate bounds information between them$}}}}
+  r[10] = 5;  // expected-note{{used in buffer access here}}
+}
+
+void rhs_span2() {
+  int *q = new int[6];
+  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information, and change 'q' to 'std::span' to propagate bounds information between them$}}}}
+  p[5] = 10;  // expected-note{{used in buffer access here}}
+}
+
+// FIXME: Suggest fixits for p, q, and r since span a valid fixit for r.
+void rhs_span3() {
+  int *q = new int[6];
+  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
+  p[5] = 10;  // expected-note{{used in buffer access here}}
+  int *r = q;
+}
+
+void test_grouping() {
+  int *z = new int[8];
+  int tmp;
+  int *y = new int[10];  // expected-warning{{'y' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'y' to 'std::span' to preserve bounds information$}}}}
+  tmp = y[5]; // expected-note{{used in buffer access here}}
+
+  int *x = new int[10];
+  x = y;
+
+  int *w = z;
+}
+
+void test_crash() {
+  int *r = new int[8];
+  int *q = r;
+  int *p;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information, and change ('r' and 'q'|'q' and 'r') to 'std::span' to propagate bounds information between them$}}}}
+  p = q;
+  int tmp = p[9];  // expected-note{{used in buffer access here}}
+}

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
index 0c5716ba19478..6c867fe8a3204 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
@@ -48,6 +48,21 @@ void uuc_if_body1(bool flag) {
   p[5] = 4;
 }
 
+void uuc_if_body2_ptr_init(bool flag) {
+  int *r = new int[7];
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
+  // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 7}"
+  if (flag) {
+  } else {
+    int* p = r;
+    // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:5-[[@LINE-1]]:13}:"std::span<int> p"
+    // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:14-[[@LINE-2]]:14}:"{"
+    // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:15-[[@LINE-3]]:15}:", <# placeholder #>}"
+    p[5] = 4;
+  }
+}
+
 void uuc_if_cond_no_unsafe_op() {
   int *r = new int[7];
   int *p = new int[4];
@@ -58,32 +73,32 @@ void uuc_if_cond_no_unsafe_op() {
 
 void uuc_if_cond_unsafe_op() {
   int *r = new int[7];
-  int *p = new int[4];  //expected-warning{{'p' is an unsafe pointer used for buffer access}}
+  int *p = new int[4];
   if ((p = r)) {
-    p[3] = 2;  // expected-note{{used in buffer access here}}
+    p[3] = 2;
   }
 }
 
 void uuc_if_cond_unsafe_op1() {
-  int *r = new int[7];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
+  int *r = new int[7];
   int *p = new int[4];
   if ((p = r)) {
-    r[3] = 2;  // expected-note{{used in buffer access here}}
+    r[3] = 2;
   }
 }
 
 void uuc_if_cond_unsafe_op2() {
-  int *r = new int[7];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  int *p = new int[4];  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
+  int *r = new int[7];
+  int *p = new int[4];
   if ((p = r)) {
-    r[3] = 2;  // expected-note{{used in buffer access here}}
+    r[3] = 2;
   }
-  p[4] = 6;  // expected-note{{used in buffer access here}}
+  p[4] = 6;
 }
 
 void uuc_call1() {
-  int *w = new int[4];  // expected-warning{{'w' is an unsafe pointer used for buffer access}}
+  int *w = new int[4];
   int *y = new int[4];
   bar(w = y);
-  w[5] = 0;  // expected-note{{used in buffer access here}}
+  w[5] = 0;
 }

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
index 2b37442cbd84b..d5a3f121c19ea 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
@@ -38,6 +38,15 @@ void uuc_if_body2(bool flag) {
   p[5] = 4;  // expected-note{{used in buffer access here}}
 }
 
+void uuc_if_body2_ptr_init(bool flag) {
+  int *r = new int[7];
+  if (flag) {
+  } else {
+    int* p = r;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} // expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information, and change 'r' to 'std::span' to propagate bounds information between them$}}}}
+    p[5] = 4;  // expected-note{{used in buffer access here}}
+  }
+}
+
 void uuc_if_cond_no_unsafe_op() {
   int *r = new int[7];
   int *p = new int[4];

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
index d2aa57997e6d4..a60e7310c99a6 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
@@ -39,13 +39,11 @@ void local_assign_lhs_span() {
   p = q;
 }
 
-
-// FIXME: Support initializations at declarations.
 void lhs_span_multi_assign() {
   int *a = new int[2];
   int *b = a;
   int *c = b;
-  int *d = c;  // expected-warning{{'d' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'd' to 'std::span' to preserve bounds information$}}}}
+  int *d = c;  // expected-warning{{'d' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'd' to 'std::span' to preserve bounds information, and change ('a', 'b', and 'c'|'a', 'c', and 'b'|'b', 'a', and 'c'|'b', 'c', and 'a'|'c', 'a', and 'b'|'c', 'b', and 'a') to 'std::span' to propagate bounds information between them$}}}}
   int tmp = d[2];  // expected-note{{used in buffer access here}}
 }
 
@@ -59,15 +57,15 @@ void rhs_span() {
 
 void rhs_span1() {
   int *q = new int[12];
-  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information$}}}}
+  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information, and change ('q' and 'r'|'r' and 'q') to 'std::span' to propagate bounds information between them$}}}}
   p[5] = 10;  // expected-note{{used in buffer access here}}
-  int *r = q;  // expected-warning{{'r' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'r' to 'std::span' to preserve bounds information$}}}}
+  int *r = q;  // expected-warning{{'r' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'r' to 'std::span' to preserve bounds information, and change ('p' and 'q'|'q' and 'p') to 'std::span' to propagate bounds information between them$}}}}
   r[10] = 5;  // expected-note{{used in buffer access here}}
 }
 
 void rhs_span2() {
   int *q = new int[6];
-  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information$}}}}
+  int *p = q;  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
   p[5] = 10;  // expected-note{{used in buffer access here}}
   int *r = q;
 }
@@ -175,7 +173,7 @@ void foo3b() {
 void test_crash() {
   int *r = new int[8];
   int *q = r;
-  int *p;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information, and change 'q' to 'std::span' to propagate bounds information between them$}}}}
+  int *p;  // expected-warning{{'p' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'p' to 'std::span' to preserve bounds information, and change ('r' and 'q'|'q' and 'r') to 'std::span' to propagate bounds information between them$}}}}
   p = q;
   int tmp = p[9];  // expected-note{{used in buffer access here}}
 }


        


More information about the cfe-commits mailing list