Skip to content

[clang-tidy] bugprone-unhandled-self-assignment doesn't know about allocator arguments to copy/move constructors #146324

Open
@MikeWeller

Description

@MikeWeller

I may have copy/move constructors that take an additional allocator argument. Additionally, the type may use the leading-allocator convention with std::allocator_arg_t.

If I call one of these "extended" copy/move constructors in my copy/move-and-swap idiom, bugprone-unhandled-self-assignment doesn't recognize it and produces a false positive warning (copy-and-swap/move should not trigger the warning).

A rough test:

// REQUIRES: static-analyzer
// RUN: clang-tidy -checks='-*,bugprone-unhandled-self-assignment' %s --

namespace std {
  namespace pmr {
    template <typename TYPE = void>
    class allocator {};
  }

  struct allocator_arg_t {} allocator_arg;
};

#define LEADING_STYLE 1

class MyValueType
{
  // pointer member to trigger bugprone-unhandled-self-assignment
  void *foo = nullptr;

  public:
    using allocator_type = std::pmr::allocator<>;

    MyValueType(const MyValueType& other)
    {
    }

#ifdef LEADING_STYLE
    MyValueType(std::allocator_arg_t, const allocator_type& alloc, const MyValueType& other)
    {
    }
#else
    MyValueType(const MyValueType& other, const allocator_type& alloc)
    {
    }
#endif

#ifdef LEADING_STYLE
    // CHECK-NOT: warning
    MyValueType& operator=(const MyValueType& other)
    {
        MyValueType tmp(std::allocator_arg, get_allocator(), other);
        swap(tmp);
        return *this;
    }
#else
    // CHECK-NOT: warning
    MyValueType& operator=(const MyValueType& other)
    {
        MyValueType tmp(other, get_allocator());
        swap(tmp);
        return *this;
    }
#endif

    void swap(MyValueType& other) noexcept {
    }

    allocator_type get_allocator() const {
        return allocator_type();
    }
};

Though we're hitting this in our own code, there are examples of these patterns in the standard with e.g. https://en.cppreference.com/w/cpp/container/vector.html which has a trailing allocator overload for its copy ctor and https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2047r5.html for a pmr-aware optional which uses the leading allocator style.

Note that since we call swap we must ensure the tmp we swap with uses the same allocator as us, hence the call to the extended version passing our own allocator.

Also, the allocator_type could be templated in the general case.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions