summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikolas Klauser <nikolasklauser@berlin.de>2023-02-01 16:04:53 +0100
committerTobias Hieta <tobias@hieta.se>2023-03-28 08:55:21 +0200
commit140c68db4fe4d37274c4f3322a058a7a26e45537 (patch)
tree905b0fbee62be1fd96508b606abcade9bf588540
parenta18482ac5089d7eec2321711b2428a2ed63edf02 (diff)
downloadllvm-140c68db4fe4d37274c4f3322a058a7a26e45537.tar.gz
[libc++] Avoid ODR violations in __exception_guard
Having an ODR violation with `__exception_guard` seems to be problematic in LTO builds. To avoid the ODR violation, give the class different names for exception/no-exceptions mode and have an alias to the correct class. Reviewed By: ldionne, #libc, alexfh Spies: aeubanks, dblaikie, joanahalili, alexfh, rupprecht, libcxx-commits Differential Revision: https://reviews.llvm.org/D143071 (cherry picked from commit 1a17739d3aa78599c32f6106e05dcfa7f3f9e823)
-rw-r--r--libcxx/include/__expected/expected.h7
-rw-r--r--libcxx/include/__memory/uninitialized_algorithms.h8
-rw-r--r--libcxx/include/__memory_resource/polymorphic_allocator.h2
-rw-r--r--libcxx/include/__utility/exception_guard.h47
-rw-r--r--libcxx/test/libcxx/utilities/exception_guard.odr.sh.cpp40
5 files changed, 78 insertions, 26 deletions
diff --git a/libcxx/include/__expected/expected.h b/libcxx/include/__expected/expected.h
index e1f590c65efe..ca3e8a59922d 100644
--- a/libcxx/include/__expected/expected.h
+++ b/libcxx/include/__expected/expected.h
@@ -292,7 +292,8 @@ private:
"be reverted to the previous state in case an exception is thrown during the assignment.");
_T2 __tmp(std::move(__oldval));
std::destroy_at(std::addressof(__oldval));
- __exception_guard __trans([&] { std::construct_at(std::addressof(__oldval), std::move(__tmp)); });
+ auto __trans =
+ std::__make_exception_guard([&] { std::construct_at(std::addressof(__oldval), std::move(__tmp)); });
std::construct_at(std::addressof(__newval), std::forward<_Args>(__args)...);
__trans.__complete();
}
@@ -451,7 +452,7 @@ public:
if constexpr (is_nothrow_move_constructible_v<_Err>) {
_Err __tmp(std::move(__with_err.__union_.__unex_));
std::destroy_at(std::addressof(__with_err.__union_.__unex_));
- __exception_guard __trans([&] {
+ auto __trans = std::__make_exception_guard([&] {
std::construct_at(std::addressof(__with_err.__union_.__unex_), std::move(__tmp));
});
std::construct_at(std::addressof(__with_err.__union_.__val_), std::move(__with_val.__union_.__val_));
@@ -464,7 +465,7 @@ public:
"that it can be reverted to the previous state in case an exception is thrown during swap.");
_Tp __tmp(std::move(__with_val.__union_.__val_));
std::destroy_at(std::addressof(__with_val.__union_.__val_));
- __exception_guard __trans([&] {
+ auto __trans = std::__make_exception_guard([&] {
std::construct_at(std::addressof(__with_val.__union_.__val_), std::move(__tmp));
});
std::construct_at(std::addressof(__with_val.__union_.__unex_), std::move(__with_err.__union_.__unex_));
diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h
index 0067780c3f5d..90aecb7d6ad2 100644
--- a/libcxx/include/__memory/uninitialized_algorithms.h
+++ b/libcxx/include/__memory/uninitialized_algorithms.h
@@ -421,7 +421,7 @@ constexpr void __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* _
_Tp& __array = *__loc;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __exception_guard __guard([&]() {
+ auto __guard = std::__make_exception_guard([&]() {
std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
});
@@ -461,7 +461,7 @@ constexpr void __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* _
_Tp& __array = *__loc;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __exception_guard __guard([&]() {
+ auto __guard = std::__make_exception_guard([&]() {
std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
});
for (; __i != extent_v<_Tp>; ++__i) {
@@ -488,7 +488,7 @@ __uninitialized_allocator_fill_n_multidimensional(_Alloc& __alloc, _BidirIter __
_BidirIter __begin = __it;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __exception_guard __guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
+ auto __guard = std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
for (; __n != 0; --__n, ++__it) {
std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it), __value);
}
@@ -505,7 +505,7 @@ __uninitialized_allocator_value_construct_n_multidimensional(_Alloc& __alloc, _B
_BidirIter __begin = __it;
// If an exception is thrown, destroy what we have constructed so far in reverse order.
- __exception_guard __guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
+ auto __guard = std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
for (; __n != 0; --__n, ++__it) {
std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it));
}
diff --git a/libcxx/include/__memory_resource/polymorphic_allocator.h b/libcxx/include/__memory_resource/polymorphic_allocator.h
index 2489502bcdaf..f7b9a0b408c1 100644
--- a/libcxx/include/__memory_resource/polymorphic_allocator.h
+++ b/libcxx/include/__memory_resource/polymorphic_allocator.h
@@ -98,7 +98,7 @@ public:
template <class _Type, class... _CtorArgs>
[[nodiscard]] _Type* new_object(_CtorArgs&&... __ctor_args) {
_Type* __ptr = allocate_object<_Type>();
- __exception_guard __guard([&] { deallocate_object(__ptr); });
+ auto __guard = std::__make_exception_guard([&] { deallocate_object(__ptr); });
construct(__ptr, std::forward<_CtorArgs>(__ctor_args)...);
__guard.__complete();
return __ptr;
diff --git a/libcxx/include/__utility/exception_guard.h b/libcxx/include/__utility/exception_guard.h
index 737d1a69c971..46f9359a5c0e 100644
--- a/libcxx/include/__utility/exception_guard.h
+++ b/libcxx/include/__utility/exception_guard.h
@@ -60,25 +60,26 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_NO_EXCEPTIONS
template <class _Rollback>
-struct __exception_guard {
- __exception_guard() = delete;
+struct __exception_guard_exceptions {
+ __exception_guard_exceptions() = delete;
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __exception_guard(_Rollback __rollback)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit __exception_guard_exceptions(_Rollback __rollback)
: __rollback_(std::move(__rollback)), __completed_(false) {}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __exception_guard(__exception_guard&& __other)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ __exception_guard_exceptions(__exception_guard_exceptions&& __other)
_NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value)
: __rollback_(std::move(__other.__rollback_)), __completed_(__other.__completed_) {
__other.__completed_ = true;
}
- __exception_guard(__exception_guard const&) = delete;
- __exception_guard& operator=(__exception_guard const&) = delete;
- __exception_guard& operator=(__exception_guard&&) = delete;
+ __exception_guard_exceptions(__exception_guard_exceptions const&) = delete;
+ __exception_guard_exceptions& operator=(__exception_guard_exceptions const&) = delete;
+ __exception_guard_exceptions& operator=(__exception_guard_exceptions&&) = delete;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __complete() _NOEXCEPT { __completed_ = true; }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__exception_guard() {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__exception_guard_exceptions() {
if (!__completed_)
__rollback_();
}
@@ -87,36 +88,46 @@ private:
_Rollback __rollback_;
bool __completed_;
};
+
+_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__exception_guard_exceptions);
+
+template <class _Rollback>
+using __exception_guard = __exception_guard_exceptions<_Rollback>;
#else // _LIBCPP_NO_EXCEPTIONS
template <class _Rollback>
-struct __exception_guard {
- __exception_guard() = delete;
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG explicit __exception_guard(_Rollback) {}
+struct __exception_guard_noexceptions {
+ __exception_guard_noexceptions() = delete;
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+ _LIBCPP_NODEBUG explicit __exception_guard_noexceptions(_Rollback) {}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG __exception_guard(__exception_guard&& __other)
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG
+ __exception_guard_noexceptions(__exception_guard_noexceptions&& __other)
_NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value)
: __completed_(__other.__completed_) {
__other.__completed_ = true;
}
- __exception_guard(__exception_guard const&) = delete;
- __exception_guard& operator=(__exception_guard const&) = delete;
- __exception_guard& operator=(__exception_guard&&) = delete;
+ __exception_guard_noexceptions(__exception_guard_noexceptions const&) = delete;
+ __exception_guard_noexceptions& operator=(__exception_guard_noexceptions const&) = delete;
+ __exception_guard_noexceptions& operator=(__exception_guard_noexceptions&&) = delete;
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG void __complete() _NOEXCEPT {
__completed_ = true;
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG ~__exception_guard() {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG ~__exception_guard_noexceptions() {
_LIBCPP_ASSERT(__completed_, "__exception_guard not completed with exceptions disabled");
}
private:
bool __completed_ = false;
};
-#endif // _LIBCPP_NO_EXCEPTIONS
-_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__exception_guard);
+_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__exception_guard_noexceptions);
+
+template <class _Rollback>
+using __exception_guard = __exception_guard_noexceptions<_Rollback>;
+#endif // _LIBCPP_NO_EXCEPTIONS
template <class _Rollback>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __exception_guard<_Rollback> __make_exception_guard(_Rollback __rollback) {
diff --git a/libcxx/test/libcxx/utilities/exception_guard.odr.sh.cpp b/libcxx/test/libcxx/utilities/exception_guard.odr.sh.cpp
new file mode 100644
index 000000000000..07bbdbb8bc2f
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/exception_guard.odr.sh.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Make sure that we don't get ODR violations with __exception_guard when
+// linking together TUs compiled with different values of -f[no-]exceptions.
+
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -o %t.except.o -O1 -Wno-private-header -fexceptions
+// RUN: %{cxx} %s %{flags} %{compile_flags} -c -o %t.noexcept.o -O1 -Wno-private-header -fno-exceptions
+// RUN: %{cxx} %{flags} %{link_flags} -o %t.exe %t.except.o %t.noexcept.o
+// RUN: %{run}
+
+#include <__utility/exception_guard.h>
+#include <cassert>
+#include <cstring>
+#include <typeinfo>
+
+struct Rollback {
+ void operator()() {}
+};
+
+#if defined(__cpp_exceptions) && __cpp_exceptions >= 199711L
+
+const char* func();
+
+int main(int, char**) {
+ assert(std::strcmp(typeid(std::__exception_guard<Rollback>).name(), func()) != 0);
+
+ return 0;
+}
+
+#else
+
+const char* func() { return typeid(std::__exception_guard<Rollback>).name(); }
+
+#endif