Index: clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h =================================================================== --- clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -52,10 +52,10 @@ } }; -/// Analyze all function declarations in a complete `TU`: +/// Analyze all function declarations in a complete `TU`: void checkUnsafeBufferUsageForTU(const TranslationUnitDecl *TU, UnsafeBufferUsageHandler &Handler, - clang::Sema &S, bool EmitFixits); + clang::Sema &S, bool EmitSuggestions); namespace internal { // Tests if any two `FixItHint`s in `FixIts` conflict. Two `FixItHint`s Index: clang/include/clang/Basic/DiagnosticOptions.def =================================================================== --- clang/include/clang/Basic/DiagnosticOptions.def +++ clang/include/clang/Basic/DiagnosticOptions.def @@ -95,6 +95,8 @@ /// Column limit for formatting message diagnostics, or 0 if unused. VALUE_DIAGOPT(MessageLength, 32, 0) +DIAGOPT(ShowSafeBufferUsageSuggestions, 1, 0) + #undef DIAGOPT #undef ENUM_DIAGOPT #undef VALUE_DIAGOPT Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11889,6 +11889,8 @@ "used%select{| in pointer arithmetic| in buffer access}0 here">; 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< "this builtin requires target: loongarch32">; Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1599,6 +1599,11 @@ Group, Flags<[CC1Option]>, HelpText<"Print a template comparison tree for differing templates">, MarshallingInfoFlag>; +defm safe_buffer_usage_suggestions : BoolFOption<"safe-buffer-usage-suggestions", + DiagnosticOpts<"ShowSafeBufferUsageSuggestions">, DefaultFalse, + PosFlag, + NegFlag>; def fdiscard_value_names : Flag<["-"], "fdiscard-value-names">, Group, HelpText<"Discard value names in LLVM IR">, Flags<[NoXarchOption]>; def fno_discard_value_names : Flag<["-"], "fno-discard-value-names">, Group, Index: clang/lib/Analysis/UnsafeBufferUsage.cpp =================================================================== --- clang/lib/Analysis/UnsafeBufferUsage.cpp +++ clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -867,7 +867,8 @@ /// Scan the function and return a list of gadgets found with provided kits. static std::tuple -findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler) { +findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler, + bool EmitSuggestions) { struct GadgetFinderCallback : MatchFinder::MatchCallback { FixableGadgetList FixableGadgets; @@ -920,33 +921,35 @@ // clang-format off M.addMatcher( - stmt(eachOf( - // A `FixableGadget` matcher and a `WarningGadget` matcher should not disable - // each other (they could if they were put in the same `anyOf` group). - // We also should make sure no two `FixableGadget` (resp. `WarningGadget`) matchers - // match for the same node, so that we can group them - // in one `anyOf` group (for better performance via short-circuiting). - forEveryDescendantStmt(stmt(eachOf( -#define FIXABLE_GADGET(x) \ + stmt(forEveryDescendantEvaluatedStmt(stmt(eachOf( + // Add Gadget::matcher() for every gadget in the registry. +#define WARNING_GADGET(x) \ + allOf(x ## Gadget::matcher().bind(#x), notInSafeBufferOptOut(&Handler)), +#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def" + // Avoid a hanging comma. + unless(stmt()) + )))), + &CB + ); + + if (EmitSuggestions) { + M.addMatcher( + stmt(forEveryDescendantStmt(stmt(eachOf( +#define FIXABLE_GADGET(x) \ x ## Gadget::matcher().bind(#x), #include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def" // In parallel, match all DeclRefExprs so that to find out // whether there are any uncovered by gadgets. - declRefExpr(anyOf(hasPointerType(), hasArrayType()), to(varDecl())).bind("any_dre") - ))), - forEveryDescendantEvaluatedStmt(stmt(anyOf( - // Add Gadget::matcher() for every gadget in the registry. -#define WARNING_GADGET(x) \ - allOf(x ## Gadget::matcher().bind(#x), notInSafeBufferOptOut(&Handler)), -#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def" + declRefExpr(anyOf(hasPointerType(), hasArrayType()), + to(varDecl())).bind("any_dre"), // Also match DeclStmts because we'll need them when fixing // their underlying VarDecls that otherwise don't have // any backreferences to DeclStmts. declStmt().bind("any_ds") - )) - ))), - &CB - ); + )))), + &CB + ); + } // clang-format on M.match(*D->getBody(), D->getASTContext()); @@ -1601,15 +1604,32 @@ void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler, - bool EmitFixits) { + bool EmitSuggestions) { assert(D && D->getBody()); - WarningGadgetSets UnsafeOps; FixableGadgetSets FixablesForUnsafeVars; DeclUseTracker Tracker; { - auto [FixableGadgets, WarningGadgets, TrackerRes] = findGadgets(D, Handler); + 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); + } + + // 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); @@ -1617,36 +1637,33 @@ std::map FixItsForVariable; - if (EmitFixits) { - // Filter out non-local vars and vars with unclaimed DeclRefExpr-s. - for (auto it = FixablesForUnsafeVars.byVar.cbegin(); - it != FixablesForUnsafeVars.byVar.cend();) { - // FIXME: Support ParmVarDecl as well. - if (!it->first->isLocalVarDecl() || Tracker.hasUnclaimedUses(it->first)) { - it = FixablesForUnsafeVars.byVar.erase(it); - } else { - ++it; - } + // Filter out non-local vars and vars with unclaimed DeclRefExpr-s. + for (auto it = FixablesForUnsafeVars.byVar.cbegin(); + it != FixablesForUnsafeVars.byVar.cend();) { + // FIXME: Support ParmVarDecl as well. + if (!it->first->isLocalVarDecl() || Tracker.hasUnclaimedUses(it->first)) { + it = FixablesForUnsafeVars.byVar.erase(it); + } else { + ++it; } + } - llvm::SmallVector UnsafeVars; - for (const auto &[VD, ignore] : FixablesForUnsafeVars.byVar) - UnsafeVars.push_back(VD); + llvm::SmallVector UnsafeVars; + for (const auto &[VD, ignore] : FixablesForUnsafeVars.byVar) + UnsafeVars.push_back(VD); - Strategy NaiveStrategy = getNaiveStrategy(UnsafeVars); - FixItsForVariable = getFixIts(FixablesForUnsafeVars, NaiveStrategy, Tracker, - D->getASTContext(), Handler); + Strategy NaiveStrategy = getNaiveStrategy(UnsafeVars); + FixItsForVariable = getFixIts(FixablesForUnsafeVars, NaiveStrategy, Tracker, + D->getASTContext(), Handler); - // FIXME Detect overlapping FixIts. - } + // FIXME Detect overlapping FixIts. for (const auto &G : UnsafeOps.noVar) { Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false); } for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) { - auto FixItsIt = - EmitFixits ? FixItsForVariable.find(VD) : FixItsForVariable.end(); + auto FixItsIt = FixItsForVariable.find(VD); Handler.handleFixableVariable(VD, FixItsIt != FixItsForVariable.end() ? std::move(FixItsIt->second) : FixItList{}); Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -7143,6 +7143,9 @@ A->claim(); } + Args.addOptInFlag(CmdArgs, options::OPT_fsafe_buffer_usage_suggestions, + options::OPT_fno_safe_buffer_usage_suggestions); + // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) { Index: clang/lib/Sema/AnalysisBasedWarnings.cpp =================================================================== --- clang/lib/Sema/AnalysisBasedWarnings.cpp +++ clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2156,9 +2156,11 @@ namespace { class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { Sema &S; + bool SuggestSuggestions; // Recommend -fsafe-buffer-usage-suggestions? public: - UnsafeBufferUsageReporter(Sema &S) : S(S) {} + UnsafeBufferUsageReporter(Sema &S, bool SuggestSuggestions) + : S(S), SuggestSuggestions(SuggestSuggestions) {} void handleUnsafeOperation(const Stmt *Operation, bool IsRelatedToDecl) override { @@ -2192,20 +2194,30 @@ } } else { if (isa(Operation)) { + // note_unsafe_buffer_operation doesn't have this mode yet. + assert(!IsRelatedToDecl && "Not implemented yet!"); MsgParam = 3; } Loc = Operation->getBeginLoc(); Range = Operation->getSourceRange(); } - if (IsRelatedToDecl) + if (IsRelatedToDecl) { + assert(!SuggestSuggestions && + "Variables blamed for unsafe buffer usage without suggestions!"); S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range; - else + } else { S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range; + if (SuggestSuggestions) { + S.Diag(Loc, diag::note_safe_buffer_usage_suggestions_disabled); + } + } } // FIXME: rename to handleUnsafeVariable void handleFixableVariable(const VarDecl *Variable, FixItList &&Fixes) override { + assert(!SuggestSuggestions && + "Unsafe buffer usage fixits displayed without suggestions!"); S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable) << Variable << (Variable->getType()->isPointerType() ? 0 : 1) << Variable->getSourceRange(); @@ -2300,11 +2312,17 @@ // Emit unsafe buffer usage warnings and fixits. if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, SourceLocation()) || !Diags.isIgnored(diag::warn_unsafe_buffer_variable, SourceLocation())) { - UnsafeBufferUsageReporter R(S); - checkUnsafeBufferUsageForTU( - TU, R, S, - /*EmitFixits=*/S.getDiagnostics().getDiagnosticOptions().ShowFixits && - S.getLangOpts().CPlusPlus20); + DiagnosticOptions &DiagOpts = S.getDiagnostics().getDiagnosticOptions(); + + bool CanEmitSuggestions = S.getLangOpts().CPlusPlus20; + // Should != Can. + bool ShouldEmitSuggestions = CanEmitSuggestions && + DiagOpts.ShowSafeBufferUsageSuggestions; + bool ShouldSuggestSuggestions = CanEmitSuggestions && + !DiagOpts.ShowSafeBufferUsageSuggestions; + + UnsafeBufferUsageReporter R(S, ShouldSuggestSuggestions); + checkUnsafeBufferUsageForTU(TU, R, S, ShouldEmitSuggestions); } } Index: clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp =================================================================== --- clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp +++ clang/test/SemaCXX/unsafe-buffer-usage-diag-type.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -verify %s +// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions -verify %s namespace localVar { void testRefersPtrLocalVarDecl(int i) { Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-addressof-arraysubscript.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-addressof-arraysubscript.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-addressof-arraysubscript.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s int f(unsigned long, void *); Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-assign-to-array-subscr-on-ptr.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-assign-to-array-subscr-on-ptr.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-assign-to-array-subscr-on-ptr.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s // TODO cases where we don't want fixits Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-deref-simple-ptr-arith.cpp @@ -1,4 +1,7 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits -fsyntax-only %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits -fsyntax-only \ +// RUN: %s 2>&1 | FileCheck %s // TODO test we don't mess up vertical whitespace // TODO test different whitespaces Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s typedef int * Int_ptr_t; typedef int Int_t; Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s void foo(int* v) { } Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s void basic_dereference() { int tmp; Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pre-increment.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pre-increment.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pre-increment.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s void foo(int * , int *); Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -verify %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions -verify %s [[clang::unsafe_buffer_usage]] void deprecatedFunction3(); 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 @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s void basic(int * x) { int tmp; Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -Wno-unused-value -verify %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -Wno-unused-value -verify %s void basic(int * x) { // expected-warning{{'x' is an unsafe pointer used for buffer access}} int *p1 = new int[10]; // not to warn Index: clang/test/SemaCXX/warn-unsafe-buffer-usage-suggestions-flag.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/warn-unsafe-buffer-usage-suggestions-flag.cpp @@ -0,0 +1,66 @@ +// Test the -cc1 flag. There's no -fno-... option in -cc1 invocations, +// just the positive option. + +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -verify=OFF %s +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -verify=ON %s \ +// RUN: -fsafe-buffer-usage-suggestions + +// Test driver flags. Now there's both -f... and -fno-... to worry about. + +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -Xclang -verify=OFF %s +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -Xclang -verify=ON %s +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fno-safe-buffer-usage-suggestions \ +// RUN: -Xclang -verify=OFF %s + +// In case of driver flags, last flag takes precedence. + +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fno-safe-buffer-usage-suggestions \ +// RUN: -Xclang -verify=OFF %s +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fno-safe-buffer-usage-suggestions \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -Xclang -verify=ON %s + +// Passing through -Xclang. + +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -Xclang -fsafe-buffer-usage-suggestions \ +// RUN: -Xclang -verify=ON %s + +// -Xclang flags take precedence over driver flags. + +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -Xclang -fsafe-buffer-usage-suggestions \ +// RUN: -fno-safe-buffer-usage-suggestions \ +// RUN: -Xclang -verify=ON %s +// RUN: %clang -fsyntax-only -std=c++20 -Wunsafe-buffer-usage \ +// RUN: -fno-safe-buffer-usage-suggestions \ +// RUN: -Xclang -fsafe-buffer-usage-suggestions \ +// RUN: -Xclang -verify=ON %s + +[[clang::unsafe_buffer_usage]] void bar(int *); + +void foo(int *x) { // \ + // ON-warning{{'x' is an unsafe pointer used for buffer access}} + // FIXME: Better "OFF" warning? + x[5] = 10; // \ + // ON-note {{used in buffer access here}} \ + // OFF-warning{{unsafe buffer access}} \ + // OFF-note {{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}} + + x += 5; // \ + // ON-note {{used in pointer arithmetic here}} \ + // OFF-warning{{unsafe pointer arithmetic}} \ + // OFF-note {{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}} + + bar(x); // \ + // ON-warning{{function introduces unsafe buffer manipulation}} \ + // OFF-warning{{function introduces unsafe buffer manipulation}} \ + // OFF-note {{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}} +} Index: clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp =================================================================== --- clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp +++ clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -fblocks -include %s -verify %s +// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: -fsafe-buffer-usage-suggestions \ +// RUN: -fblocks -include %s -verify %s // RUN: %clang -x c++ -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s // RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s