[clang] 2e6325c - Revert "[-Wunsafe-buffer-usage] Group variables associated by pointer assignments"

Douglas Yung via cfe-commits cfe-commits at lists.llvm.org
Thu May 25 02:10:44 PDT 2023


Author: Douglas Yung
Date: 2023-05-25T02:10:32-07:00
New Revision: 2e6325c71feb5ab45ef3dbf4362db38602288a4e

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

LOG: Revert "[-Wunsafe-buffer-usage] Group variables associated by pointer assignments"

This reverts commit ee6b08e99375fc48d1e5848704a66c2e8e57eb3b.

One of the added tests warn-unsafe-buffer-usage-multi-decl-warnings.cpp does
not seem to be deterministic, and seems to be especially problematic on Windows.

Failures of this one test on llvm-clang-x86_64-sie-win:
- https://lab.llvm.org/buildbot/#/builders/216/builds/21758
- https://lab.llvm.org/buildbot/#/builders/216/builds/21761
- https://lab.llvm.org/buildbot/#/builders/216/builds/21762
- https://lab.llvm.org/buildbot/#/builders/216/builds/21765
- https://lab.llvm.org/buildbot/#/builders/216/builds/21770
- https://lab.llvm.org/buildbot/#/builders/216/builds/21771
- https://lab.llvm.org/buildbot/#/builders/216/builds/21773
- https://lab.llvm.org/buildbot/#/builders/216/builds/21776
- https://lab.llvm.org/buildbot/#/builders/216/builds/21777
- https://lab.llvm.org/buildbot/#/builders/216/builds/21778
- https://lab.llvm.org/buildbot/#/builders/216/builds/21779

Other random bot failures:
- https://lab.llvm.org/buildbot/#/builders/65/builds/9821
- https://lab.llvm.org/buildbot/#/builders/65/builds/9822
- https://lab.llvm.org/buildbot/#/builders/65/builds/9824
- https://lab.llvm.org/buildbot/#/builders/119/builds/13440
- https://lab.llvm.org/buildbot/#/builders/119/builds/13442
- https://lab.llvm.org/buildbot/#/builders/119/builds/13444
- https://lab.llvm.org/buildbot/#/builders/119/builds/13445
- https://lab.llvm.org/buildbot/#/builders/60/builds/12156
- https://lab.llvm.org/buildbot/#/builders/60/builds/12157
- https://lab.llvm.org/buildbot/#/builders/60/builds/12160

Added: 
    

Modified: 
    clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
    clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Analysis/UnsafeBufferUsage.cpp
    clang/lib/Sema/AnalysisBasedWarnings.cpp

Removed: 
    clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.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


