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>; - /// 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, 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 #include #include -#include using namespace llvm; using namespace clang; @@ -257,29 +256,6 @@ isInUnspecifiedPointerContext(internal::Matcher 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 -isInUnspecifiedUntypedContext(internal::Matcher 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 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> - getStrategyImplications() const { - return std::nullopt; - } }; using FixableGadgetList = std::vector>; @@ -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(PointerAssignmentTag)), - PtrLHS(Result.Nodes.getNodeAs(PointerAssignLHSTag)), - PtrRHS(Result.Nodes.getNodeAs(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 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> - getStrategyImplications() const override { - return std::make_pair(cast(PtrLHS->getDecl()), - cast(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 struct CompareNode { }; struct WarningGadgetSets { - std::map, + std::map>, // To keep keys sorted by their locations in the map so that the // order is deterministic: CompareNode> byVar; // These Gadgets are not related to pointer variables (e. g. temporaries). - llvm::SmallVector noVar; + llvm::SmallVector, 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(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> byVar; + std::map>> byVar; }; static FixableGadgetSets @@ -1117,7 +1031,7 @@ groupFixablesByVar(FixableGadgetList &&AllFixableOperations) { for (const DeclRefExpr *DRE : DREs) { if (const auto *VD = dyn_cast(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 &FixIts, return false; } -std::optional -PointerAssignmentGadget::getFixits(const Strategy &S) const { - const auto *LeftVD = cast(PtrLHS->getDecl()); - const auto *RightVD = cast(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 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 Fixits = F->getFixits(S); - if (!Fixits) { - return true; - } - } - return false; -} - static std::map 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 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 &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 FixItsForVariableGroup; - DefMapTy VariableGroupsMap{}; + std::map 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 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>; - DepMapTy DependenciesMap{}; - DepMapTy PtrAssignmentGraph{}; - - for (auto it : FixablesForAllVars.byVar) { - for (const FixableGadget *fixable : it.second) { - std::optional> ImplPair = - fixable->getStrategyImplications(); - if (ImplPair) { - std::pair 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 VisitedVarsDirected{}; - for (const auto &[Var, ignore] : UnsafeOps.byVar) { - if (VisitedVarsDirected.find(Var) == VisitedVarsDirected.end()) { - - std::queue 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 VisitedVars{}; - for (const auto &[Var, ignore] : UnsafeOps.byVar) { - if (VisitedVars.find(Var) == VisitedVars.end()) { - std::vector VarGroup{}; - - std::queue 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 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 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 q" - q = r; -} - -void foo1b() { - int *r = new int[7]; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span 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 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 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 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 p" - p = r; - int tmp = r[9]; - int *q; - // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span 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 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 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 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 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 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 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 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 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 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 r" - int *p = new int[5]; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span 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 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 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 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 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 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 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 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 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 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 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; -}