[Libc++] Use #pragma push_macro/pop_macro to better handle min/max on Windows

Summary:
This patch improves how libc++ handles min/max macros within the headers. Previously libc++ would undef them and emit a warning.
This patch changes libc++ to use `#pragma push_macro`  to save the macro before undefining it, and `#pragma pop_macro` to restore the macros and the end of the header.

Reviewers: mclow.lists, bcraig, compnerd, EricWF

Reviewed By: EricWF

Subscribers: cfe-commits, krytarowski

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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@304357 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/__bit_reference b/include/__bit_reference
index 9aea961..3e4a21d 100644
--- a/include/__bit_reference
+++ b/include/__bit_reference
@@ -14,12 +14,14 @@
 #include <__config>
 #include <algorithm>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Cp, bool _IsConst, typename _Cp::__storage_type = 0> class __bit_iterator;
@@ -1273,4 +1275,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP___BIT_REFERENCE
diff --git a/include/__config b/include/__config
index 32e542b..ec00790 100644
--- a/include/__config
+++ b/include/__config
@@ -1205,4 +1205,34 @@
 #define _LIBCPP_AVAILABILITY_NO_STREAMS_EXTERN_TEMPLATE
 #endif
 
+#if defined(_LIBCPP_COMPILER_IBM)
+#define _LIBCPP_HAS_NO_PRAGMA_PUSH_POP_MACRO
+#endif
+
+#if defined(_LIBCPP_HAS_NO_PRAGMA_PUSH_POP_MACRO)
+# define _LIBCPP_PUSH_MACROS
+# define _LIBCPP_POP_MACROS
+#else
+  // Don't warn about macro conflicts when we can restore them at the
+  // end of the header.
+# ifndef _LIBCPP_DISABLE_MACRO_CONFLICT_WARNINGS
+#   define _LIBCPP_DISABLE_MACRO_CONFLICT_WARNINGS
+# endif
+# if defined(_LIBCPP_COMPILER_MSVC)
+#   define _LIBCPP_PUSH_MACROS    \
+      __pragma(push_macro("min")) \
+      __pragma(push_macro("max"))
+#   define _LIBCPP_POP_MACROS     \
+      __pragma(pop_macro("min"))  \
+      __pragma(pop_macro("max"))
+# else
+#   define _LIBCPP_PUSH_MACROS        \
+      _Pragma("push_macro(\"min\")")  \
+      _Pragma("push_macro(\"max\")")
+#   define _LIBCPP_POP_MACROS         \
+      _Pragma("pop_macro(\"min\")")   \
+      _Pragma("pop_macro(\"max\")")
+# endif
+#endif // defined(_LIBCPP_HAS_NO_PRAGMA_PUSH_POP_MACRO)
+
 #endif // _LIBCPP_CONFIG
diff --git a/include/__hash_table b/include/__hash_table
index acdc443..79336ff 100644
--- a/include/__hash_table
+++ b/include/__hash_table
@@ -20,17 +20,18 @@
 #include <utility>
 #include <type_traits>
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
-_LIBCPP_BEGIN_NAMESPACE_STD
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
 
 
+_LIBCPP_BEGIN_NAMESPACE_STD
+
 #ifndef _LIBCPP_CXX03_LANG
 template <class _Key, class _Tp>
 union __hash_value_type;
@@ -2667,6 +2668,9 @@
 }
 
 #endif  // _LIBCPP_DEBUG_LEVEL >= 2
+
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP__HASH_TABLE
diff --git a/include/__mutex_base b/include/__mutex_base
index 7f5e2ea..159acd6 100644
--- a/include/__mutex_base
+++ b/include/__mutex_base
@@ -15,12 +15,16 @@
 #include <chrono>
 #include <system_error>
 #include <__threading_support>
-#include <__undef_min_max>
+
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #ifndef _LIBCPP_HAS_NO_THREADS
@@ -428,4 +432,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP___MUTEX_BASE
diff --git a/include/__split_buffer b/include/__split_buffer
index 72073f0..1daa4e5 100644
--- a/include/__split_buffer
+++ b/include/__split_buffer
@@ -6,12 +6,14 @@
 #include <type_traits>
 #include <algorithm>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <bool>
