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 @@ -1716,7 +1716,7 @@ // `Init` a pointer to the initializer expression // `Ctx` a reference to the ASTContext static FixItList -populateInitializerFixItWithSpan(const Expr *Init, ASTContext &Ctx, +FixVarInitializerWithSpan(const Expr *Init, ASTContext &Ctx, const StringRef UserFillPlaceHolder) { const SourceManager &SM = Ctx.getSourceManager(); const LangOptions &LangOpts = Ctx.getLangOpts(); @@ -1827,59 +1827,67 @@ } // For a `VarDecl` of the form `T * var (= Init)?`, this -// function generates a fix-it for the declaration, which re-declares `var` to -// be of `span` type and transforms the initializer, if present, to a span -// constructor---`span var {Init, Extent}`, where `Extent` may need the user -// to fill in. +// function generates fix-its that +// 1) replace `T * var` with `std::span var`; and +// 2) change `Init` accordingly to a span constructor, if it exists. // // FIXME: support Multi-level pointers // // Parameters: // `D` a pointer the variable declaration node // `Ctx` a reference to the ASTContext +// `UserFillPlaceHolder` the user-input placeholder text // Returns: -// the generated fix-it -static FixItList fixVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, - const StringRef UserFillPlaceHolder, - UnsafeBufferUsageHandler &Handler) { - (void)Handler; // Suppress unused variable warning in release builds. - const QualType &SpanEltT = D->getType()->getPointeeType(); - assert(!SpanEltT.isNull() && "Trying to fix a non-pointer type variable!"); - +// the non-empty fix-it list, if fix-its are successfuly generated; empty +// list otherwise. +static FixItList fixLocalVarDeclWithSpan(const VarDecl *D, ASTContext &Ctx, + const StringRef UserFillPlaceHolder, + UnsafeBufferUsageHandler &Handler) { FixItList FixIts{}; - std::optional - ReplacementLastLoc; // the inclusive end location of the replacement - const SourceManager &SM = Ctx.getSourceManager(); + std::optional SpanTyText = createSpanTypeForVarDecl(D, Ctx); + + if (!SpanTyText) { + DEBUG_NOTE_DECL_FAIL(D, " : failed to generate 'std::span' type"); + return {}; + } + // Will hold the text for `std::span Ident`: + std::stringstream SS; + + SS << *SpanTyText; + // Append qualifiers to the type of `D`, if any: + if (D->getType().hasQualifiers()) + SS << " " << D->getType().getQualifiers().getAsString(); + + // The end of the range of the original source that will be replaced + // by `std::span ident`: + SourceLocation EndLocForReplacement = D->getEndLoc(); + std::optional IdentText = + getVarDeclIdentifierText(D, Ctx.getSourceManager(), Ctx.getLangOpts()); + + if (!IdentText) { + DEBUG_NOTE_DECL_FAIL(D, " : failed to locate the identifier"); + return {}; + } + // Fix the initializer if it exists: if (const Expr *Init = D->getInit()) { FixItList InitFixIts = - populateInitializerFixItWithSpan(Init, Ctx, UserFillPlaceHolder); - - if (InitFixIts.empty()) { - DEBUG_NOTE_DECL_FAIL(D, " : empty initializer"); + FixVarInitializerWithSpan(Init, Ctx, UserFillPlaceHolder); + if (InitFixIts.empty()) return {}; - } - - // The loc right before the initializer: - ReplacementLastLoc = Init->getBeginLoc().getLocWithOffset(-1); FixIts.insert(FixIts.end(), std::make_move_iterator(InitFixIts.begin()), std::make_move_iterator(InitFixIts.end())); - } else - ReplacementLastLoc = getEndCharLoc(D, SM, Ctx.getLangOpts()); - - // Producing fix-it for variable declaration---make `D` to be of span type: - SmallString<32> Replacement; - raw_svector_ostream OS(Replacement); - - OS << "std::span<" << SpanEltT.getAsString() << "> " << D->getName(); - - if (!ReplacementLastLoc) { - DEBUG_NOTE_DECL_FAIL(D, " : failed to get end char loc (macro)"); + // If the declaration has the form `T *ident = init`, we want to replace + // `T *ident = ` with `std::span ident`: + EndLocForReplacement = Init->getBeginLoc().getLocWithOffset(-1); + } + SS << " " << IdentText->str(); + if (!EndLocForReplacement.isValid()) { + DEBUG_NOTE_DECL_FAIL(D, " : failed to locate the end of the declaration"); return {}; } - FixIts.push_back(FixItHint::CreateReplacement( - SourceRange{D->getBeginLoc(), *ReplacementLastLoc}, OS.str())); + SourceRange(D->getBeginLoc(), EndLocForReplacement), SS.str())); return FixIts; } @@ -2139,8 +2147,7 @@ (void)DS; // FIXME: handle cases where DS has multiple declarations - return fixVarDeclWithSpan(VD, Ctx, getUserFillPlaceHolder(), - Handler); + return fixLocalVarDeclWithSpan(VD, Ctx, getUserFillPlaceHolder(), Handler); } // TODO: we should be consistent to use `std::nullopt` to represent no-fix due diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-local-var-span.cpp @@ -4,53 +4,66 @@ typedef int * Int_ptr_t; typedef int Int_t; -#define DEFINE_PTR(X) int* ptr = (X); - void local_array_subscript_simple() { int tmp; 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}" + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"std::span p" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:12-[[@LINE-2]]:12}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:23-[[@LINE-3]]:23}:", 10}" const int *q = new int[10]; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::span q" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:"{" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:29}:", 10}" + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::span q" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:18-[[@LINE-2]]:18}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:29-[[@LINE-3]]:29}:", 10}" tmp = p[5]; tmp = q[5]; + // We do not fix the following declaration. Because if the + // definition of `Int_ptr_t` gets changed, the fixed code becomes + // incorrect and may NOT be noticed. + // FIXME: Fix with std::span>? Int_ptr_t x = new int[10]; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:16}:"std::span x" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"{" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}" - Int_ptr_t y = new int; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:16}:"std::span y" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:17-[[@LINE-2]]:17}:"{" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 1}" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] Int_t * z = new int[10]; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span z" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}" + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span z" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}" Int_t * w = new Int_t[10]; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span w" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{" - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}" + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span w" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:15-[[@LINE-2]]:15}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:28-[[@LINE-3]]:28}:", 10}" tmp = x[5]; - tmp = y[5]; // y[5] will crash after being span tmp = z[5]; tmp = w[5]; } void local_array_subscript_auto() { int tmp; + // We do not fix the following declaration because + // that'd cause us to hardcode the element type. + // FIXME: Can we use the C++17 class template argument deduction + // to avoid spelling out the element type? auto 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}" + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] tmp = p[5]; } +void local_variable_qualifiers_specifiers() { + int a[10]; + const int * p = a; + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span p" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:20}:", 10}" + const int * const q = a; + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:24}:"std::span const q" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:25-[[@LINE-2]]:25}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:26-[[@LINE-3]]:26}:", 10}" + int tmp; + tmp = p[5]; + tmp = q[5]; +} + + void local_array_subscript_variable_extent() { int n = 10; int tmp; @@ -102,8 +115,8 @@ int * p; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"std::span p" // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}} - Int_ptr_t q; - // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:14}:"std::span q" + Int_t * q; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span q" // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:{{^3}} tmp = p[5]; tmp = q[5]; @@ -168,15 +181,42 @@ void unsupported_multi_decl(int * x) { int * p = x, * q = new int[10]; - // CHECK-NOT: fix-it:"{{.*}}":[[@LINE-1]] + // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] *p = q[5]; } +void macroVariableIdentifier() { +#define MY_NAME p +#define MY_NAME_ARG(x) q + + // Although fix-its include macros, the macros do not overlap with + // the bounds of the source range of these fix-its. So these fix-its + // are valid. + + int * MY_NAME = new int[10]; + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:18}:"std::span MY_NAME" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:19-[[@LINE-2]]:19}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:30-[[@LINE-3]]:30}:", 10}" + int * MY_NAME_ARG( 'x' ) = new int[10]; + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:29}:"std::span MY_NAME_ARG( 'x' )" + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:30-[[@LINE-2]]:30}:"{" + // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:41-[[@LINE-3]]:41}:", 10}" + p[5] = 5; + q[5] = 5; +#undef MY_NAME +#undef MY_NAME_ARG +} + void unsupported_fixit_overlapping_macro(int * x) { int tmp; // In the case below, a tentative fix-it replaces `MY_INT * p =` with `std::span p `. - // It overlaps with the use of the macro `MY_INT`. The fix-it is - // discarded then. + // The bounds of the source range of the fix-it overlap with the use of the macro + // `MY_INT`. The fix-it is discarded then. + + // FIXME: we do not have to discard a fix-it if its begin location + // overlaps with the begin location of a macro. Similar for end + // locations. + #define MY_INT int MY_INT * p = new int[10]; // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]] @@ -227,6 +267,8 @@ tmp = r[(unsigned int)-1]; // a cast-to-unsigned-expression is also non-negative } +#define DEFINE_PTR(X) int* ptr = (X); + void all_vars_in_macro() { int* local; DEFINE_PTR(local) @@ -239,10 +281,10 @@ ptr[1] = 0; int tmp; ptr[2] = 30; - auto 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 * p = new int[10]; + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"std::span p" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{" + // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}" tmp = p[5]; int val = *p; // CHECK-DAG: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:14}:"" diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-access.cpp @@ -10,7 +10,7 @@ } void condition_check_nullptr() { - auto p = new int[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}" @@ -21,7 +21,7 @@ } void condition_check() { - auto p = new int[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}" @@ -53,12 +53,12 @@ } void condition_check_two_usafe_buffers() { - auto p = new int[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}" - auto q = new int[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}" @@ -72,7 +72,7 @@ } void unsafe_method_invocation_single_param() { - auto p = new int[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}" @@ -84,12 +84,12 @@ } void safe_method_invocation_single_param() { - auto p = new int[10]; + int* p = new int[10]; foo(p); } void unsafe_method_invocation_double_param() { - auto p = new int[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}" @@ -111,7 +111,7 @@ } void unsafe_access_in_lamda() { - auto p = new int[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}" @@ -125,7 +125,7 @@ } void fixits_in_lamda() { - auto p = new int[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}" diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-pointer-deref.cpp @@ -4,7 +4,7 @@ void basic_dereference() { int tmp; - auto p = new int[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}" @@ -15,7 +15,7 @@ } int return_method() { - auto p = new int[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}" @@ -29,7 +29,7 @@ } void method_invocation() { - auto p = new int[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}" @@ -42,7 +42,7 @@ } void binary_operation() { - auto p = new int[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}" diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-fixits-unevaluated-context.cpp @@ -15,7 +15,7 @@ int bar(int *ptr); void uneval_context_fix_pointer_dereference() { - auto p = new int[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}" @@ -30,7 +30,7 @@ } void uneval_context_fix_pointer_array_access() { - auto p = new int[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}" @@ -41,7 +41,7 @@ } void uneval_context_fix_pointer_reference() { - auto p = new int[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}" @@ -63,7 +63,7 @@ // FIXME: Emit fixits for each of the below use. void uneval_context_fix_pointer_dereference_not_handled() { - auto p = new int[10]; + int* p = new int[10]; int tmp = p[5]; foo(sizeof(*p), sizeof(decltype(*p))); diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp @@ -80,28 +80,16 @@ ); } -void testArraySubscriptsWithAuto(int *p, int **pp) { +void testArraySubscriptsWithAuto() { int a[10]; - auto ap1 = a; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}} - + // We do not fix a declaration if the type is `auto`. Because the actual type may change later. + auto ap1 = a; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} foo(ap1[1]); // expected-note{{used in buffer access here}} - auto ap2 = p; // expected-warning{{'ap2' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'ap2' to 'std::span' to preserve bounds information}} - + // In case the type is `auto *`, we know it must be a pointer. We can fix it. + auto * ap2 = a; // expected-warning{{'ap2' is an unsafe pointer used for buffer access}} \ + expected-note{{change type of 'ap2' to 'std::span' to preserve bounds information}} foo(ap2[1]); // expected-note{{used in buffer access here}} - - auto ap3 = pp; // expected-warning{{'ap3' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'ap3' to 'std::span' to preserve bounds information}} - - foo(ap3[1][1]); // expected-note{{used in buffer access here}} - // expected-warning@-1{{unsafe buffer access}} - - auto ap4 = *pp; // expected-warning{{'ap4' is an unsafe pointer used for buffer access}} \ - expected-note{{change type of 'ap4' to 'std::span' to preserve bounds information}} - - foo(ap4[1]); // expected-note{{used in buffer access here}} } void testUnevaluatedContext(int * p) {// no-warning @@ -395,8 +383,9 @@ } void testMultiLineDeclStmt(int * p) { - auto + int + * ap1 = p; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \ expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}}