Fix std::pointer_safety type in ABI v2

In the C++ standard `std::pointer_safety` is defined
as a C++11 strongly typed enum. However libc++ currently defines
it as a class type which simulates a C++11 enumeration. This
can be detected in valid C++ code.

This patch introduces an the _LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE ABI option.
When defined `std::pointer_safety` is implemented as an enum type.
Unfortunatly this also means it can no longer be provided as an extension
in C++03.

Additionally this patch moves the definition for `get_pointer_safety()`
out of the dylib, and into the headers. New usages of `get_pointer_safety()`
will now use the inline version instead of the dylib version. However in
order to keep the dylib ABI compatible the old definition is explicitly
compiled into it.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@291046 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/__config b/include/__config
index 08ca88b..ffd37c1 100644
--- a/include/__config
+++ b/include/__config
@@ -52,6 +52,11 @@
 // provided under the alternate keyword __nullptr, which changes the mangling
 // of nullptr_t. This option is ABI incompatible with GCC in C++03 mode.
 #define _LIBCPP_ABI_ALWAYS_USE_CXX11_NULLPTR
+// Define the `pointer_safety` enum as a C++11 strongly typed enumeration
+// instead of as a class simulating an enum. If this option is enabled
+// `pointer_safety` and `get_pointer_safety()` will no longer be available
+// in C++03.
+#define _LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE
 #elif _LIBCPP_ABI_VERSION == 1
 #if !defined(_WIN32)
 // Enable compiling a definition of error_category() into the libc++ dylib.
diff --git a/include/memory b/include/memory
index d851295..3ea9a77 100644
--- a/include/memory
+++ b/include/memory
@@ -5616,6 +5616,15 @@
 #endif  // !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER)
 
 //enum class
+#if defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE)
+# ifndef _LIBCPP_CXX03_LANG
+enum class pointer_safety : unsigned char {
+  relaxed,
+  preferred,
+  strict
+};
+# endif
+#else
 struct _LIBCPP_TYPE_VIS pointer_safety
 {
     enum __lx
@@ -5632,11 +5641,25 @@
     _LIBCPP_INLINE_VISIBILITY
     operator int() const {return __v_;}
 };
+#endif
+
+#if !defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE) && \
+    defined(_LIBCPP_BUILDING_MEMORY)
+_LIBCPP_FUNC_VIS pointer_safety get_pointer_safety() _NOEXCEPT;
+#else
+// This function is only offered in C++03 under ABI v1.
+# if !defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE) || !defined(_LIBCPP_CXX03_LANG)
+inline _LIBCPP_INLINE_VISIBILITY
+pointer_safety get_pointer_safety() _NOEXCEPT {
+  return pointer_safety::relaxed;
+}
+# endif
+#endif
+
 
 _LIBCPP_FUNC_VIS void declare_reachable(void* __p);
 _LIBCPP_FUNC_VIS void declare_no_pointers(char* __p, size_t __n);
 _LIBCPP_FUNC_VIS void undeclare_no_pointers(char* __p, size_t __n);
-_LIBCPP_FUNC_VIS pointer_safety get_pointer_safety() _NOEXCEPT;
 _LIBCPP_FUNC_VIS void* __undeclare_reachable(void* __p);
 
 template <class _Tp>
diff --git a/src/memory.cpp b/src/memory.cpp
index 514a2ce..8569faf 100644
--- a/src/memory.cpp
+++ b/src/memory.cpp
@@ -220,11 +220,12 @@
 {
 }
 
-pointer_safety
-get_pointer_safety() _NOEXCEPT
+#if !defined(_LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE)
+pointer_safety get_pointer_safety() _NOEXCEPT
 {
     return pointer_safety::relaxed;
 }
+#endif
 
 void*
 __undeclare_reachable(void* p)
diff --git a/test/libcxx/utilities/memory/util.dynamic.safety/get_pointer_safety_cxx03.pass.cpp b/test/libcxx/utilities/memory/util.dynamic.safety/get_pointer_safety_cxx03.pass.cpp
new file mode 100644
index 0000000..04671c3
--- /dev/null
+++ b/test/libcxx/utilities/memory/util.dynamic.safety/get_pointer_safety_cxx03.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <memory>
+
+// pointer_safety get_pointer_safety();
+
+#include <memory>
+#include <cassert>
+
+int main()
+{
+  // Test that std::pointer_safety is still offered in C++03 under the old ABI.
+#ifndef _LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE
+    std::pointer_safety r = std::get_pointer_safety();
+    assert(r == std::pointer_safety::relaxed ||
+           r == std::pointer_safety::preferred ||
+           r == std::pointer_safety::strict);
+#endif
+}
diff --git a/test/libcxx/utilities/memory/util.dynamic.safety/get_pointer_safety_new_abi.pass.cpp b/test/libcxx/utilities/memory/util.dynamic.safety/get_pointer_safety_new_abi.pass.cpp
new file mode 100644
index 0000000..752edb6
--- /dev/null
+++ b/test/libcxx/utilities/memory/util.dynamic.safety/get_pointer_safety_new_abi.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// <memory>
+
+// pointer_safety get_pointer_safety();
+
+// The pointer_safety interface is no longer provided in C++03 in the new ABI.
+// XFAIL: c++98, c++03
+
+// MODULES_DEFINES: _LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE
+#define _LIBCPP_ABI_POINTER_SAFETY_ENUM_TYPE
+#include <memory>
+#include <cassert>
+
+int main()
+{
+  {
+    static_assert(std::is_enum<std::pointer_safety>::value, "");
+    static_assert(!std::is_convertible<std::pointer_safety, int>::value, "");
+    static_assert(std::is_same<
+        std::underlying_type<std::pointer_safety>::type,
+        unsigned char
+    >::value, "");
+  }
+  {
+    std::pointer_safety r = std::get_pointer_safety();
+    assert(r == std::pointer_safety::relaxed ||
+           r == std::pointer_safety::preferred ||
+           r == std::pointer_safety::strict);
+  }
+}
diff --git a/test/std/utilities/memory/util.dynamic.safety/get_pointer_safety.pass.cpp b/test/std/utilities/memory/util.dynamic.safety/get_pointer_safety.pass.cpp
index 1f27b45..ee2f817 100644
--- a/test/std/utilities/memory/util.dynamic.safety/get_pointer_safety.pass.cpp
+++ b/test/std/utilities/memory/util.dynamic.safety/get_pointer_safety.pass.cpp
@@ -11,6 +11,8 @@
 
 // pointer_safety get_pointer_safety();
 
+// UNSUPPORTED: c++98, c++03
+
 #include <memory>
 #include <cassert>