@@ -628,7 +630,8 @@
     __x.swap(__y);
 }
 
-
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_SPLIT_BUFFER
diff --git a/include/__std_stream b/include/__std_stream
index fb5a346..db90795 100644
--- a/include/__std_stream
+++ b/include/__std_stream
@@ -17,12 +17,14 @@
 #include <__locale>
 #include <cstdio>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 static const int __limit = 8;
@@ -355,4 +357,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP___STD_STREAM
diff --git a/include/__string b/include/__string
index 75608ce..d30c7fd 100644
--- a/include/__string
+++ b/include/__string
@@ -57,14 +57,16 @@
 #include <cstdio>     // For EOF.
 #include <memory>     // for __murmur2_or_cityhash
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 // char_traits
@@ -870,4 +872,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP___STRING
diff --git a/include/__threading_support b/include/__threading_support
index afd7cb5..5d4c907 100644
--- a/include/__threading_support
+++ b/include/__threading_support
@@ -30,9 +30,12 @@
 #include <windows.h>
 #include <process.h>
 #include <fibersapi.h>
-#include <__undef_min_max>
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \
     defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)
 #define _LIBCPP_THREAD_ABI_VISIBILITY _LIBCPP_FUNC_VIS
@@ -629,6 +632,8 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // !_LIBCPP_HAS_NO_THREADS
 
 #endif // _LIBCPP_THREADING_SUPPORT
diff --git a/include/__tree b/include/__tree
index 6771589..792870a 100644
--- a/include/__tree
+++ b/include/__tree
@@ -17,12 +17,14 @@
 #include <stdexcept>
 #include <algorithm>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp, class _Compare, class _Allocator> class __tree;
@@ -2685,4 +2687,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP___TREE
diff --git a/include/__undef_min_max b/include/__undef_macros
similarity index 80%
rename from include/__undef_min_max
rename to include/__undef_macros
index 71db396..60ab1db 100644
--- a/include/__undef_min_max
+++ b/include/__undef_macros
@@ -1,13 +1,14 @@
 // -*- C++ -*-
-//===----------------------------------------------------------------------===//
+//===------------------------ __undef_macros ------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 
+
 #ifdef min
 #if !defined(_LIBCPP_DISABLE_MACRO_CONFLICT_WARNINGS)
 #if defined(_LIBCPP_WARNING)
diff --git a/include/algorithm b/include/algorithm
index 7144050..9fe0361 100644
--- a/include/algorithm
+++ b/include/algorithm
@@ -651,14 +651,16 @@
 #include <intrin.h>
 #endif
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 // I'd like to replace these with _VSTD::equal_to<void>, but can't because:
@@ -5904,4 +5906,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_ALGORITHM
diff --git a/include/array b/include/array
index 31f5501..79f7e0d 100644
--- a/include/array
+++ b/include/array
@@ -113,6 +113,8 @@
 #pragma GCC system_header
 #endif
 
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp, size_t _Size>
diff --git a/include/bitset b/include/bitset
index b49c93c..583122f 100644
--- a/include/bitset
+++ b/include/bitset
@@ -113,10 +113,6 @@
 
 */
 
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
-#endif
-
 #include <__config>
 #include <__bit_reference>
 #include <cstddef>
@@ -126,7 +122,13 @@
 #include <iosfwd>
 #include <__functional_base>
 
-#include <__undef_min_max>
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
@@ -1090,4 +1092,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_BITSET
diff --git a/include/chrono b/include/chrono
index 6578087..4b793c7 100644
--- a/include/chrono
+++ b/include/chrono
@@ -305,12 +305,14 @@
 #include <ratio>
 #include <limits>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace chrono
