diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -46,6 +46,9 @@ s += " #>"; return s; } + + /// Returns a reference to the `Preprocessor`: + virtual const Preprocessor & getPP() const; }; // This function invokes the analysis and allows the caller to react to it diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -945,4 +945,15 @@ } +def err_pp_double_begin_pragma_unsafe_buffer_usage : +Error<"already inside '#pragma unsafe_buffer_usage'">; + +def err_pp_unmatched_end_begin_pragma_unsafe_buffer_usage : +Error<"not currently inside '#pragma unsafe_buffer_usage'">; + +def err_pp_unclosed_pragma_unsafe_buffer_usage : +Error<"'#pragma unsafe_buffer_usage' was not ended">; + +def err_pp_pragma_unsafe_buffer_usage_syntax : +Error<"Expected 'begin' or 'end'">; } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2688,6 +2688,51 @@ void emitMacroDeprecationWarning(const Token &Identifier) const; void emitRestrictExpansionWarning(const Token &Identifier) const; void emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const; + + /// This boolean state keeps track if the current scanned token (by this PP) + /// is in an "-Wunsafe-buffer-usage" opt-out region. Assuming PP scans a + /// translation unit in a linear order. + bool InSafeBufferOptOutRegion = 0; + + /// Hold the start location of the current "-Wunsafe-buffer-usage" opt-out + /// region if PP is currently in such a region. Hold undefined value + /// otherwise. + SourceLocation CurrentSafeBufferOptOutStart; // It is used to report the start location of an never-closed region. + + // An ordered sequence of "-Wunsafe-buffer-usage" opt-out regions in one + // translation unit. Each region is represented by a pair of start and end + // locations. A region is "open" if its' start and end locations are + // identical. + SmallVector, 8> SafeBufferOptOutMap; + +public: + /// \return true iff the given `Loc` is in a "-Wunsafe-buffer-usage" opt-out + /// region. This `Loc` must be a source location that has been pre-processed. + bool isSafeBufferOptOut(const SourceManager&SourceMgr, const SourceLocation &Loc) const; + + /// Alter the state of whether this PP currently is in a + /// "-Wunsafe-buffer-usage" opt-out region. + /// + /// \param isEnter: true if this PP is entering a region; otherwise, this PP + /// is exiting a region + /// \param Loc: the location of the entry or exit of a + /// region + /// \return true iff it is INVALID to enter or exit a region, i.e., + /// attempt to enter a region before exiting a previous region, or exiting a + /// region that PP is not currently in. + bool enterOrExitSafeBufferOptOutRegion(bool isEnter, + const SourceLocation &Loc); + + /// \return true iff this PP is currently in a "-Wunsafe-buffer-usage" + /// opt-out region + bool isPPInSafeBufferOptOutRegion(); + + /// \param StartLoc: output argument. It will be set to the start location of + /// the current "-Wunsafe-buffer-usage" opt-out region iff this function + /// returns true. + /// \return true iff this PP is currently in a "-Wunsafe-buffer-usage" + /// opt-out region + bool isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc); }; /// Abstract base class that describes a handler that will receive diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -9,6 +9,7 @@ #include "clang/Analysis/Analyses/UnsafeBufferUsage.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallVector.h" #include @@ -117,6 +118,12 @@ return Visitor.findMatch(DynTypedNode::create(Node)); } +// Matches a `Stmt` node iff the node is in a safe-buffer opt-out region +AST_MATCHER_P(Stmt, notInSafeBufferOptOut, const Preprocessor *, PP) { + const SourceManager &SM = Finder->getASTContext().getSourceManager(); + return !PP->isSafeBufferOptOut(SM, Node.getBeginLoc()); +} + AST_MATCHER_P(CastExpr, castSubExpr, internal::Matcher, innerMatcher) { return innerMatcher.matches(*Node.getSubExpr(), Finder, Builder); } @@ -548,7 +555,8 @@ } // namespace /// Scan the function and return a list of gadgets found with provided kits. -static std::tuple findGadgets(const Decl *D) { +static std::tuple +findGadgets(const Decl *D, const Preprocessor &PP) { struct GadgetFinderCallback : MatchFinder::MatchCallback { FixableGadgetList FixableGadgets; @@ -620,7 +628,7 @@ stmt(anyOf( // Add Gadget::matcher() for every gadget in the registry. #define WARNING_GADGET(x) \ - x ## Gadget::matcher().bind(#x), + allOf(x ## Gadget::matcher().bind(#x), notInSafeBufferOptOut(&PP)), #include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def" // In parallel, match all DeclRefExprs so that to find out // whether there are any uncovered by gadgets. @@ -1009,7 +1017,7 @@ DeclUseTracker Tracker; { - auto [FixableGadgets, WarningGadgets, TrackerRes] = findGadgets(D); + auto [FixableGadgets, WarningGadgets, TrackerRes] = findGadgets(D, Handler.getPP()); UnsafeOps = groupWarningGadgetsByVar(std::move(WarningGadgets)); FixablesForUnsafeVars = groupFixablesByVar(std::move(FixableGadgets)); Tracker = std::move(TrackerRes); diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -333,6 +333,15 @@ assert(!CurTokenLexer && "Ending a file when currently in a macro!"); + SourceLocation UnclosedSafeBufferOptOutLoc; + + if (IncludeMacroStack.empty() && + isPPInSafeBufferOptOutRegion(UnclosedSafeBufferOptOutLoc)) { + // To warn if a "-Wunsafe-buffer-usage" opt-out region is still open by the + // end of a file. + Diag(UnclosedSafeBufferOptOutLoc, + diag::err_pp_unclosed_pragma_unsafe_buffer_usage); + } // If we have an unclosed module region from a pragma at the end of a // module, complain and close it now. const bool LeavingSubmodule = CurLexer && CurLexerSubmodule; diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1243,6 +1243,32 @@ #endif }; +struct PragmaUnsafeBufferUsageHandler : public PragmaHandler { + PragmaUnsafeBufferUsageHandler() : PragmaHandler("unsafe_buffer_usage") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &FirstToken) override { + Token Tok; + + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok, diag::err_pp_pragma_unsafe_buffer_usage_syntax); + return; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation Loc = Tok.getLocation(); + + if (II->isStr("begin")) { + if (PP.enterOrExitSafeBufferOptOutRegion(true, Loc)) + PP.Diag(Loc, diag::err_pp_double_begin_pragma_unsafe_buffer_usage); + } else if (II->isStr("end")) { + if (PP.enterOrExitSafeBufferOptOutRegion(false, Loc)) + PP.Diag(Loc, diag::err_pp_unmatched_end_begin_pragma_unsafe_buffer_usage); + } else + PP.Diag(Tok, diag::err_pp_pragma_unsafe_buffer_usage_syntax); + } +}; + /// PragmaDiagnosticHandler - e.g. '\#pragma GCC diagnostic ignored "-Wformat"' struct PragmaDiagnosticHandler : public PragmaHandler { private: @@ -2128,6 +2154,9 @@ ModuleHandler->AddPragma(new PragmaModuleBuildHandler()); ModuleHandler->AddPragma(new PragmaModuleLoadHandler()); + // Safe Buffers pragmas + AddPragmaHandler("clang", new PragmaUnsafeBufferUsageHandler); + // Add region pragmas. AddPragmaHandler(new PragmaRegionHandler("region")); AddPragmaHandler(new PragmaRegionHandler("endregion")); diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -1462,6 +1462,75 @@ Diag(*A.FinalAnnotationLoc, diag::note_pp_macro_annotation) << 2; } +bool Preprocessor::isSafeBufferOptOut(const SourceManager &SourceMgr, + const SourceLocation &Loc) const { + // Try to find a region in `SafeBufferOptOutMap` where `Loc` is in: + auto FirstRegionEndingAfterLoc = llvm::partition_point( + SafeBufferOptOutMap, + [&SourceMgr, + &Loc](const std::pair &Region) { + return SourceMgr.isBeforeInTranslationUnit(Region.second, Loc); + }); + + if (FirstRegionEndingAfterLoc != SafeBufferOptOutMap.end()) { + // To test if the start location of the found region precedes `Loc`: + return SourceMgr.isBeforeInTranslationUnit(FirstRegionEndingAfterLoc->first, + Loc); + } + // If we do not find a region whose end location passes `Loc`, we want to + // check if the current region is still open: + if (!SafeBufferOptOutMap.empty() && + SafeBufferOptOutMap.back().first == SafeBufferOptOutMap.back().second) + return SourceMgr.isBeforeInTranslationUnit(SafeBufferOptOutMap.back().first, + Loc); + return false; +} + +bool Preprocessor::enterOrExitSafeBufferOptOutRegion( + bool isEnter, const SourceLocation &Loc) { + if (isEnter) { + if (isPPInSafeBufferOptOutRegion()) + return true; // invalid enter action + InSafeBufferOptOutRegion = true; + CurrentSafeBufferOptOutStart = Loc; + + // To set the start location of a new region: + + if (!SafeBufferOptOutMap.empty()) { + auto *PrevRegion = &SafeBufferOptOutMap.back(); + assert(PrevRegion->first != PrevRegion->second && + "Shall not begin a safe buffer opt-out region before closing the " + "previous one."); + } + // If the start location equals to the end location, we call the region a + // open region or a unclosed region (i.e., end location has not been set + // yet). + SafeBufferOptOutMap.emplace_back(Loc, Loc); + } else { + if (!isPPInSafeBufferOptOutRegion()) + return true; // invalid enter action + InSafeBufferOptOutRegion = false; + + // To set the end location of the current open region: + + assert(!SafeBufferOptOutMap.empty() && + "Misordered safe buffer opt-out regions"); + auto *CurrRegion = &SafeBufferOptOutMap.back(); + assert(CurrRegion->first == CurrRegion->second && + "Set end location to a closed safe buffer opt-out region"); + CurrRegion->second = Loc; + } + return false; +} + +bool Preprocessor::isPPInSafeBufferOptOutRegion() { + return InSafeBufferOptOutRegion; +} +bool Preprocessor::isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc) { + StartLoc = CurrentSafeBufferOptOutStart; + return InSafeBufferOptOutRegion; +} + ModuleLoader::~ModuleLoader() = default; CommentHandler::~CommentHandler() = default; diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2213,6 +2213,10 @@ FD << F; } } + + const clang::Preprocessor & getPP() const override { + return S.getPreprocessor(); + } }; } // namespace diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-fixit.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-fixit.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-fixit.cpp @@ -0,0 +1,107 @@ +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +void basic(int * x) { + int tmp; + int *p1 = new int[10]; // no fix + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + int *p2 = new int[10]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p2" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" +#pragma clang unsafe_buffer_usage begin + tmp = p1[5]; +#pragma clang unsafe_buffer_usage end + tmp = p2[5]; +} + +void withDiagnosticWarning() { + int tmp; + int *p1 = new int[10]; // no fix + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + int *p2 = new int[10]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p2" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" + + // diagnostics in opt-out region +#pragma clang unsafe_buffer_usage begin + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wunsafe-buffer-usage" + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang diagnostic warning "-Weverything" + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang diagnostic pop +#pragma clang unsafe_buffer_usage end + + // opt-out region under diagnostic warning +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wunsafe-buffer-usage" +#pragma clang unsafe_buffer_usage begin + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang unsafe_buffer_usage end +#pragma clang diagnostic pop + + tmp = p2[5]; +} + + +void withDiagnosticIgnore() { + int tmp; + int *p1 = new int[10]; + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: + int *p2 = new int[10]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p2" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" + int *p3 = new int[10]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p3" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" + +#pragma clang unsafe_buffer_usage begin + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang diagnostic ignored "-Weverything" + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang diagnostic pop +#pragma clang unsafe_buffer_usage end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#pragma clang unsafe_buffer_usage begin + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang unsafe_buffer_usage end +#pragma clang diagnostic pop + + tmp = p2[5]; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#pragma clang unsafe_buffer_usage begin + tmp = p1[5]; // not to warn + tmp = p2[5]; // not to warn +#pragma clang unsafe_buffer_usage end + tmp = p3[5]; // expected-note{{used in buffer access here}} +#pragma clang diagnostic pop +} + +void noteGoesWithVarDeclWarning() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + int *p = new int[10]; // not to warn + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]: +#pragma clang diagnostic pop + + p[5]; // not to note since the associated warning is suppressed +} diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-misuse.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-misuse.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma-misuse.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -verify %s + +void beginUnclosed(int * x) { +#pragma clang unsafe_buffer_usage begin + +#pragma clang unsafe_buffer_usage begin // expected-error{{already inside '#pragma unsafe_buffer_usage'}} + x++; +#pragma clang unsafe_buffer_usage end +} + +void endUnopened(int *x) { +#pragma clang unsafe_buffer_usage end // expected-error{{not currently inside '#pragma unsafe_buffer_usage'}} + +#pragma clang unsafe_buffer_usage begin + x++; +#pragma clang unsafe_buffer_usage end +} + +void wrongOption() { +#pragma clang unsafe_buffer_usage start // expected-error{{Expected 'begin' or 'end'}} +#pragma clang unsafe_buffer_usage close // expected-error{{Expected 'begin' or 'end'}} +} + +void unclosed(int * p1) { +#pragma clang unsafe_buffer_usage begin +// End of the included file will not raise the unclosed region warning: +#define _INCLUDE_NO_WARN +#include "warn-unsafe-buffer-usage-pragma.h" +#pragma clang unsafe_buffer_usage end + +// End of this file raises the warning: +#pragma clang unsafe_buffer_usage begin // expected-error{{'#pragma unsafe_buffer_usage' was not ended}} +} diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.h b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.h new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.h @@ -0,0 +1,14 @@ +#ifdef _INCLUDE_NO_WARN +// the snippet will be included in an opt-out region +p1++; + +#undef _INCLUDE_NO_WARN + +#elif defined(_INCLUDE_WARN) +// the snippet will be included in a location where warnings are expected +p2++; // expected-note{{used in pointer arithmetic here}} +#undef _INCLUDE_WARN + +#else + +#endif diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-pragma.cpp @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -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 + int *p2 = new int[10]; // expected-warning{{'p2' is an unsafe pointer used for buffer access}} + +#pragma clang unsafe_buffer_usage begin + p1[5]; // not to warn + +#define _INCLUDE_NO_WARN +#include "warn-unsafe-buffer-usage-pragma.h" // increment p1 in header + + int *p3 = new int[10]; // expected-warning{{'p3' is an unsafe pointer used for buffer access}} + +#pragma clang unsafe_buffer_usage end + p2[5]; //expected-note{{used in buffer access here}} + p3[5]; //expected-note{{used in buffer access here}} + x++; //expected-note{{used in pointer arithmetic here}} +#define _INCLUDE_WARN +#include "warn-unsafe-buffer-usage-pragma.h" // increment p2 in header +} + + +void withDiagnosticWarning() { + int *p1 = new int[10]; // not to warn + int *p2 = new int[10]; // expected-warning{{'p2' is an unsafe pointer used for buffer access}} + + // diagnostics in opt-out region +#pragma clang unsafe_buffer_usage begin + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wunsafe-buffer-usage" + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang diagnostic warning "-Weverything" + p1[5]; // not to warn expected-warning{{expression result unused}} + p2[5]; // not to warn expected-warning{{expression result unused}} +#pragma clang diagnostic pop +#pragma clang unsafe_buffer_usage end + + // opt-out region under diagnostic warning +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wunsafe-buffer-usage" +#pragma clang unsafe_buffer_usage begin + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang unsafe_buffer_usage end +#pragma clang diagnostic pop + + p2[5]; // expected-note{{used in buffer access here}} +} + + +void withDiagnosticIgnore() { + int *p1 = new int[10]; // not to warn + int *p2 = new int[10]; // expected-warning{{'p2' is an unsafe pointer used for buffer access}} + int *p3 = new int[10]; // expected-warning{{'p3' is an unsafe pointer used for buffer access}} + +#pragma clang unsafe_buffer_usage begin + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang diagnostic ignored "-Weverything" + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang diagnostic pop +#pragma clang unsafe_buffer_usage end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#pragma clang unsafe_buffer_usage begin + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang unsafe_buffer_usage end +#pragma clang diagnostic pop + + p2[5]; // expected-note{{used in buffer access here}} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" +#pragma clang unsafe_buffer_usage begin + p1[5]; // not to warn + p2[5]; // not to warn +#pragma clang unsafe_buffer_usage end + p3[5]; // expected-note{{used in buffer access here}} +#pragma clang diagnostic pop +} + +void noteGoesWithVarDeclWarning() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + int *p = new int[10]; // not to warn +#pragma clang diagnostic pop + + p[5]; // not to note since the associated warning is suppressed +}