[libcxx-commits] [libcxx] [libc++] Make sure LWG2070 is implemented as a DR (PR #65998)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Sep 13 12:53:15 PDT 2023


================
@@ -321,7 +323,9 @@ struct __shared_ptr_emplace
             allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem());
         }
 #else
-        __get_elem()->~_Tp();
+        using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type;
----------------
ldionne wrote:

You make a great point about this `#ifdef` being in a virtual function, which could lead to ODR violations if two TUs both contain a definition of the function but are compiled with different standard modes. We can't drop the `#if` entirely because `if constexpr` doesn't work before C++17, and this code needs to work all the way back to C++03.

That being said, any ODR violation would necessarily be benign, so I don't think this really has been a problem. Indeed, `__for_overwrite_tag` is only passed when `allocate_shared_for_overwrite` is used, and that function is only provided in C++20 mode. Hence, in a TU compiled with C++17 and earlier, this function would always be as follows (if we used the same definition in all standard modes):

```
if constexpr (false) {
    __get_elem()->~_Tp();
} else {
    using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type;
    _TpAlloc __tmp(*__get_alloc());
    allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem());
}
```

So whether the linker decides to select that function or the function defined as

```
using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type;
_TpAlloc __tmp(*__get_alloc());
allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem());
```

is irrelevant. That being said, I think it's easy to fix this problem so I'll do it in this patch. And this certainly was a good catch!

https://github.com/llvm/llvm-project/pull/65998


More information about the libcxx-commits mailing list