@@ -1160,4 +1162,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_CHRONO
diff --git a/include/deque b/include/deque
index bd43164..f795b48 100644
--- a/include/deque
+++ b/include/deque
@@ -150,10 +150,6 @@
 
 */
 
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
-#endif
-
 #include <__config>
 #include <__split_buffer>
 #include <type_traits>
@@ -162,7 +158,13 @@
 #include <algorithm>
 #include <stdexcept>
 
-#include <__undef_min_max>
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
@@ -2900,4 +2902,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_DEQUE
diff --git a/include/experimental/algorithm b/include/experimental/algorithm
index b32d7ca..3801cae 100644
--- a/include/experimental/algorithm
+++ b/include/experimental/algorithm
@@ -39,17 +39,18 @@
 #include <algorithm>
 #include <type_traits>
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
-_LIBCPP_BEGIN_NAMESPACE_LFTS
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
 
 
+_LIBCPP_BEGIN_NAMESPACE_LFTS
+
 template <class _ForwardIterator, class _Searcher>
 _LIBCPP_INLINE_VISIBILITY
 _ForwardIterator search(_ForwardIterator __f, _ForwardIterator __l, const _Searcher &__s)
@@ -67,4 +68,6 @@
 
 _LIBCPP_END_NAMESPACE_LFTS
 
+_LIBCPP_POP_MACROS
+
 #endif /* _LIBCPP_EXPERIMENTAL_ALGORITHM */
