[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