[libc++] Always define a key function for std::bad_function_call in the dylib

However, whether applications rely on the std::bad_function_call vtable
being in the dylib is still controlled by the ABI macro, since changing
that would be an ABI break.

Also separate preprocessor definitions for whether to use a key function
and whether to use a `bad_function_call`-specific `what` message
(`what` message is mandated by [LWG2233](http://wg21.link/LWG2233)).

Differential Revision: https://reviews.llvm.org/D92397

GitOrigin-RevId: 434dc0a5bcae50e87458e893ae5469619a35839e
diff --git a/include/__config b/include/__config
index 779a33c..e537fe7 100644
--- a/include/__config
+++ b/include/__config
@@ -82,6 +82,11 @@
 // its vtable and typeinfo to libc++ rather than having all other libraries
 // using that class define their own copies.
 #  define _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
+// Override the default return value of exception::what() for
+// bad_function_call::what() with a string that is specific to
+// bad_function_call (see http://wg21.link/LWG2233). This is an ABI break
+// because it changes the vtable layout of bad_function_call.
+#  define _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE
 // Enable optimized version of __do_get_(un)signed which avoids redundant copies.
 #  define _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
 // In C++20 and later, don't derive std::plus from std::binary_function,
@@ -127,6 +132,11 @@
 // reduces the number of weak definitions generated in programs that use
 // iostreams by providing a single strong definition in the shared library.
 # define _LIBCPP_ABI_ENABLE_ADDITIONAL_IOSTREAM_EXPLICIT_INSTANTIATIONS_1
+
+// Define a key function for `bad_function_call` in the library, to centralize
+// its vtable and typeinfo to libc++ rather than having all other libraries
+// using that class define their own copies.
+#  define _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
 #endif
 
 #define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y
diff --git a/include/__functional/function.h b/include/__functional/function.h
index dff44fc..83fd7c1 100644
--- a/include/__functional/function.h
+++ b/include/__functional/function.h
@@ -35,10 +35,17 @@
 class _LIBCPP_EXCEPTION_ABI bad_function_call
     : public exception
 {
-#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
 public:
+// Note that when a key function is not used, every translation unit that uses
+// bad_function_call will end up containing a weak definition of the vtable and
+// typeinfo.
+#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION
     virtual ~bad_function_call() _NOEXCEPT;
+#else
+    virtual ~bad_function_call() _NOEXCEPT {}
+#endif
 
+#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE
     virtual const char* what() const _NOEXCEPT;
 #endif
 };
diff --git a/lib/abi/CHANGELOG.TXT b/lib/abi/CHANGELOG.TXT
index af9c305..06cdb9f 100644
--- a/lib/abi/CHANGELOG.TXT
+++ b/lib/abi/CHANGELOG.TXT
@@ -13,6 +13,38 @@
 New entries should be added directly below the "Version" header.
 
 ------------
+Version 14.0
+------------
+
+* [libc++] Always define a key function for std::bad_function_call in the dylib
+
+  This commit added a new explicit instantiation of std::bad_function_call's
+  vtable in the shared library. This change is not an ABI break as it only
+  adds symbols to the library. Programs compiled against the library will not
+  rely on the vtable being defined in it by default. Reliance on the vtable
+  being in the shared library can be enabled by defining the
+  _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION macro.
+
+  x86_64-apple-apple-darwin
+  -------------------------
+  Symbol added: __ZNSt3__117bad_function_callD0Ev
+  Symbol added: __ZNSt3__117bad_function_callD1Ev
+  Symbol added: __ZNSt3__117bad_function_callD2Ev
+  Symbol added: __ZTINSt3__117bad_function_callE
+  Symbol added: __ZTSNSt3__117bad_function_callE
+  Symbol added: __ZTVNSt3__117bad_function_callE
+
+  x86_64-unknown-linux-gnu
+  ------------------------
+  Symbol added: _ZNKSt9exception4whatEv
+  Symbol added: _ZNSt3__117bad_function_callD0Ev
+  Symbol added: _ZNSt3__117bad_function_callD1Ev
+  Symbol added: _ZNSt3__117bad_function_callD2Ev
+  Symbol added: _ZTINSt3__117bad_function_callE
+  Symbol added: _ZTSNSt3__117bad_function_callE
+  Symbol added: _ZTVNSt3__117bad_function_callE
+
+------------
 Version 12.0
 ------------
 
diff --git a/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist b/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
index f2dbb6e..f037b1b 100644
--- a/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
+++ b/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
@@ -1482,6 +1482,9 @@
 {'is_defined': True, 'name': '__ZNSt3__117__widen_from_utf8ILm32EED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117__widen_from_utf8ILm32EED1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117__widen_from_utf8ILm32EED2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__117bad_function_callD0Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__117bad_function_callD1Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__117bad_function_callD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117declare_reachableEPv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117iostream_categoryEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIcLb0EE4initEPKc', 'type': 'FUNC'}
@@ -2025,6 +2028,7 @@
 {'is_defined': True, 'name': '__ZTINSt3__117__assoc_sub_stateE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117__widen_from_utf8ILm16EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117__widen_from_utf8ILm32EEE', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTINSt3__117bad_function_callE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117moneypunct_bynameIcLb0EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117moneypunct_bynameIcLb1EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117moneypunct_bynameIwLb0EEE', 'size': 0, 'type': 'OBJECT'}
@@ -2198,6 +2202,7 @@
 {'is_defined': True, 'name': '__ZTSNSt3__115time_get_bynameIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__115time_put_bynameIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__115time_put_bynameIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEE', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTSNSt3__117bad_function_callE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__117moneypunct_bynameIcLb0EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__117moneypunct_bynameIcLb1EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__117moneypunct_bynameIwLb0EEE', 'size': 0, 'type': 'OBJECT'}
@@ -2398,6 +2403,7 @@
 {'is_defined': True, 'name': '__ZTVNSt3__117__assoc_sub_stateE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117__widen_from_utf8ILm16EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117__widen_from_utf8ILm32EEE', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTVNSt3__117bad_function_callE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117moneypunct_bynameIcLb0EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117moneypunct_bynameIcLb1EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117moneypunct_bynameIwLb0EEE', 'size': 0, 'type': 'OBJECT'}
diff --git a/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist b/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
index 17739ea..2318cb4 100644
--- a/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
+++ b/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
@@ -1482,6 +1482,9 @@
 {'is_defined': True, 'name': '__ZNSt3__117__widen_from_utf8ILm32EED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117__widen_from_utf8ILm32EED1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117__widen_from_utf8ILm32EED2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__117bad_function_callD0Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__117bad_function_callD1Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__117bad_function_callD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117declare_reachableEPv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117iostream_categoryEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIcLb0EE4initEPKc', 'type': 'FUNC'}
@@ -2037,6 +2040,7 @@
 {'is_defined': True, 'name': '__ZTINSt3__117__assoc_sub_stateE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117__widen_from_utf8ILm16EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117__widen_from_utf8ILm32EEE', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTINSt3__117bad_function_callE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117moneypunct_bynameIcLb0EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117moneypunct_bynameIcLb1EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTINSt3__117moneypunct_bynameIwLb0EEE', 'size': 0, 'type': 'OBJECT'}
@@ -2223,6 +2227,7 @@
 {'is_defined': True, 'name': '__ZTSNSt3__115time_get_bynameIwNS_19istreambuf_iteratorIwNS_11char_traitsIwEEEEEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__115time_put_bynameIcNS_19ostreambuf_iteratorIcNS_11char_traitsIcEEEEEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__115time_put_bynameIwNS_19ostreambuf_iteratorIwNS_11char_traitsIwEEEEEE', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTSNSt3__117bad_function_callE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__117moneypunct_bynameIcLb0EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__117moneypunct_bynameIcLb1EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTSNSt3__117moneypunct_bynameIwLb0EEE', 'size': 0, 'type': 'OBJECT'}
@@ -2428,6 +2433,7 @@
 {'is_defined': True, 'name': '__ZTVNSt3__117__assoc_sub_stateE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117__widen_from_utf8ILm16EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117__widen_from_utf8ILm32EEE', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTVNSt3__117bad_function_callE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117moneypunct_bynameIcLb0EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117moneypunct_bynameIcLb1EEE', 'size': 0, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '__ZTVNSt3__117moneypunct_bynameIwLb0EEE', 'size': 0, 'type': 'OBJECT'}
diff --git a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
index fd20a7d..c815c44 100644
--- a/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
+++ b/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.no_new_in_libcxx.abilist
@@ -1,5 +1,6 @@
 {'is_defined': False, 'name': '_ZNKSt11logic_error4whatEv', 'type': 'FUNC'}
 {'is_defined': False, 'name': '_ZNKSt13runtime_error4whatEv', 'type': 'FUNC'}
+{'is_defined': False, 'name': '_ZNKSt9exception4whatEv', 'type': 'FUNC'}
 {'is_defined': False, 'name': '_ZNSt11logic_errorD2Ev', 'type': 'FUNC'}
 {'is_defined': False, 'name': '_ZNSt12length_errorD1Ev', 'type': 'FUNC'}
 {'is_defined': False, 'name': '_ZNSt12out_of_rangeD1Ev', 'type': 'FUNC'}
@@ -1172,6 +1173,9 @@
 {'is_defined': True, 'name': '_ZNSt3__117__widen_from_utf8ILm32EED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__117__widen_from_utf8ILm32EED1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__117__widen_from_utf8ILm32EED2Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__117bad_function_callD0Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__117bad_function_callD1Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__117bad_function_callD2Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__117declare_reachableEPv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__117iostream_categoryEv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIcLb0EE4initEPKc', 'type': 'FUNC'}
@@ -1703,6 +1707,7 @@
 {'is_defined': True, 'name': '_ZTINSt3__117__assoc_sub_stateE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__117__widen_from_utf8ILm16EEE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__117__widen_from_utf8ILm32EEE', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTINSt3__117bad_function_callE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__117moneypunct_bynameIcLb0EEE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__117moneypunct_bynameIcLb1EEE', 'size': 24, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTINSt3__117moneypunct_bynameIwLb0EEE', 'size': 24, 'type': 'OBJECT'}
@@ -1832,6 +1837,7 @@
 {'is_defined': True, 'name': '_ZTSNSt3__117__assoc_sub_stateE', 'size': 28, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__117__widen_from_utf8ILm16EEE', 'size': 35, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__117__widen_from_utf8ILm32EEE', 'size': 35, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSNSt3__117bad_function_callE', 'size': 28, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__117moneypunct_bynameIcLb0EEE', 'size': 35, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__117moneypunct_bynameIcLb1EEE', 'size': 35, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTSNSt3__117moneypunct_bynameIwLb0EEE', 'size': 35, 'type': 'OBJECT'}
@@ -1962,6 +1968,7 @@
 {'is_defined': True, 'name': '_ZTVNSt3__117__assoc_sub_stateE', 'size': 48, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__117__widen_from_utf8ILm16EEE', 'size': 96, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__117__widen_from_utf8ILm32EEE', 'size': 96, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVNSt3__117bad_function_callE', 'size': 40, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__117moneypunct_bynameIcLb0EEE', 'size': 112, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__117moneypunct_bynameIcLb1EEE', 'size': 112, 'type': 'OBJECT'}
 {'is_defined': True, 'name': '_ZTVNSt3__117moneypunct_bynameIwLb0EEE', 'size': 112, 'type': 'OBJECT'}
diff --git a/src/functional.cpp b/src/functional.cpp
index cc5f43a..fbc6200 100644
--- a/src/functional.cpp
+++ b/src/functional.cpp
@@ -14,7 +14,9 @@
 bad_function_call::~bad_function_call() noexcept
 {
 }
+#endif
 
+#ifdef _LIBCPP_ABI_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE
 const char*
 bad_function_call::what() const noexcept
 {
diff --git a/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/copy.pass.cpp b/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/copy.pass.cpp
index d5af63a..b79f9c9 100644
--- a/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/copy.pass.cpp
+++ b/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/copy.pass.cpp
@@ -6,7 +6,18 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03
+// Address Sanitizer doesn't instrument weak symbols on Linux. When a key
+// function is defined for bad_function_call's vtable, its typeinfo and vtable
+// will be defined as strong symbols in the library and weak symbols in other
+// translation units. Only the strong symbol will be instrumented, increasing
+// its size (due to the redzone) and leading to a serious ODR violation
+// resulting in a crash.
+// Some relevant bugs:
+// https://github.com/google/sanitizers/issues/1017
+// https://github.com/google/sanitizers/issues/619
+// https://github.com/google/sanitizers/issues/398
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68016
+// UNSUPPORTED: c++03, asan
 // XFAIL: LIBCXX-AIX-FIXME
 
 // <functional>
diff --git a/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp b/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp
index 6797014..de8e8e2 100644
--- a/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp
+++ b/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.inv/invoke.pass.cpp
@@ -15,6 +15,19 @@
 // This test runs in C++03, but we have deprecated using std::function in C++03.
 // ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
 
+// Address Sanitizer doesn't instrument weak symbols on Linux. When a key
+// function is defined for bad_function_call's vtable, its typeinfo and vtable
+// will be defined as strong symbols in the library and weak symbols in other
+// translation units. Only the strong symbol will be instrumented, increasing
+// its size (due to the redzone) and leading to a serious ODR violation
+// resulting in a crash.
+// Some relevant bugs:
+// https://github.com/google/sanitizers/issues/1017
+// https://github.com/google/sanitizers/issues/619
+// https://github.com/google/sanitizers/issues/398
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68016
+// UNSUPPORTED: asan
+
 #include <functional>
 #include <cassert>
 
diff --git a/test/std/utilities/function.objects/func.wrap/func.wrap.func/robust_against_adl.pass.cpp b/test/std/utilities/function.objects/func.wrap/func.wrap.func/robust_against_adl.pass.cpp
index f831ec7..23e4776 100644
--- a/test/std/utilities/function.objects/func.wrap/func.wrap.func/robust_against_adl.pass.cpp
+++ b/test/std/utilities/function.objects/func.wrap/func.wrap.func/robust_against_adl.pass.cpp
@@ -6,7 +6,18 @@
 //
 //===----------------------------------------------------------------------===//
 
-// UNSUPPORTED: c++03
+// Address Sanitizer doesn't instrument weak symbols on Linux. When a key
+// function is defined for bad_function_call's vtable, its typeinfo and vtable
+// will be defined as strong symbols in the library and weak symbols in other
+// translation units. Only the strong symbol will be instrumented, increasing
+// its size (due to the redzone) and leading to a serious ODR violation
+// resulting in a crash.
+// Some relevant bugs:
+// https://github.com/google/sanitizers/issues/1017
+// https://github.com/google/sanitizers/issues/619
+// https://github.com/google/sanitizers/issues/398
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68016
+// UNSUPPORTED: c++03, asan
 
 // <functional>