diff --git a/include/experimental/dynarray b/include/experimental/dynarray
index f96a0e5..1619331 100644
--- a/include/experimental/dynarray
+++ b/include/experimental/dynarray
@@ -107,6 +107,9 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 namespace std { namespace experimental { inline namespace __array_extensions_v1 {
 
 template <class _Tp>
@@ -295,5 +298,7 @@
 struct _LIBCPP_TEMPLATE_VIS uses_allocator<std::experimental::dynarray<_Tp>, _Alloc> : true_type {};
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // if _LIBCPP_STD_VER > 11 
 #endif  // _LIBCPP_DYNARRAY
diff --git a/include/experimental/functional b/include/experimental/functional
index 75fc8e9..a136cbb 100644
--- a/include/experimental/functional
+++ b/include/experimental/functional
@@ -89,21 +89,22 @@
 
 #include <experimental/__config>
 #include <functional>
-
 #include <algorithm>
 #include <type_traits>
 #include <vector>
 #include <array>
 #include <unordered_map>
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_LFTS
 
 #if _LIBCPP_STD_VER > 11
@@ -456,4 +457,6 @@
 
 _LIBCPP_END_NAMESPACE_LFTS
 
+_LIBCPP_POP_MACROS
+
 #endif /* _LIBCPP_EXPERIMENTAL_FUNCTIONAL */
diff --git a/include/experimental/memory_resource b/include/experimental/memory_resource
index 743f9cb..d101f3e 100644
--- a/include/experimental/memory_resource
+++ b/include/experimental/memory_resource
@@ -82,6 +82,9 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
 
 // Round __s up to next multiple of __a.
@@ -419,4 +422,6 @@
 
 _LIBCPP_END_NAMESPACE_LFTS_PMR
 
+_LIBCPP_POP_MACROS
+
 #endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */
diff --git a/include/experimental/numeric b/include/experimental/numeric
index 6488a68..d784c08 100644
--- a/include/experimental/numeric
+++ b/include/experimental/numeric
@@ -41,6 +41,9 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 #if _LIBCPP_STD_VER > 11
 
 _LIBCPP_BEGIN_NAMESPACE_LFTS_V2
@@ -110,4 +113,7 @@
 _LIBCPP_END_NAMESPACE_LFTS_V2
 
 #endif /* _LIBCPP_STD_VER > 11 */
+
+_LIBCPP_POP_MACROS
+
 #endif /* _LIBCPP_EXPERIMENTAL_NUMERIC */
diff --git a/include/experimental/optional b/include/experimental/optional
index 48adfba..b251748 100644
--- a/include/experimental/optional
+++ b/include/experimental/optional
@@ -143,6 +143,21 @@
 #include <experimental/__config>
 #include <functional>
 #include <stdexcept>
+#if _LIBCPP_STD_VER > 11
+#include <initializer_list>
+#include <type_traits>
+#include <new>
+#include <__functional_base>
+#include <__debug>
+#endif
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 
 _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL
 class _LIBCPP_EXCEPTION_ABI _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS bad_optional_access
@@ -160,17 +175,6 @@
 
 #if _LIBCPP_STD_VER > 11
 
-#include <initializer_list>
-#include <type_traits>
-#include <new>
-#include <__functional_base>
-#include <__undef_min_max>
-#include <__debug>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
-#endif
-
 _LIBCPP_BEGIN_NAMESPACE_LFTS
 
 struct in_place_t {};
@@ -913,4 +917,6 @@
 
 #endif  // _LIBCPP_STD_VER > 11
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_EXPERIMENTAL_OPTIONAL
diff --git a/include/experimental/string_view b/include/experimental/string_view
index 41c0d34..da104f9 100644
--- a/include/experimental/string_view
+++ b/include/experimental/string_view
@@ -189,6 +189,9 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_LFTS
 
     template<class _CharT, class _Traits = _VSTD::char_traits<_CharT> >
@@ -810,4 +813,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // _LIBCPP_LFTS_STRING_VIEW
diff --git a/include/forward_list b/include/forward_list
index e4ab41e..8bfa9a0 100644
--- a/include/forward_list
+++ b/include/forward_list
@@ -167,19 +167,20 @@
 */
 
 #include <__config>
-
 #include <initializer_list>
 #include <memory>
 #include <limits>
 #include <iterator>
 #include <algorithm>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp, class _VoidPtr> struct __forward_list_node;
@@ -1719,4 +1720,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_FORWARD_LIST
diff --git a/include/fstream b/include/fstream
index 5ec42bd..e41a53a 100644
--- a/include/fstream
+++ b/include/fstream
@@ -171,12 +171,14 @@
 #include <__locale>
 #include <cstdio>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _CharT, class _Traits>
@@ -1476,4 +1478,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_FSTREAM
diff --git a/include/istream b/include/istream
index 530f204..0b8e05d 100644
--- a/include/istream
+++ b/include/istream
@@ -162,12 +162,14 @@
 #include <__config>
 #include <ostream>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _CharT, class _Traits>
@@ -1683,4 +1685,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_ISTREAM
diff --git a/include/limits b/include/limits
index 4755c57..675cfc4 100644
--- a/include/limits
+++ b/include/limits
@@ -102,15 +102,8 @@
 
 */
 #include <__config>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
-#endif
-
 #include <type_traits>
 
-#include <__undef_min_max>
-
 #if defined(_LIBCPP_COMPILER_MSVC)
 #include "support/win32/limits_msvc_win32.h"
 #endif // _LIBCPP_MSVCRT
@@ -119,6 +112,14 @@
 #include "support/ibm/limits.h"
 #endif // __IBMCPP__
 
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 enum float_round_style
@@ -811,4 +812,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_LIMITS
diff --git a/include/list b/include/list
index 5e76d11..20a66c3 100644
--- a/include/list
+++ b/include/list
@@ -177,14 +177,16 @@
 #include <algorithm>
 #include <type_traits>
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Tp, class _VoidPtr> struct __list_node;
@@ -2415,4 +2417,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_LIST
diff --git a/include/locale b/include/locale
index d29a2dc..bdedbea 100644
--- a/include/locale
+++ b/include/locale
@@ -208,18 +208,20 @@
 #include <Availability.h>
 #endif
 
-#include <__undef_min_max>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
-#endif
-
 #ifdef _LIBCPP_LOCALE__L_EXTENSIONS
 #include <__bsd_locale_defaults.h>
 #else
 #include <__bsd_locale_fallbacks.h>
 #endif
 
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #if defined(__APPLE__) || defined(__FreeBSD__)
@@ -4274,4 +4276,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_LOCALE
diff --git a/include/memory b/include/memory
index 31dc73d..b12b46a 100644
--- a/include/memory
+++ b/include/memory
@@ -658,12 +658,14 @@
 #  include <atomic>
 #endif
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _ValueType>
@@ -5574,4 +5576,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_MEMORY
diff --git a/include/module.modulemap b/include/module.modulemap
index 98b1870..3194b5c 100644
--- a/include/module.modulemap
+++ b/include/module.modulemap
@@ -484,7 +484,7 @@
   module __string { header "__string" export * }
   module __tree { header "__tree" export * }
   module __tuple { header "__tuple" export * }
-  module __undef_min_max { header "__undef_min_max" export * }
+  module __undef_macros { header "__undef_macros" export * }
 
   module experimental {
     requires cplusplus11
diff --git a/include/mutex b/include/mutex
index 0b25614..5538088 100644
--- a/include/mutex
+++ b/include/mutex
@@ -196,12 +196,14 @@
 #endif
 #include <__threading_support>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 #ifndef _LIBCPP_HAS_NO_THREADS
@@ -696,4 +698,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_MUTEX
diff --git a/include/numeric b/include/numeric
index 9c98cdb..0e53ba3 100644
--- a/include/numeric
+++ b/include/numeric
@@ -71,6 +71,9 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _InputIterator, class _Tp>
@@ -267,4 +270,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_NUMERIC
diff --git a/include/optional b/include/optional
index 70b6eb4..8c8ee76 100644
--- a/include/optional
+++ b/include/optional
@@ -146,7 +146,6 @@
 #include <__config>
 #include <__debug>
 #include <__functional_base>
-#include <__undef_min_max>
 #include <functional>
 #include <initializer_list>
 #include <new>
@@ -158,6 +157,10 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 namespace std  // purposefully not using versioning namespace
 {
 
@@ -1315,4 +1318,6 @@
 
 #endif  // _LIBCPP_STD_VER > 14
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_OPTIONAL
diff --git a/include/random b/include/random
index c6dfb66..ba8a088 100644
--- a/include/random
+++ b/include/random
@@ -1646,12 +1646,14 @@
 #include <istream>
 #include <ostream>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 // __is_seed_sequence
@@ -6736,4 +6738,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_RANDOM
diff --git a/include/ratio b/include/ratio
index fa89363..27aa0de 100644
--- a/include/ratio
+++ b/include/ratio
@@ -83,12 +83,14 @@
 #include <climits>
 #include <type_traits>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 // __static_gcd
@@ -520,4 +522,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_RATIO
diff --git a/include/regex b/include/regex
index 0f49b95..443c2e3 100644
--- a/include/regex
+++ b/include/regex
@@ -765,12 +765,14 @@
 #include <vector>
 #include <deque>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace regex_constants
@@ -6562,4 +6564,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_REGEX
diff --git a/include/shared_mutex b/include/shared_mutex
index ff36ee6..9cb8152 100644
--- a/include/shared_mutex
+++ b/include/shared_mutex
@@ -125,12 +125,14 @@
 
 #include <__config>
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 #if _LIBCPP_STD_VER > 11 || defined(_LIBCPP_BUILDING_SHARED_MUTEX)
 
 #include <__mutex_base>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
@@ -500,4 +502,6 @@
 
 #endif  // _LIBCPP_STD_VER > 11
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_SHARED_MUTEX
diff --git a/include/sstream b/include/sstream
index 4113742..b9903f9 100644
--- a/include/sstream
+++ b/include/sstream
@@ -175,12 +175,14 @@
 #include <istream>
 #include <string>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 // basic_stringbuf
@@ -970,4 +972,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_SSTREAM
diff --git a/include/streambuf b/include/streambuf
index 12eded5..a10ce1b 100644
--- a/include/streambuf
+++ b/include/streambuf
@@ -116,6 +116,9 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _CharT, class _Traits>
@@ -486,4 +489,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_STEAMBUF
diff --git a/include/string b/include/string
index af028a0..91df914 100644
--- a/include/string
+++ b/include/string
@@ -484,14 +484,16 @@
 #include <cstdint>
 #endif
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 // fpos
@@ -4041,4 +4043,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_STRING
diff --git a/include/string_view b/include/string_view
index e59f099..75374d2 100644
--- a/include/string_view
+++ b/include/string_view
@@ -166,7 +166,6 @@
 */
 
 #include <__config>
-
 #include <__string>
 #include <algorithm>
 #include <iterator>
@@ -178,6 +177,10 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template<class _CharT, class _Traits = char_traits<_CharT> >
@@ -784,4 +787,6 @@
 #endif
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif // _LIBCPP_STRING_VIEW
diff --git a/include/thread b/include/thread
index 360b43d..1b8dca3 100644
--- a/include/thread
+++ b/include/thread
@@ -105,6 +105,9 @@
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
 #define __STDCPP_THREADS__ __cplusplus
 
 #ifdef _LIBCPP_HAS_NO_THREADS
@@ -476,4 +479,6 @@
 
 #endif // !_LIBCPP_HAS_NO_THREADS
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_THREAD
diff --git a/include/valarray b/include/valarray
index f8e19ac..ee61238 100644
--- a/include/valarray
+++ b/include/valarray
@@ -347,12 +347,14 @@
 #include <functional>
 #include <new>
 
-#include <__undef_min_max>
-
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template<class _Tp> class _LIBCPP_TEMPLATE_VIS valarray;
@@ -4865,4 +4867,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_VALARRAY
diff --git a/include/vector b/include/vector
index 6759dbd..ee19fb7 100644
--- a/include/vector
+++ b/include/vector
@@ -275,14 +275,16 @@
 #include <__split_buffer>
 #include <__functional_base>
 
-#include <__undef_min_max>
-
 #include <__debug>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
 #endif
 
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <bool>
@@ -3357,4 +3359,6 @@
 
 _LIBCPP_END_NAMESPACE_STD
 
+_LIBCPP_POP_MACROS
+
 #endif  // _LIBCPP_VECTOR
diff --git a/src/condition_variable.cpp b/src/condition_variable.cpp
index 3f60727..2200aef 100644
--- a/src/condition_variable.cpp
+++ b/src/condition_variable.cpp
@@ -14,6 +14,7 @@
 #include "condition_variable"
 #include "thread"
 #include "system_error"
+#include "__undef_macros"
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
diff --git a/src/ios.cpp b/src/ios.cpp
index 7c76ca2..0f1d88e 100644
--- a/src/ios.cpp
+++ b/src/ios.cpp
@@ -22,6 +22,7 @@
 #include "new"
 #include "streambuf"
 #include "string"
+#include "__undef_macros"
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
diff --git a/src/locale.cpp b/src/locale.cpp
index 4163c2c..3d61fbe 100644
--- a/src/locale.cpp
+++ b/src/locale.cpp
@@ -36,6 +36,7 @@
 #endif
 #include <stdlib.h>
 #include <stdio.h>
+#include "__undef_macros"
 
 // On Linux, wint_t and wchar_t have different signed-ness, and this causes
 // lots of noise in the build log, but no bugs that I know of. 
diff --git a/src/mutex.cpp b/src/mutex.cpp
index b858e88..c36bd55 100644
--- a/src/mutex.cpp
+++ b/src/mutex.cpp
@@ -12,6 +12,7 @@
 #include "limits"
 #include "system_error"
 #include "include/atomic_support.h"
+#include "__undef_macros"
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 #ifndef _LIBCPP_HAS_NO_THREADS
diff --git a/src/strstream.cpp b/src/strstream.cpp
index be94f9c..01523cf 100644
--- a/src/strstream.cpp
+++ b/src/strstream.cpp
@@ -13,6 +13,7 @@
 #include "cstring"
 #include "cstdlib"
 #include "__debug"
+#include "__undef_macros"
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
diff --git a/test/libcxx/min_max_macros.sh.cpp b/test/libcxx/min_max_macros.sh.cpp
new file mode 100644
index 0000000..bae4175
--- /dev/null
+++ b/test/libcxx/min_max_macros.sh.cpp
@@ -0,0 +1,298 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Test that we can include each header in two TU's and link them together.
+
+// RUN: %compile -fsyntax-only
+
+// Prevent <ext/hash_map> from generating deprecated warnings for this test.
+#if defined(__DEPRECATED)
+#undef __DEPRECATED
+#endif
+
+#define TEST_MACROS() static_assert(min() == true && max() == true, "")
+#define min() true
+#define max() true
+
+// Top level headers
+#include <algorithm>
+TEST_MACROS();
+#include <any>
+TEST_MACROS();
+#include <array>
+TEST_MACROS();
+#ifndef _LIBCPP_HAS_NO_THREADS
+#include <atomic>
+TEST_MACROS();
+#endif
+#include <bitset>
+TEST_MACROS();
+#include <cassert>
+TEST_MACROS();
+#include <ccomplex>
+TEST_MACROS();
+#include <cctype>
+TEST_MACROS();
+#include <cerrno>
+TEST_MACROS();
+#include <cfenv>
+TEST_MACROS();
+#include <cfloat>
+TEST_MACROS();
+#include <chrono>
+TEST_MACROS();
+#include <cinttypes>
+TEST_MACROS();
+#include <ciso646>
+TEST_MACROS();
+#include <climits>
+TEST_MACROS();
+#include <clocale>
+TEST_MACROS();
+#include <cmath>
+TEST_MACROS();
+#include <codecvt>
+TEST_MACROS();
+#include <complex>
+TEST_MACROS();
+#include <complex.h>
+TEST_MACROS();
+#include <condition_variable>
+TEST_MACROS();
+#include <csetjmp>
+TEST_MACROS();
+#include <csignal>
+TEST_MACROS();
+#include <cstdarg>
+TEST_MACROS();
+#include <cstdbool>
+TEST_MACROS();
+#include <cstddef>
+TEST_MACROS();
+#include <cstdint>
+TEST_MACROS();
+#include <cstdio>
+TEST_MACROS();
+#include <cstdlib>
+TEST_MACROS();
+#include <cstring>
+TEST_MACROS();
+#include <ctgmath>
+TEST_MACROS();
+#include <ctime>
+TEST_MACROS();
+#include <ctype.h>
+TEST_MACROS();
+#include <cwchar>
+TEST_MACROS();
+#include <cwctype>
+TEST_MACROS();
+#include <deque>
+TEST_MACROS();
+#include <errno.h>
+TEST_MACROS();
+#include <exception>
+TEST_MACROS();
+#include <float.h>
+TEST_MACROS();
+#include <forward_list>
+TEST_MACROS();
+#include <fstream>
+TEST_MACROS();
+#include <functional>
+TEST_MACROS();
+#ifndef _LIBCPP_HAS_NO_THREADS
+#include <future>
+TEST_MACROS();
+#endif
+#include <initializer_list>
+TEST_MACROS();
+#include <inttypes.h>
+TEST_MACROS();
+#include <iomanip>
+TEST_MACROS();
+#include <ios>
+TEST_MACROS();
+#include <iosfwd>
+TEST_MACROS();
+#include <iostream>
+TEST_MACROS();
+#include <istream>
+TEST_MACROS();
+#include <iterator>
+TEST_MACROS();
+#include <limits>
+TEST_MACROS();
+#include <limits.h>
+TEST_MACROS();
+#include <list>
+TEST_MACROS();
+#include <locale>
+TEST_MACROS();
+#include <locale.h>
+TEST_MACROS();
+#include <map>
+TEST_MACROS();
+#include <math.h>
+TEST_MACROS();
+#include <memory>
+TEST_MACROS();
+#ifndef _LIBCPP_HAS_NO_THREADS
+#include <mutex>
+TEST_MACROS();
+#endif
+#include <new>
+TEST_MACROS();
+#include <numeric>
+TEST_MACROS();
+#include <optional>
+TEST_MACROS();
+#include <ostream>
+TEST_MACROS();
+#include <queue>
+TEST_MACROS();
+#include <random>
+TEST_MACROS();
+#include <ratio>
+TEST_MACROS();
+#include <regex>
+TEST_MACROS();
+#include <scoped_allocator>
+TEST_MACROS();
+#include <set>
+TEST_MACROS();
+#include <setjmp.h>
+TEST_MACROS();
+#ifndef _LIBCPP_HAS_NO_THREADS
+#include <shared_mutex>
+TEST_MACROS();
+#endif
+#include <sstream>
+TEST_MACROS();
+#include <stack>
+TEST_MACROS();
+#include <stdbool.h>
+TEST_MACROS();
+#include <stddef.h>
+TEST_MACROS();
+#include <stdexcept>
+TEST_MACROS();
+#include <stdint.h>
+TEST_MACROS();
+#include <stdio.h>
+TEST_MACROS();
+#include <stdlib.h>
+TEST_MACROS();
+#include <streambuf>
+TEST_MACROS();
+#include <string>
+TEST_MACROS();
+#include <string.h>
+TEST_MACROS();
+#include <string_view>
+TEST_MACROS();
+#include <strstream>
+TEST_MACROS();
+#include <system_error>
+TEST_MACROS();
+#include <tgmath.h>
+TEST_MACROS();
+#ifndef _LIBCPP_HAS_NO_THREADS
+#include <thread>
+TEST_MACROS();
+#endif
+#include <tuple>
+TEST_MACROS();
+#include <typeindex>
+TEST_MACROS();
+#include <typeinfo>
+TEST_MACROS();
+#include <type_traits>
+TEST_MACROS();
+#include <unordered_map>
+TEST_MACROS();
+#include <unordered_set>
+TEST_MACROS();
+#include <utility>
+TEST_MACROS();
+#include <valarray>
+TEST_MACROS();
+#include <variant>
+TEST_MACROS();
+#include <vector>
+TEST_MACROS();
+#include <wchar.h>
+TEST_MACROS();
+#include <wctype.h>
+TEST_MACROS();
+
+// experimental headers
+#if __cplusplus >= 201103L
+#include <experimental/algorithm>
+TEST_MACROS();
+#include <experimental/any>
+TEST_MACROS();
+#include <experimental/chrono>
+TEST_MACROS();
+#include <experimental/deque>
+TEST_MACROS();
+#include <experimental/dynarray>
+TEST_MACROS();
+#include <experimental/filesystem>
+TEST_MACROS();
+#include <experimental/forward_list>
+TEST_MACROS();
+#include <experimental/functional>
+TEST_MACROS();
+#include <experimental/iterator>
+TEST_MACROS();
+#include <experimental/list>
+TEST_MACROS();
+#include <experimental/map>
+TEST_MACROS();
+#include <experimental/memory_resource>
+TEST_MACROS();
+#include <experimental/numeric>
+TEST_MACROS();
+#include <experimental/optional>
+TEST_MACROS();
+#include <experimental/propagate_const>
+TEST_MACROS();
+#include <experimental/ratio>
+TEST_MACROS();
+#include <experimental/regex>
+TEST_MACROS();
+#include <experimental/set>
+TEST_MACROS();
+#include <experimental/string>
+TEST_MACROS();
+#include <experimental/string_view>
+TEST_MACROS();
+#include <experimental/system_error>
+TEST_MACROS();
+#include <experimental/tuple>
+TEST_MACROS();
+#include <experimental/type_traits>
+TEST_MACROS();
+#include <experimental/unordered_map>
+TEST_MACROS();
+#include <experimental/unordered_set>
+TEST_MACROS();
+#include <experimental/utility>
+TEST_MACROS();
+#include <experimental/vector>
+TEST_MACROS();
+#endif // __cplusplus >= 201103L
+
+// extended headers
+#include <ext/hash_map>
+TEST_MACROS();
+#include <ext/hash_set>
+TEST_MACROS();