################################################################################
diff  --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index 617bc7c77c565..10635e8f3a29f 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -19,8 +19,6 @@
 
 namespace clang {
 
-using DefMapTy = llvm::DenseMap<const VarDecl *, std::vector<const VarDecl *>>;
-
 /// The interface that lets the caller handle unsafe buffer usage analysis
 /// results by overriding this class's handle... methods.
 class UnsafeBufferUsageHandler {
@@ -36,12 +34,9 @@ class UnsafeBufferUsageHandler {
   virtual void handleUnsafeOperation(const Stmt *Operation,
                                      bool IsRelatedToDecl) = 0;
 
-  /// Invoked when a fix is suggested against a variable. This function groups
-  /// all variables that must be fixed together (i.e their types must be changed to the
-  /// same target type to prevent type mismatches) into a single fixit.
-  virtual void handleUnsafeVariableGroup(const VarDecl *Variable,
-                                         const DefMapTy &VarGrpMap,
-                                         FixItList &&Fixes) = 0;
+  /// Invoked when a fix is suggested against a variable.
+  virtual void handleFixableVariable(const VarDecl *Variable,
+                                     FixItList &&List) = 0;
 
   /// Returns a reference to the `Preprocessor`:
   virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0;

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

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a777d43f1468f..f203ac6c2a84e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11822,8 +11822,8 @@ def warn_unsafe_buffer_operation : Warning<
   InGroup<UnsafeBufferUsage>, DefaultIgnore;
 def note_unsafe_buffer_operation : Note<
   "used%select{| in pointer arithmetic| in buffer access}0 here">;
-def note_unsafe_buffer_variable_fixit_group : Note<
-  "change type of %0 to '%select{std::span|std::array|std::span::iterator}1' to preserve bounds information%select{|, and change %2 to '%select{std::span|std::array|std::span::iterator}1' to propagate bounds information between them}3">;
+def note_unsafe_buffer_variable_fixit : Note<
+  "change type of '%0' to '%select{std::span|std::array|std::span::iterator}1' to preserve bounds information">;
 def note_safe_buffer_usage_suggestions_disabled : Note<
   "pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions">;
 def err_loongarch_builtin_requires_la32 : Error<

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index c9cc4ccbfb5d5..87e3ec90dbf2f 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -16,7 +16,6 @@
 #include <memory>
 #include <optional>
 #include <sstream>
-#include <queue>
 
 using namespace llvm;
 using namespace clang;
@@ -257,29 +256,6 @@ isInUnspecifiedPointerContext(internal::Matcher<Stmt> InnerMatcher) {
   // FIXME: any more cases? (UPC excludes the RHS of an assignment.  For now we
   // don't have to check that.)
 }
-
-// Returns a matcher that matches any expression 'e' such that `innerMatcher`
-// matches 'e' and 'e' is in an unspecified untyped context (i.e the expression
-// 'e' isn't evaluated to an RValue). For example, consider the following code:
-//    int *p = new int[4];
-//    int *q = new int[4];
-//    if ((p = q)) {}
-//    p = q;
-// The expression `p = q` in the conditional of the `if` statement
-// `if ((p = q))` is evaluated as an RValue, whereas the expression `p = q;`
-// in the assignment statement is in an untyped context.
-static internal::Matcher<Stmt>
-isInUnspecifiedUntypedContext(internal::Matcher<Stmt> InnerMatcher) {
-  // An unspecified context can be
-  // 1. A compound statement,
-  // 2. The body of an if statement
-  // 3. Body of a loop
-  auto CompStmt = compoundStmt(forEach(InnerMatcher));
-  auto IfStmtThen = ifStmt(hasThen(InnerMatcher));
-  auto IfStmtElse = ifStmt(hasElse(InnerMatcher));
-  // FIXME: Handle loop bodies.
-  return stmt(anyOf(CompStmt, IfStmtThen, IfStmtElse));
-}
 } // namespace clang::ast_matchers
 
 namespace {
@@ -361,16 +337,6 @@ class FixableGadget : public Gadget {
   virtual std::optional<FixItList> getFixits(const Strategy &) const {
     return std::nullopt;
   }
-  
-  /// Returns a list of two elements where the first element is the LHS of a pointer assignment
-  /// statement and the second element is the RHS. This two-element list represents the fact that
-  /// the LHS buffer gets its bounds information from the RHS buffer. This information will be used
-  /// later to group all those variables whose types must be modified together to prevent type
-  /// mismatches.
-  virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
-  getStrategyImplications() const {
-    return std::nullopt;
-  }
 };
 
 using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
@@ -533,58 +499,6 @@ class PointerArithmeticGadget : public WarningGadget {
   // FIXME: this gadge will need a fix-it
 };
 
-/// 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)) {}
-
-  static bool classof(const Gadget *G) {
-    return G->getKind() == Kind::PointerAssignment;
-  }
-
-  static Matcher matcher() {
-    auto PtrAssignExpr = binaryOperator(allOf(hasOperatorName("="),
-      hasRHS(ignoringParenImpCasts(declRefExpr(hasPointerType(),
-                                               to(varDecl())).
-                                   bind(PointerAssignRHSTag))),
-                                   hasLHS(declRefExpr(hasPointerType(),
-                                                      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 DeclUseList getClaimedVarUseSites() const override {
-    return DeclUseList{PtrLHS, PtrRHS};
-  }
-
-  virtual std::optional<std::pair<const VarDecl *, const VarDecl *>>
-  getStrategyImplications() const override {
-    return std::make_pair(cast<VarDecl>(PtrLHS->getDecl()),
-                          cast<VarDecl>(PtrRHS->getDecl()));
-  }
-};
-
 /// A call of a function or method that performs unchecked buffer operations
 /// over one of its pointer parameters.
 class UnsafeBufferUsageAttrGadget : public WarningGadget {
@@ -1072,17 +986,17 @@ template <typename NodeTy> struct CompareNode {
 };
 
 struct WarningGadgetSets {
-  std::map<const VarDecl *, std::set<const WarningGadget *>,
+  std::map<const VarDecl *, std::set<std::unique_ptr<WarningGadget>>,
            // To keep keys sorted by their locations in the map so that the
            // order is deterministic:
            CompareNode<VarDecl>>
       byVar;
   // These Gadgets are not related to pointer variables (e. g. temporaries).
-  llvm::SmallVector<const WarningGadget *, 16> noVar;
+  llvm::SmallVector<std::unique_ptr<WarningGadget>, 16> noVar;
 };
 
 static WarningGadgetSets
-groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations) {
+groupWarningGadgetsByVar(WarningGadgetList &&AllUnsafeOperations) {
   WarningGadgetSets result;
   // If some gadgets cover more than one
   // variable, they'll appear more than once in the map.
@@ -1092,13 +1006,13 @@ groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations) {
     bool AssociatedWithVarDecl = false;
     for (const DeclRefExpr *DRE : ClaimedVarUseSites) {
       if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
-        result.byVar[VD].insert(G.get());
+        result.byVar[VD].emplace(std::move(G));
         AssociatedWithVarDecl = true;
       }
     }
 
     if (!AssociatedWithVarDecl) {
-      result.noVar.push_back(G.get());
+      result.noVar.emplace_back(std::move(G));
       continue;
     }
   }
@@ -1106,7 +1020,7 @@ groupWarningGadgetsByVar(const WarningGadgetList &AllUnsafeOperations) {
 }
 
 struct FixableGadgetSets {
-  std::map<const VarDecl *, std::set<const FixableGadget *>> byVar;
+  std::map<const VarDecl *, std::set<std::unique_ptr<FixableGadget>>> byVar;
 };
 
 static FixableGadgetSets
@@ -1117,7 +1031,7 @@ groupFixablesByVar(FixableGadgetList &&AllFixableOperations) {
 
     for (const DeclRefExpr *DRE : DREs) {
       if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
-        FixablesForUnsafeVars.byVar[VD].insert(F.get());
+        FixablesForUnsafeVars.byVar[VD].emplace(std::move(F));
       }
     }
   }
@@ -1155,26 +1069,6 @@ bool clang::internal::anyConflict(const SmallVectorImpl<FixItHint> &FixIts,
   return false;
 }
 
-std::optional<FixItList>
-PointerAssignmentGadget::getFixits(const Strategy &S) const {
-  const auto *LeftVD = cast<VarDecl>(PtrLHS->getDecl());
-  const auto *RightVD = cast<VarDecl>(PtrRHS->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 {
   if (const auto *DRE =
@@ -1662,28 +1556,14 @@ static bool overlapWithMacro(const FixItList &FixIts) {
   });
 }
 
-static bool impossibleToFixForVar(const FixableGadgetSets &FixablesForUnsafeVars,
-                                  const Strategy &S,
-                                  const VarDecl * Var) {
-  for (const auto &F : FixablesForUnsafeVars.byVar.find(Var)->second) {
-    std::optional<FixItList> Fixits = F->getFixits(S);
-    if (!Fixits) {
-      return true;
-    }
-  }
-  return false;
-}
-
 static std::map<const VarDecl *, FixItList>
 getFixIts(FixableGadgetSets &FixablesForUnsafeVars, const Strategy &S,
-        const DeclUseTracker &Tracker, const ASTContext &Ctx,
-        UnsafeBufferUsageHandler &Handler,
-        const DefMapTy &VarGrpMap) {
+          const DeclUseTracker &Tracker, const ASTContext &Ctx,
+          UnsafeBufferUsageHandler &Handler) {
   std::map<const VarDecl *, FixItList> FixItsForVariable;
   for (const auto &[VD, Fixables] : FixablesForUnsafeVars.byVar) {
-    const Strategy::Kind ReplacementTypeForVD = S.lookup(VD);
     FixItsForVariable[VD] =
-        fixVariable(VD, ReplacementTypeForVD, Tracker, Ctx, Handler);
+        fixVariable(VD, S.lookup(VD), Tracker, Ctx, Handler);
     // If we fail to produce Fix-It for the declaration we have to skip the
     // variable entirely.
     if (FixItsForVariable[VD].empty()) {
@@ -1703,71 +1583,23 @@ getFixIts(FixableGadgetSets &FixablesForUnsafeVars, const Strategy &S,
                            CorrectFixes.end());
       }
     }
-
-    if (ImpossibleToFix) {
+    if (ImpossibleToFix)
       FixItsForVariable.erase(VD);
-      continue;
-    }
-    
-    const auto VarGroupForVD = VarGrpMap.find(VD);
-    if (VarGroupForVD != VarGrpMap.end()) {
-      for (const VarDecl * V : VarGroupForVD->second) {
-        if (V == VD) {
-          continue;
-        }
-        if (impossibleToFixForVar(FixablesForUnsafeVars, S, V)) {
-          ImpossibleToFix = true;
-          break;
-        }
-      }
-
-      if (ImpossibleToFix) {
-        FixItsForVariable.erase(VD);
-        for (const VarDecl * V : VarGroupForVD->second) {
-          FixItsForVariable.erase(V);
-        }
-        continue;
-      }
-    }
-    FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
-                                 FixItsForVD.begin(), FixItsForVD.end());
-
-    // Fix-it shall not overlap with macros or/and templates:
+    else
+      FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
+                                   FixItsForVD.begin(), FixItsForVD.end());
+    // We conservatively discard fix-its of a variable if
+    // a fix-it overlaps with macros; or
+    // a fix-it conflicts with another one
     if (overlapWithMacro(FixItsForVariable[VD]) ||
         clang::internal::anyConflict(FixItsForVariable[VD],
                                      Ctx.getSourceManager())) {
       FixItsForVariable.erase(VD);
-      continue;
-    }
-  }
-  
-  for (auto VD : FixItsForVariable) {
-    const auto VarGroupForVD = VarGrpMap.find(VD.first);
-    const Strategy::Kind ReplacementTypeForVD = S.lookup(VD.first);
-    if (VarGroupForVD != VarGrpMap.end()) {
-      for (const VarDecl * Var : VarGroupForVD->second) {
-        if (Var == VD.first) {
-          continue;
-        }
-        
-        FixItList GroupFix;
-        if (FixItsForVariable.find(Var) == FixItsForVariable.end()) {
-          GroupFix = fixVariable(Var, ReplacementTypeForVD, Tracker,
-                                           Var->getASTContext(), Handler);
-        } else {
-          GroupFix = FixItsForVariable[Var];
-        }
-        
-        for (auto Fix : GroupFix) {
-          FixItsForVariable[VD.first].push_back(Fix);
-        }
-      }
     }
   }
   return FixItsForVariable;
 }
 
-
 static Strategy
 getNaiveStrategy(const llvm::SmallVectorImpl<const VarDecl *> &UnsafeVars) {
   Strategy S;
@@ -1782,135 +1614,54 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
                                    bool EmitSuggestions) {
   assert(D && D->getBody());
   WarningGadgetSets UnsafeOps;
-  FixableGadgetSets FixablesForAllVars;
-
-  auto [FixableGadgets, WarningGadgets, Tracker] =
-    findGadgets(D, Handler, EmitSuggestions);
+  FixableGadgetSets FixablesForUnsafeVars;
+  DeclUseTracker Tracker;
+
+  {
+    auto [FixableGadgets, WarningGadgets, TrackerRes] =
+      findGadgets(D, Handler, EmitSuggestions);
+
+    if (!EmitSuggestions) {
+      // Our job is very easy without suggestions. Just warn about
+      // every problematic operation and consider it done. No need to deal
+      // with fixable gadgets, no need to group operations by variable.
+      for (const auto &G : WarningGadgets) {
+        Handler.handleUnsafeOperation(G->getBaseStmt(),
+                                      /*IsRelatedToDecl=*/false);
+      }
 
-  if (!EmitSuggestions) {
-    // Our job is very easy without suggestions. Just warn about
-    // every problematic operation and consider it done. No need to deal
-    // with fixable gadgets, no need to group operations by variable.
-    for (const auto &G : WarningGadgets) {
-      Handler.handleUnsafeOperation(G->getBaseStmt(),
-                                    /*IsRelatedToDecl=*/false);
+      // This return guarantees that most of the machine doesn't run when
+      // suggestions aren't requested.
+      assert(FixableGadgets.size() == 0 &&
+             "Fixable gadgets found but suggestions not requested!");
+      return;
     }
 
-    // This return guarantees that most of the machine doesn't run when
-    // suggestions aren't requested.
-    assert(FixableGadgets.size() == 0 &&
-           "Fixable gadgets found but suggestions not requested!");
-    return;
+    UnsafeOps = groupWarningGadgetsByVar(std::move(WarningGadgets));
+    FixablesForUnsafeVars = groupFixablesByVar(std::move(FixableGadgets));
+    Tracker = std::move(TrackerRes);
   }
 
-  UnsafeOps = groupWarningGadgetsByVar(std::move(WarningGadgets));
-  FixablesForAllVars = groupFixablesByVar(std::move(FixableGadgets));
-
-  std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
-  DefMapTy VariableGroupsMap{};
+  std::map<const VarDecl *, FixItList> FixItsForVariable;
 
   // Filter out non-local vars and vars with unclaimed DeclRefExpr-s.
-  for (auto it = FixablesForAllVars.byVar.cbegin();
-       it != FixablesForAllVars.byVar.cend();) {
+  for (auto it = FixablesForUnsafeVars.byVar.cbegin();
+       it != FixablesForUnsafeVars.byVar.cend();) {
     // FIXME: Support ParmVarDecl as well.
     if (!it->first->isLocalVarDecl() || Tracker.hasUnclaimedUses(it->first)) {
-      it = FixablesForAllVars.byVar.erase(it);
+      it = FixablesForUnsafeVars.byVar.erase(it);
     } else {
       ++it;
     }
   }
 
   llvm::SmallVector<const VarDecl *, 16> UnsafeVars;
-  for (const auto &[VD, ignore] : FixablesForAllVars.byVar)
+  for (const auto &[VD, ignore] : FixablesForUnsafeVars.byVar)
     UnsafeVars.push_back(VD);
-  
-  // Fixpoint iteration for pointer assignments
-  using DepMapTy = DenseMap<const VarDecl *, std::set<const VarDecl *>>;
-  DepMapTy DependenciesMap{};
-  DepMapTy PtrAssignmentGraph{};
-    
-  for (auto it : FixablesForAllVars.byVar) {
-    for (const FixableGadget *fixable : it.second) {
-      std::optional<std::pair<const VarDecl *, const VarDecl *>> ImplPair =
-                                  fixable->getStrategyImplications();
-      if (ImplPair) {
-        std::pair<const VarDecl *, const VarDecl *> Impl = ImplPair.value();
-        PtrAssignmentGraph[Impl.first].insert(Impl.second);
-      }
-    }
-  }
-    
-  /*
-   The following code does a BFS traversal of the `PtrAssignmentGraph`
-   considering all unsafe vars as starting nodes and constructs an undirected
-   graph `DependenciesMap`. Constructing the `DependenciesMap` in this manner
-   elimiates all variables that are unreachable from any unsafe var. In other
-   words, this removes all dependencies that don't include any unsafe variable
-   and consequently don't need any fixit generation.
-   Note: A careful reader would observe that the code traverses
-   `PtrAssignmentGraph` using `CurrentVar` but adds edges between `Var` and
-   `Adj` and not between `CurrentVar` and `Adj`. Both approaches would
-   achieve the same result but the one used here dramatically cuts the
-   amount of hoops the second part of the algorithm needs to jump, given that
-   a lot of these connections become "direct". The reader is advised not to
-   imagine how the graph is transformed because of using `Var` instead of
-   `CurrentVar`. The reader can continue reading as if `CurrentVar` was used,
-   and think about why it's equivalent later.
-   */
-  std::set<const VarDecl *> VisitedVarsDirected{};
-  for (const auto &[Var, ignore] : UnsafeOps.byVar) {
-    if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) {
-  
-      std::queue<const VarDecl*> QueueDirected{};
-      QueueDirected.push(Var);
-      while(!QueueDirected.empty()) {
-        const VarDecl* CurrentVar = QueueDirected.front();
-        QueueDirected.pop();
-        VisitedVarsDirected.insert(CurrentVar);
-        auto AdjacentNodes = PtrAssignmentGraph[CurrentVar];
-        for (const VarDecl *Adj : AdjacentNodes) {
-          if (VisitedVarsDirected.find(Adj) == VisitedVarsDirected.end()) {
-            QueueDirected.push(Adj);
-          }
-          DependenciesMap[Var].insert(Adj);
-          DependenciesMap[Adj].insert(Var);
-        }
-      }
-    }
-  }
-  
-  // Group Connected Components for Unsafe Vars
-  // (Dependencies based on pointer assignments)
-  std::set<const VarDecl *> VisitedVars{};
-  for (const auto &[Var, ignore] : UnsafeOps.byVar) {
-    if (VisitedVars.find(Var) == VisitedVars.end()) {
-      std::vector<const VarDecl *> VarGroup{};
-  
-      std::queue<const VarDecl*> Queue{};
-      Queue.push(Var);
-      while(!Queue.empty()) {
-        const VarDecl* CurrentVar = Queue.front();
-        Queue.pop();
-        VisitedVars.insert(CurrentVar);
-        VarGroup.push_back(CurrentVar);
-        auto AdjacentNodes = DependenciesMap[CurrentVar];
-        for (const VarDecl *Adj : AdjacentNodes) {
-          if (VisitedVars.find(Adj) == VisitedVars.end()) {
-            Queue.push(Adj);
-          }
-        }
-      }
-      for (const VarDecl * V : VarGroup) {
-        if (UnsafeOps.byVar.find(V) != UnsafeOps.byVar.end()) {
-          VariableGroupsMap[V] = VarGroup;
-        }
-      }
-    }
-  }
 
   Strategy NaiveStrategy = getNaiveStrategy(UnsafeVars);
-  FixItsForVariableGroup = getFixIts(FixablesForAllVars, NaiveStrategy, Tracker,
-                                D->getASTContext(), Handler, VariableGroupsMap);
+  FixItsForVariable = getFixIts(FixablesForUnsafeVars, NaiveStrategy, Tracker,
+                                D->getASTContext(), Handler);
 
   // FIXME Detect overlapping FixIts.
 
@@ -1919,11 +1670,10 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
   }
 
   for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) {
-    auto FixItsIt = FixItsForVariableGroup.find(VD);
-    Handler.handleUnsafeVariableGroup(VD, VariableGroupsMap,
-                                      FixItsIt != FixItsForVariableGroup.end()
-                                      ? std::move(FixItsIt->second)
-                                      : FixItList{});
+    auto FixItsIt = FixItsForVariable.find(VD);
+    Handler.handleFixableVariable(VD, FixItsIt != FixItsForVariable.end()
+                                          ? std::move(FixItsIt->second)
+                                          : FixItList{});
     for (const auto &G : WarningGadgets) {
       Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true);
     }

diff  --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 5a194d8ad70a8..eced15ea62a4e 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2218,8 +2218,8 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
     }
   }
 
-  void handleUnsafeVariableGroup(const VarDecl *Variable,
-                                 const DefMapTy &VarGrpMap,
+  // FIXME: rename to handleUnsafeVariable
+  void handleFixableVariable(const VarDecl *Variable,
                              FixItList &&Fixes) override {
     assert(!SuggestSuggestions &&
            "Unsafe buffer usage fixits displayed without suggestions!");
@@ -2227,52 +2227,11 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
         << Variable << (Variable->getType()->isPointerType() ? 0 : 1)
         << Variable->getSourceRange();
     if (!Fixes.empty()) {
-      const auto VarGroupForVD = VarGrpMap.find(Variable)->second;
-      unsigned FixItStrategy = 0; // For now we only have 'std::span' strategy
+      unsigned FixItStrategy = 0; // For now we only has 'std::span' strategy
       const auto &FD = S.Diag(Variable->getLocation(),
-                              diag::note_unsafe_buffer_variable_fixit_group);
-      
-      FD << Variable << FixItStrategy;
-      std::string AllVars = "";
-      if (VarGroupForVD.size() > 1) {
-        if (VarGroupForVD.size() == 2) {
-          if (VarGroupForVD[0] == Variable) {
-            AllVars.append("'" + VarGroupForVD[1]->getName().str() + "'");
-          } else {
-            AllVars.append("'" + VarGroupForVD[0]->getName().str() + "'");
-          }
-        } else {
-          bool first = false;
-          if (VarGroupForVD.size() == 3) {
-            for (const VarDecl * V : VarGroupForVD) {
-              if (V == Variable) {
-                continue;
-              }
-              if (!first) {
-                first = true;
-                AllVars.append("'" + V->getName().str() + "'" + " and ");
-              } else {
-                AllVars.append("'" + V->getName().str() + "'");
-              }
-            }
-          } else {
-            for (const VarDecl * V : VarGroupForVD) {
-              if (V == Variable) {
-                continue;
-              }
-              if (VarGroupForVD.back() != V) {
-                AllVars.append("'" + V->getName().str() + "'" + ", ");
-              } else {
-                AllVars.append("and '" + V->getName().str() + "'");
-              }
-            }
-          }
-        }
-        FD << AllVars << 1;
-      } else {
-        FD << "" << 0;
-      }
+                              diag::note_unsafe_buffer_variable_fixit);
 
+      FD << Variable->getName() << FixItStrategy;
       for (const auto &F : Fixes)
         FD << F;
     }

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp
deleted file mode 100644
index 73bf2cb7a689a..0000000000000
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits -fsafe-buffer-usage-suggestions %s 2>&1 | FileCheck %s
-
-void foo1a() {
-  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}"
-  int *p = new int[4];
-  // 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]]:22-[[@LINE-3]]:22}:", 4}"
-  p = r;
-  int tmp = p[9];
-  int *q;
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
-  q = r;
-}
-
-void foo1b() {
-  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}"
-  int *p = new int[4];
-  // 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]]:22-[[@LINE-3]]:22}:", 4}"
-  p = r;
-  int tmp = p[9];
-  int *q = new int[4];
-  // 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}:", 4}"
-  q = r;
-  tmp = q[9];
-}
-
-void foo1c() {
-  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}"
-  int *p = new int[4];
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
-  p = r;
-  int tmp = r[9];
-  int *q;
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
-  q = r;
-  tmp = q[9];
-}
-
-void foo2a() {
-  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}"
-  int *p = new int[5];
-  // 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]]:22-[[@LINE-3]]:22}:", 5}"
-  int *q = new int[4];
-  // 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}:", 4}"
-  p = q;
-  int tmp = p[8];
-  q = r;
-}
-
-void foo2b() {
-  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}"
-  int *p = new int[5];
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> p"
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{"
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 5}"
-  int *q = new int[4];
-  // 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}:", 4}"
-  p = q;
-  int tmp = q[8];
-  q = r;
-}
-
-void foo2c() {
-  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}"
-  int *p = new int[5];
-  // 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]]:22-[[@LINE-3]]:22}:", 5}"
-  int *q = new int[4];
-  // 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}:", 4}"
-  p = q;
-  int tmp = p[8];
-  q = r;
-  tmp = q[8];
-}
-
-void foo3a() {
-  int *r = new int[7];
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> r"
-  int *p = new int[5];
-  // 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]]:22-[[@LINE-3]]:22}:", 5}"
-  int *q = new int[4];
-  // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span<int> q"
-  q = p;
-  int tmp = p[8];
-  q = r;
-}
-
-void foo3b() {
-  int *r = new int[10];
-  // 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]]:23-[[@LINE-3]]:23}:", 10}"
-  int *p = new int[10];
-  // 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]]:23-[[@LINE-3]]:23}:", 10}"
-  int *q = new int[10];
-  // 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}:", 10}"
-  q = p;
-  int tmp = q[8];
-  q = r;
-}

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
deleted file mode 100644
index 0c5716ba19478..0000000000000
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
-// RUN:            -fsafe-buffer-usage-suggestions \
-// RUN:            -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
-
-void bar(int * param) {}
-
-void foo1a() {
-  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}"
-  int *p = new int[4];
-  // 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]]:22-[[@LINE-3]]:22}:", 4}"
-  p = r;
-  int tmp = p[9];
-  int *q;
-  q = r;
-}
-
-void uuc_if_body() {
-  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}"
-  int *p = new int[4];
-  // 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]]:22-[[@LINE-3]]:22}:", 4}"
-  if (true)
-    p = r;
-  p[5] = 4;
-}
-
-void uuc_if_body1(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}"
-  int *p = new int[4];
-  // 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]]:22-[[@LINE-3]]:22}:", 4}"
-  if (flag) {
-    p = r;
-  }
-  p[5] = 4;
-}
-
-void uuc_if_cond_no_unsafe_op() {
-  int *r = new int[7];
-  int *p = new int[4];
-  if ((p = r)) {
-    int x = 0;
-  }
-}
-
-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}}
-  if ((p = r)) {
-    p[3] = 2;  // expected-note{{used in buffer access here}}
-  }
-}
-
-void uuc_if_cond_unsafe_op1() {
-  int *r = new int[7];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  int *p = new int[4];
-  if ((p = r)) {
-    r[3] = 2;  // expected-note{{used in buffer access here}}
-  }
-}
-
-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}}
-  if ((p = r)) {
-    r[3] = 2;  // expected-note{{used in buffer access here}}
-  }
-  p[4] = 6;  // expected-note{{used in buffer access here}}
-}
-
-void uuc_call1() {
-  int *w = new int[4];  // expected-warning{{'w' is an unsafe pointer used for buffer access}}
-  int *y = new int[4];
-  bar(w = y);
-  w[5] = 0;  // expected-note{{used in buffer access here}}
-}

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
deleted file mode 100644
index 2b37442cbd84b..0000000000000
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fsafe-buffer-usage-suggestions -verify %s
-void bar(int * param) {}
-
-void foo1a() {
-  int *r = new int[7];
-  int *p = new int[4];  // 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 = r;
-  int tmp = p[9];  // expected-note{{used in buffer access here}}
-  int *q;
-  q = r;
-}
-
-void uuc_if_body() {
-  int *r = new int[7];
-  int *p = new int[4];  // 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$}}}}
-  if (true)
-    p = r;
-  p[5] = 4;  // expected-note{{used in buffer access here}}
-}
-
-void uuc_if_body1(bool flag) {
-  int *r = new int[7];
-  int *p = new int[4];  // 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$}}}}
-  if (flag) {
-    p = r;
-  }
-  p[5] = 4;  // expected-note{{used in buffer access here}}
-}
-
-void uuc_if_body2(bool flag) {
-  int *r = new int[7];
-  int *p = new int[4];  // 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$}}}}
-  if (flag) {
-  } else {
-    p = r;
-  }
-
-  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];
-  if ((p = r)) {
-    int x = 0;
-  }
-}
-
-void uuc_if_cond_no_unsafe_op1() {
-  int *r = new int[7];
-  int *p = new int[4];
-  if (true) {
-    int x = 0;
-  } else if ((p = r))
-    int y = 10;
-}
-
-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}}
-  if ((p = r)) {
-    p[3] = 2;  // expected-note{{used in buffer access here}}
-  }
-}
-
-void uuc_if_cond_unsafe_op1() {
-  int *r = new int[7];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  int *p = new int[4];
-  if ((p = r)) {
-    r[3] = 2;  // expected-note{{used in buffer access here}}
-  }
-}
-
-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}}
-  if ((p = r)) {
-    r[3] = 2;  // expected-note{{used in buffer access here}}
-  }
-  p[4] = 6;  // expected-note{{used in buffer access here}}
-}
-
-void uuc_call1() {
-  int *w = new int[4];  // expected-warning{{'w' is an unsafe pointer used for buffer access}}
-  int *y = new int[4];
-  bar(w = y);
-  w[5] = 0;  // expected-note{{used in buffer access here}}
-}

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
deleted file mode 100644
index d2fb56fbdac07..0000000000000
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp
+++ /dev/null
@@ -1,347 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fsafe-buffer-usage-suggestions -verify %s
-
-namespace std {
-  class type_info { };
-}
-
-void local_assign_both_span() {
-  int tmp;
-  int* p = new int[10]; // 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$}}}}
-  tmp = p[4];  // expected-note{{used in buffer access here}}
-
-  int* q = new int[10];  // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'p' to 'std::span' to propagate bounds information between them$}}}}
-  tmp = q[4];  // expected-note{{used in buffer access here}}
-
-  q = p;
-}
-
-void local_assign_rhs_span() {
-  int tmp;
-  int* p = new int[10];
-  int* q = new int[10];  // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information$}}}}
-  tmp = q[4];  // expected-note{{used in buffer access here}}
-  p = q;
-}
-
-void local_assign_no_span() {
-  int tmp;
-  int* p = new int[10];
-  int* q = new int[10];
-  p = q;
-}
-
-void local_assign_lhs_span() {
-  int tmp;
-  int* p = new int[10];  // 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$}}}}
-  tmp = p[4];  // expected-note{{used in buffer access here}}
-  int* q = new int[10];
-
-  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 tmp = d[2];  // expected-note{{used in buffer access here}}
-}
-
-void rhs_span() {
-  int *x = new int[3];
-  int *y;  // 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$}}}}
-  y[5] = 10;  // expected-note{{used in buffer access here}}
-
-  x = y;
-}
-
-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$}}}}
-  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$}}}}
-  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$}}}}
-  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_grouping1() {
-  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 = new int[10];  // expected-warning{{'w' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'w' to 'std::span' to preserve bounds information$}}}}
-  tmp = w[5];  // expected-note{{used in buffer access here}}
-  int *z = new int[10];
-  z = w;
-}
-
-void foo1a() {
-  int *r = new int[7];
-  int *p = new int[4];  // 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 = r;
-  int tmp = p[9];  // expected-note{{used in buffer access here}}
-  int *q;
-  q = r;
-}
-
-void foo1b() {
-  int *r = new int[7];
-  int *p = new int[4];  // 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' to 'std::span' to propagate bounds information between them$}}}}
-  p = r;
-  int tmp = p[9];  // expected-note{{used in buffer access here}}
-  int *q;  // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'p' and 'r' to 'std::span' to propagate bounds information between them$}}}}
-  q = r;
-  tmp = q[9];  // expected-note{{used in buffer access here}}
-}
-
-void foo1c() {
-  int *r = new int[7];  // 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 'q' to 'std::span' to propagate bounds information between them$}}}}
-  int *p = new int[4];
-  p = r;
-  int tmp = r[9];  // expected-note{{used in buffer access here}}
-  int *q;  // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'r' to 'std::span' to propagate bounds information between them$}}}}
-  q = r;
-  tmp = q[9];  // expected-note{{used in buffer access here}}
-}
-
-void foo2a() {
-  int *r = new int[7];
-  int *p = new int[5];  // 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' to 'std::span' to propagate bounds information between them$}}}}
-  int *q = new int[4];
-  p = q;
-  int tmp = p[8];  // expected-note{{used in buffer access here}}
-  q = r;
-}
-
-void foo2b() {
-  int *r = new int[7];
-  int *p = new int[5];
-  int *q = new int[4];  // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'r' to 'std::span' to propagate bounds information between them$}}}}
-  p = q;
-  int tmp = q[8];  // expected-note{{used in buffer access here}}
-  q = r;
-}
-
-void foo2c() {
-  int *r = new int[7];
-  int *p = new int[5];  // 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' to 'std::span' to propagate bounds information between them$}}}}
-  int *q = new int[4];  // expected-warning{{'q' is an unsafe pointer used for buffer access}} expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'p' and 'r' to 'std::span' to propagate bounds information between them$}}}}
-  p = q;
-  int tmp = p[8];  // expected-note{{used in buffer access here}}
-  q = r;
-  tmp = q[8];  // expected-note{{used in buffer access here}}
-}
-
-void foo3a() {
-  int *r = new int[7];
-  int *p = new int[5];  // 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 *q = new int[4];
-  q = p;
-  int tmp = p[8];  // expected-note{{used in buffer access here}}
-  q = r;
-}
-
-void foo3b() {
-  int *r = new int[7];
-  int *p = new int[5];
-  int *q = new int[4];  // expected-warning{{'q' is an unsafe pointer used for buffer access}} //expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'r' and 'p' to 'std::span' to propagate bounds information between them$}}}}
-  q = p;
-  int tmp = q[8];  // expected-note{{used in buffer access here}}
-  q = r;
-}
-
-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$}}}}
-  p = q;
-  int tmp = p[9];  // expected-note{{used in buffer access here}}
-}
-
-void foo_uuc() {
-  int *ptr;
-  int *local;  // expected-warning{{'local' is an unsafe pointer used for buffer access}}
-  local = ptr;
-  local++;  // expected-note{{used in pointer arithmetic here}}
-
-  (local = ptr) += 5;  // expected-warning{{unsafe pointer arithmetic}}
-}
-
-void check_rhs_fix() {
-  int *r = new int[8];  // 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 'x' to 'std::span' to propagate bounds information between them$}}}}
-  int *x;
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  r = x;
-}
-
-void check_rhs_nofix() {
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  int *x;  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  r = x;
-  x++;  // expected-note{{used in pointer arithmetic here}}
-}
-
-void check_rhs_nofix_order() {
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  int *x;  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  x++;  // expected-note{{used in pointer arithmetic here}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  r = x;
-}
-
-void check_rhs_nofix_order1() {
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  int *x;  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  x++;  // expected-note{{used in pointer arithmetic here}}
-  r = x;
-}
-
-void check_rhs_nofix_order2() {
-  int *x;  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  x++;  // expected-note{{used in pointer arithmetic here}}
-  r = x;
-}
-
-void check_rhs_nofix_order3() {
-  int *x;  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  r = x;
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  x++;  // expected-note{{used in pointer arithmetic here}}
-}
-
-void check_rhs_nofix_order4() {
-  int *x;  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  r = x;
-  x++;  // expected-note{{used in pointer arithmetic here}}
-}
-
-void no_unhandled_lhs() {
-  int *r = new int[8];  // 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 'x' to 'std::span' to propagate bounds information between them$}}}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  int *x;
-  r = x;
-}
-
-const std::type_info unhandled_lhs() {
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  int *x;
-  r = x;
-  return typeid(*r);
-}
-
-const std::type_info unhandled_rhs() {
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  r[7] = 9;  // expected-note{{used in buffer access here}}
-  int *x;
-  r = x;
-  return typeid(*x);
-}
-
-void test_negative_index() {
-  int *x = new int[4];  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  int *p;  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
-  p = &x[1];  // expected-note{{used in buffer access here}}
-  p[-1] = 9;  // expected-note{{used in buffer access here}}
-}
-
-void test_unfixable() {
-  int *r = new int[8];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  int *x;  // expected-warning{{'x' is an unsafe pointer used for buffer access}}
-  x[7] = 9;  // expected-note{{used in buffer access here}}
-  r = x;
-  r++;  // expected-note{{used in pointer arithmetic here}}
-}
-
-void test_cyclic_deps() {
-  int *r = new int[10];  // 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 'q' and 'p' to 'std::span' to propagate bounds information between them$}}}}
-  int *q;
-  q = r;
-  int *p;
-  p = q;
-  r[3] = 9; // expected-note{{used in buffer access here}}
-  r = p;
-}
-
-void test_cyclic_deps_a() {
-  int *r = new int[10];  // expected-warning{{'r' is an unsafe pointer used for buffer access}}
-  int *q;
-  q = r;
-  int *p;  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
-  p = q;
-  r[3] = 9; // expected-note{{used in buffer access here}}
-  r = p;
-  p++;  // expected-note{{used in pointer arithmetic here}}
-}
-
-void test_cyclic_deps1() {
-  int *r = new int[10];
-  int *q;
-  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' to 'std::span' to propagate bounds information between them$}}}}
-  p = q;
-  p[3] = 9; // expected-note{{used in buffer access here}}
-  r = p;
-}
-
-void test_cyclic_deps2() {
-  int *r = new int[10];
-  int *q;  // expected-warning{{'q' is an unsafe pointer used for buffer access}}  expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'r' and 'p' to 'std::span' to propagate bounds information between them$}}}}
-  q = r;
-  int *p;
-  p = q;
-  q[3] = 9; // expected-note{{used in buffer access here}}
-  r = p;
-}
-
-void test_cyclic_deps3() {
-  int *r = new int[10];
-  int *q;  // expected-warning{{'q' is an unsafe pointer used for buffer access}}  expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'r' and 'p' to 'std::span' to propagate bounds information between them$}}}}
-  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' and 'r' to 'std::span' to propagate bounds information between them$}}}}
-  p = q;
-  q[3] = 9; // expected-note{{used in buffer access here}}
-  p[4] = 7; // expected-note{{used in buffer access here}}
-  r = p;
-}
-
-void test_cyclic_deps4() {
-  int *r = new int[10];  // 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 'q' and 'p' to 'std::span' to propagate bounds information between them$}}}}
-  int *q;  // expected-warning{{'q' is an unsafe pointer used for buffer access}}  expected-note-re{{{{^change type of 'q' to 'std::span' to preserve bounds information, and change 'r' and 'p' to 'std::span' to propagate bounds information between them$}}}}
-  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' to 'std::span' to propagate bounds information between them$}}}}
-  p = q;
-  q[3] = 9; // expected-note{{used in buffer access here}}
-  p[4] = 7; // expected-note{{used in buffer access here}}
-  r[1] = 5; // expected-note{{used in buffer access here}}
-  r = p;
-}


        


More information about the cfe-commits mailing list