diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 018f4b99abd1d..40a084a3ee26c 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -366,6 +366,7 @@ isInUnspecifiedUntypedContext(internal::Matcher InnerMatcher) { // 4. `std::span{a, n}`, where `a` is of an array-of-T with constant size // `n` // 5. `std::span{any, 0}` +// 6. `std::span{std::addressof(...), 1}` AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { assert(Node.getNumArgs() == 2 && "expecting a two-parameter std::span constructor"); @@ -410,6 +411,15 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { // Check form 3: return Arg1CV && Arg1CV->isOne(); break; + case Stmt::CallExprClass: + if (const auto *CE = dyn_cast(Arg0)) { + const auto FnDecl = CE->getDirectCallee(); + if (FnDecl && FnDecl->getNameAsString() == "addressof" && + FnDecl->isInStdNamespace()) { + return Arg1CV && Arg1CV->isOne(); + } + } + break; default: break; } diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp index 014aae0e8a4c0..b0174a1e854c0 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp @@ -21,6 +21,12 @@ namespace std { template< class T > T&& move( T&& t ) noexcept; + + template + _Tp* addressof(_Tp& __x) { + return &__x; + } + } namespace irrelevant_constructors { @@ -74,13 +80,24 @@ namespace construct_wt_ptr_size { return std::span{p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } + // addressof method defined outside std namespace. + template + _Tp* addressof(_Tp& __x) { + return &__x; + } + void notWarnSafeCases(unsigned n, int *p) { int X; unsigned Y = 10; std::span S = std::span{&X, 1}; // no-warning + S = std::span{std::addressof(X), 1}; // no-warning int Arr[10]; S = std::span{&X, 2}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{std::addressof(X), 2}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + // Warn when a non std method also named addressof + S = std::span{addressof(X), 1}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{new int[10], 10}; // no-warning S = std::span{new int[n], n}; // no-warning S = std::span{new int, 1}; // no-warning