Index: clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h =================================================================== --- clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -35,6 +35,10 @@ /// variables, where `Var` is in, contains parameters. virtual VarGrpRef getGroupOfVar(const VarDecl *Var, bool *HasParm = nullptr) const =0; + + /// Returns the non-empty group of variables that include parameters of the + /// analyzing function, if such a group exists. An empty group, otherwise. + virtual VarGrpRef getGroupOfParms() const =0; }; /// The interface that lets the caller handle unsafe buffer usage analysis Index: clang/lib/Analysis/UnsafeBufferUsage.cpp =================================================================== --- clang/lib/Analysis/UnsafeBufferUsage.cpp +++ clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -13,6 +13,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/iterator_range.h" #include #include #include @@ -1637,12 +1638,10 @@ CharSourceRange derefRange = clang::CharSourceRange::getCharRange( Op->getBeginLoc(), Op->getBeginLoc().getLocWithOffset(1)); // Inserts the [0] - std::optional EndOfOperand = - getEndCharLoc(BaseDeclRefExpr, SM, Ctx.getLangOpts()); - if (EndOfOperand) { + if (auto LocPastOperand = + getPastLoc(BaseDeclRefExpr, SM, Ctx.getLangOpts())) { return FixItList{{FixItHint::CreateRemoval(derefRange), - FixItHint::CreateInsertion( - (*EndOfOperand).getLocWithOffset(1), "[0]")}}; + FixItHint::CreateInsertion(*LocPastOperand, "[0]")}}; } break; } @@ -1980,19 +1979,9 @@ // [[clang::unsafe_buffer_usage]] void f(int *p) { // added def // return f(std::span(p, <# size #>)); // } -// -// The actual fix-its may contain more details, e.g., the attribute may be guard -// by a macro -// #if __has_cpp_attribute(clang::unsafe_buffer_usage) -// [[clang::unsafe_buffer_usage]] -// #endif -// -// `ParmsMask` is an array of size of `FD->getNumParams()` such -// that `ParmsMask[i]` is true iff the `i`-th parameter will be fixed with some -// strategy. static std::optional -createOverloadsForFixedParams(const std::vector &ParmsMask, const Strategy &S, - const FunctionDecl *FD, const ASTContext &Ctx, +createOverloadsForFixedParams(const Strategy &S, const FunctionDecl *FD, + const ASTContext &Ctx, UnsafeBufferUsageHandler &Handler) { // FIXME: need to make this conflict checking better: if (hasConflictingOverload(FD)) @@ -2002,21 +1991,33 @@ const LangOptions &LangOpts = Ctx.getLangOpts(); const unsigned NumParms = FD->getNumParams(); std::vector NewTysTexts(NumParms); + std::vector ParmsMask(NumParms, false); + bool AtLeastOneParmToFix = false; for (unsigned i = 0; i < NumParms; i++) { - if (!ParmsMask[i]) + const ParmVarDecl *PVD = FD->getParamDecl(i); + + if (S.lookup(PVD) == Strategy::Kind::Wontfix) continue; + if (S.lookup(PVD) != Strategy::Kind::Span) + // Not supported, not suppose to happen: + return std::nullopt; std::optional PteTyQuals = std::nullopt; std::optional PteTyText = - getPointeeTypeText(FD->getParamDecl(i), SM, LangOpts, &PteTyQuals); + getPointeeTypeText(PVD, SM, LangOpts, &PteTyQuals); if (!PteTyText) // something wrong in obtaining the text of the pointee type, give up return std::nullopt; // FIXME: whether we should create std::span type depends on the Strategy. NewTysTexts[i] = getSpanTypeText(*PteTyText, PteTyQuals); + ParmsMask[i] = true; + AtLeastOneParmToFix = true; } + if (!AtLeastOneParmToFix) + // No need to create function overloads: + return {}; // FIXME Respect indentation of the original code. // A lambda that creates the text representation of a function declaration @@ -2325,28 +2326,17 @@ const VariableGroupsManager &VarGrpMgr, const FunctionDecl *FD, const Strategy &S, ASTContext &Ctx, UnsafeBufferUsageHandler &Handler) { FixItList FixItsSharedByParms{}; - std::vector ParmsNeedFixMask(FD->getNumParams(), false); - const VarDecl *FirstParmNeedsFix = nullptr; - - for (unsigned i = 0; i < FD->getNumParams(); i++) - if (FixItsForVariable.count(FD->getParamDecl(i))) { - ParmsNeedFixMask[i] = true; - FirstParmNeedsFix = FD->getParamDecl(i); - } - if (FirstParmNeedsFix) { - // In case at least one parameter needs to be fixed: - std::optional OverloadFixes = - createOverloadsForFixedParams(ParmsNeedFixMask, S, FD, Ctx, Handler); + std::optional OverloadFixes = + createOverloadsForFixedParams(S, FD, Ctx, Handler); - if (OverloadFixes) { - FixItsSharedByParms.append(*OverloadFixes); - } else { - // Something wrong in generating `OverloadFixes`, need to remove the - // whole group, where parameters are in, from `FixItsForVariable` (Note - // that all parameters should be in the same group): - for (auto *Member : VarGrpMgr.getGroupOfVar(FirstParmNeedsFix)) - FixItsForVariable.erase(Member); - } + if (OverloadFixes) { + FixItsSharedByParms.append(*OverloadFixes); + } else { + // Something wrong in generating `OverloadFixes`, need to remove the + // whole group, where parameters are in, from `FixItsForVariable` (Note + // that all parameters should be in the same group): + for (auto *Member : VarGrpMgr.getGroupOfParms()) + FixItsForVariable.erase(Member); } return FixItsSharedByParms; } @@ -2451,8 +2441,9 @@ return FinalFixItsForVariable; } +template static Strategy -getNaiveStrategy(const llvm::SmallVectorImpl &UnsafeVars) { +getNaiveStrategy(llvm::iterator_range UnsafeVars) { Strategy S; for (const VarDecl *VD : UnsafeVars) { S.set(VD, Strategy::Kind::Span); @@ -2486,6 +2477,10 @@ return std::nullopt; return Groups[VarGrpMap.at(Var)]; } + + VarGrpRef getGroupOfParms() const override { + return GrpsUnionForParms.getArrayRef(); + } }; void clang::checkUnsafeBufferUsage(const Decl *D, @@ -2579,6 +2574,14 @@ it->first, it->first->getBeginLoc(), ("failed to produce fixit for '" + it->first->getNameAsString() + "' : neither local nor a parameter")); +#endif + it = FixablesForAllVars.byVar.erase(it); + } else if (it->first->getType().getCanonicalType()->isReferenceType()) { +#ifndef NDEBUG + Handler.addDebugNoteForVar(it->first, it->first->getBeginLoc(), + ("failed to produce fixit for '" + + it->first->getNameAsString() + + "' : has a reference type")); #endif it = FixablesForAllVars.byVar.erase(it); } else if (Tracker.hasUnclaimedUses(it->first)) { @@ -2605,10 +2608,6 @@ } } - llvm::SmallVector UnsafeVars; - for (const auto &[VD, ignore] : FixablesForAllVars.byVar) - UnsafeVars.push_back(VD); - // Fixpoint iteration for pointer assignments using DepMapTy = DenseMap>; DepMapTy DependenciesMap{}; @@ -2737,7 +2736,13 @@ ++I; } - Strategy NaiveStrategy = getNaiveStrategy(UnsafeVars); + // We assign strategies to variables that are 1) in the graph and 2) can be + // fixed. Other variables have the default "Won't fix" strategy. + Strategy NaiveStrategy = getNaiveStrategy(llvm::make_filter_range( + VisitedVars, [&FixablesForAllVars](const VarDecl *V) { + // If a warned variable has no "Fixable", it is considered unfixable: + return FixablesForAllVars.byVar.count(V); + })); VariableGroupsManagerImpl VarGrpMgr(Groups, VarGrpMap, GrpsUnionForParms); if (isa(D)) Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-multi-parm-span.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-multi-parm-span.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-multi-parm-span.cpp @@ -68,18 +68,16 @@ // Fixing local variables implicates fixing parameters void multiParmLocalAllFix(int *p, int * r) { - // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:28-[[@LINE-1]]:34}:"std::span p" - // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:36-[[@LINE-2]]:43}:"std::span r" - // CHECK: fix-it:{{.*}}:{[[@LINE+1]]:3-[[@LINE+1]]:10}:"std::span x" - int * x; // expected-warning{{'x' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'x' to 'std::span' to preserve bounds information, and change 'p', 'z', and 'r' to safe types to make function 'multiParmLocalAllFix' bounds-safe}} - // CHECK: fix-it:{{.*}}:{[[@LINE+1]]:3-[[@LINE+1]]:10}:"std::span z" - int * z; // expected-warning{{'z' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'z' to 'std::span' to preserve bounds information, and change 'x', 'p', and 'r' to safe types to make function 'multiParmLocalAllFix' bounds-safe}} + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:28-[[@LINE-1]]:34}:"std::span p" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-2]]:36-[[@LINE-2]]:43}:"std::span r" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]:3-[[@LINE+1]]:10}:"std::span x" + int * x; // expected-warning{{'x' is an unsafe pointer used for buffer access}} + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]:3-[[@LINE+1]]:10}:"std::span z" + int * z; // expected-warning{{'z' is an unsafe pointer used for buffer access}} int * y; x = p; - y = x; + y = x; // FIXME: we do not fix `y = x` here as the `.data()` fix-it is not generally correct // `x` needs to be fixed so does the pointer assigned to `x`, i.e.,`p` x[5] = 5; // expected-note{{used in buffer access here}} z = r; @@ -89,33 +87,31 @@ // fixing `x` involves fixing all `p`, `r` and `z`. Similar for // fixing `z`. } -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void multiParmLocalAllFix(int *p, int * r) {return multiParmLocalAllFix(std::span(p, <# size #>), std::span(r, <# size #>));}\n" +// CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void multiParmLocalAllFix(int *p, int * r) {return multiParmLocalAllFix(std::span(p, <# size #>), std::span(r, <# size #>));}\n" // Fixing parameters implicates fixing local variables -// CHECK: fix-it:{{.*}}:{[[@LINE+2]]:29-[[@LINE+2]]:35}:"std::span p" -// CHECK: fix-it:{{.*}}:{[[@LINE+1]]:37-[[@LINE+1]]:44}:"std::span r" +// CHECK-NOT: fix-it:{{.*}}:{[[@LINE+2]]:29-[[@LINE+2]]:35}:"std::span p" +// CHECK-NOT: fix-it:{{.*}}:{[[@LINE+1]]:37-[[@LINE+1]]:44}:"std::span r" void multiParmLocalAllFix2(int *p, int * r) { // expected-warning{{'p' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'p' to 'std::span' to preserve bounds information, and change 'x', 'r', and 'z' to safe types to make function 'multiParmLocalAllFix2' bounds-safe}} \ - expected-warning{{'r' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'r' to 'std::span' to preserve bounds information, and change 'p', 'x', and 'z' to safe types to make function 'multiParmLocalAllFix2' bounds-safe}} + expected-warning{{'r' is an unsafe pointer used for buffer access}} int * x = new int[10]; - // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span x" - // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" - // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span x" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" int * z = new int[10]; - // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span z" - // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" - // CHECK: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span z" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" + // CHECK-NOT: fix-it:{{.*}}:{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" int * y; p = x; - y = x; + y = x; // FIXME: we do not fix `y = x` here as the `.data()` fix-it is not generally correct p[5] = 5; // expected-note{{used in buffer access here}} r = z; r[5] = 5; // expected-note{{used in buffer access here}} } -// CHECK: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void multiParmLocalAllFix2(int *p, int * r) {return multiParmLocalAllFix2(std::span(p, <# size #>), std::span(r, <# size #>));}\n" +// CHECK-NOT: fix-it:{{.*}}:{[[@LINE-1]]:2-[[@LINE-1]]:2}:"\n{{\[}}{{\[}}clang::unsafe_buffer_usage{{\]}}{{\]}} void multiParmLocalAllFix2(int *p, int * r) {return multiParmLocalAllFix2(std::span(p, <# size #>), std::span(r, <# size #>));}\n" // No fix emitted for any of the parameter since parameter `r` cannot be fixed Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-fixits-test.cpp @@ -2,18 +2,18 @@ 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}" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span r" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-NOT: 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}" + // 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}:", 4}" p = r; int tmp = p[9]; int *q; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span q" - q = r; + q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct } void foo1b() { @@ -37,12 +37,12 @@ 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}" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span r" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-NOT: 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; + p = r; // FIXME: we do not fix `p = r` here as the `.data()` fix-it is not generally correct int tmp = r[9]; int *q; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span q" @@ -70,18 +70,18 @@ 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}" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span r" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-NOT: 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; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span q" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-3]]:22-[[@LINE-3]]:22}:", 4}" + p = q; // FIXME: we do not fix `p = q` here as the `.data()` fix-it is not generally correct int tmp = q[8]; q = r; } @@ -109,12 +109,12 @@ 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}" + // 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-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span q" - q = p; + q = p; // FIXME: we do not fix `q = p` here as the `.data()` fix-it is not generally correct int tmp = p[8]; q = r; } Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init-fixits.cpp @@ -62,13 +62,13 @@ int *z = new int[8]; int tmp; int *y = new int[10]; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span y" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span y" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}" tmp = y[5]; int *x = new int[10]; - x = y; + x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct int *w = z; } Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-ptr-init.cpp @@ -27,17 +27,17 @@ int *q = new int[6]; int *p = q; // expected-warning{{'p' is an unsafe pointer used for buffer access}} p[5] = 10; // expected-note{{used in buffer access here}} - int *r = q; + int *r = q; // FIXME: we do not fix `int *r = q` here as the `.data()` fix-it is not generally correct } 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$}}}} + int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} tmp = y[5]; // expected-note{{used in buffer access here}} int *x = new int[10]; - x = y; + x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct int *w = z; } Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc-fixits.cpp @@ -6,17 +6,17 @@ 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}" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span r" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK-NOT: 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}" + // 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}:", 4}" p = r; int tmp = p[9]; int *q; - q = r; + q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct } void uuc_if_body() { Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-uuc.cpp @@ -3,11 +3,11 @@ 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$}}}} + int *p = new int[4]; // expected-warning{{'p' is an unsafe pointer used for buffer access}} p = r; int tmp = p[9]; // expected-note{{used in buffer access here}} int *q; - q = r; + q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct } void uuc_if_body() { Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-multi-decl-warnings.cpp @@ -18,9 +18,9 @@ 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$}}}} + int* q = new int[10]; // expected-warning{{'q' is an unsafe pointer used for buffer access}} tmp = q[4]; // expected-note{{used in buffer access here}} - p = q; + p = q; // FIXME: we do not fix `p = q` here as the `.data()` fix-it is not generally correct } void local_assign_no_span() { @@ -49,10 +49,10 @@ 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$}}}} + int *y; // expected-warning{{'y' is an unsafe pointer used for buffer access}} y[5] = 10; // expected-note{{used in buffer access here}} - x = y; + x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct } void rhs_span1() { @@ -65,43 +65,43 @@ void rhs_span2() { int *q = new int[6]; - int *p = q; // expected-warning{{'p' is an unsafe pointer used for buffer access}} + int *p = q; // expected-warning{{'p' is an unsafe pointer used for buffer access}} p[5] = 10; // expected-note{{used in buffer access here}} - int *r = q; + int *r = q; // FIXME: we do not fix `int *r = q` here as the `.data()` fix-it is not generally correct } 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$}}}} + int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} tmp = y[5]; // expected-note{{used in buffer access here}} int *x = new int[10]; - x = y; + x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct 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$}}}} + int *y = new int[10]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} tmp = y[5]; // expected-note{{used in buffer access here}} int *x = new int[10]; - x = y; + x = y; // FIXME: we do not fix `x = y` here as the `.data()` fix-it is not generally correct - 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$}}}} + int *w = new int[10]; // expected-warning{{'w' is an unsafe pointer used for buffer access}} tmp = w[5]; // expected-note{{used in buffer access here}} int *z = new int[10]; - z = w; + z = w; // FIXME: we do not fix `z = w` here as the `.data()` fix-it is not generally correct } 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$}}}} + int *p = new int[4]; // expected-warning{{'p' is an unsafe pointer used for buffer access}} p = r; int tmp = p[9]; // expected-note{{used in buffer access here}} int *q; - q = r; + q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct } void foo1b() { @@ -115,12 +115,12 @@ } 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 *r = new int[7]; // expected-warning{{'r' is an unsafe pointer used for buffer access}} int *p = new int[4]; - p = r; + p = r; // FIXME: we do not fix `p = r` here as the `.data()` fix-it is not generally correct 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; + int *q; // expected-warning{{'q' is an unsafe pointer used for buffer access}} + q = r; // FIXME: we do not fix `q = r` here as the `.data()` fix-it is not generally correct tmp = q[9]; // expected-note{{used in buffer access here}} } @@ -136,8 +136,8 @@ 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 *q = new int[4]; // expected-warning{{'q' is an unsafe pointer used for buffer access}} + p = q; // FIXME: we do not fix `p = q` here as the `.data()` fix-it is not generally correct int tmp = q[8]; // expected-note{{used in buffer access here}} q = r; } @@ -154,9 +154,9 @@ 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 *p = new int[5]; // expected-warning{{'p' is an unsafe pointer used for buffer access}} int *q = new int[4]; - q = p; + q = p; // FIXME: we do not fix `q = p` here as the `.data()` fix-it is not generally correct int tmp = p[8]; // expected-note{{used in buffer access here}} q = r; } Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-fixit.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-fixit.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-fixit.cpp @@ -174,7 +174,7 @@ int * b; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: int * c; - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span c" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span c" c[5] = 5; #pragma clang unsafe_buffer_usage begin @@ -182,6 +182,7 @@ #pragma clang unsafe_buffer_usage end a = b; b = c; +// FIXME: we do not fix `a = b` and `b = c` because the `.data()` fix-it is not generally correct. } // The implication edges are: `a` -> `b` -> `c` -> `a`.