Skip to content

Commit

Permalink
[libc++] Add availability markup for std::to_chars on Apple platforms
Browse files Browse the repository at this point in the history
Summary:
Otherwise, one gets link errors when trying to back-deploy to older platforms.

rdar://problem/57854364

Reviewers: lichray, EricWF

Subscribers: christof, jkorous, dexonsmith, libcxx-commits

Tags: #libc

Differential Revision: https://reviews.llvm.org/D74626
  • Loading branch information
ldionne committed Feb 19, 2020
1 parent b7d1162 commit da090f6
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 66 deletions.
3 changes: 3 additions & 0 deletions libcxx/include/__config
Expand Up @@ -1419,6 +1419,8 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
_Pragma("clang attribute pop") \
_Pragma("clang attribute pop") \
_Pragma("clang attribute pop")
# define _LIBCPP_AVAILABILITY_TO_CHARS \
_LIBCPP_AVAILABILITY_FILESYSTEM
#else
# define _LIBCPP_AVAILABILITY_SHARED_MUTEX
# define _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
Expand All @@ -1433,6 +1435,7 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
# define _LIBCPP_AVAILABILITY_FILESYSTEM
# define _LIBCPP_AVAILABILITY_FILESYSTEM_PUSH
# define _LIBCPP_AVAILABILITY_FILESYSTEM_POP
# define _LIBCPP_AVAILABILITY_TO_CHARS
#endif

// Define availability that depends on _LIBCPP_NO_EXCEPTIONS.
Expand Down
13 changes: 11 additions & 2 deletions libcxx/include/charconv
Expand Up @@ -73,6 +73,7 @@ namespace std {
*/

#include <__config>
#include <__errc>
#include <type_traits>
#include <limits>
Expand All @@ -92,8 +93,8 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD

namespace __itoa {
_LIBCPP_FUNC_VIS char* __u64toa(uint64_t __value, char* __buffer);
_LIBCPP_FUNC_VIS char* __u32toa(uint32_t __value, char* __buffer);
_LIBCPP_AVAILABILITY_TO_CHARS _LIBCPP_FUNC_VIS char* __u64toa(uint64_t __value, char* __buffer);
_LIBCPP_AVAILABILITY_TO_CHARS _LIBCPP_FUNC_VIS char* __u32toa(uint32_t __value, char* __buffer);
}

#ifndef _LIBCPP_CXX03_LANG
Expand Down Expand Up @@ -167,6 +168,7 @@ struct _LIBCPP_HIDDEN __traits_base
}
#endif

_LIBCPP_AVAILABILITY_TO_CHARS
static _LIBCPP_INLINE_VISIBILITY char* __convert(_Tp __v, char* __p)
{
return __u64toa(__v, __p);
Expand All @@ -189,6 +191,7 @@ struct _LIBCPP_HIDDEN
}
#endif

_LIBCPP_AVAILABILITY_TO_CHARS
static _LIBCPP_INLINE_VISIBILITY char* __convert(_Tp __v, char* __p)
{
return __u32toa(__v, __p);
Expand Down Expand Up @@ -292,6 +295,7 @@ __to_unsigned(_Tp __x)
}

template <typename _Tp>
_LIBCPP_AVAILABILITY_TO_CHARS
inline _LIBCPP_INLINE_VISIBILITY to_chars_result
__to_chars_itoa(char* __first, char* __last, _Tp __value, true_type)
{
Expand All @@ -306,6 +310,7 @@ __to_chars_itoa(char* __first, char* __last, _Tp __value, true_type)
}

template <typename _Tp>
_LIBCPP_AVAILABILITY_TO_CHARS
inline _LIBCPP_INLINE_VISIBILITY to_chars_result
__to_chars_itoa(char* __first, char* __last, _Tp __value, false_type)
{
Expand Down Expand Up @@ -337,6 +342,7 @@ __to_chars_itoa(char* __first, char* __last, _Tp __value, false_type)
}

template <typename _Tp>
_LIBCPP_AVAILABILITY_TO_CHARS
inline _LIBCPP_INLINE_VISIBILITY to_chars_result
__to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
true_type)
Expand All @@ -352,6 +358,7 @@ __to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
}

template <typename _Tp>
_LIBCPP_AVAILABILITY_TO_CHARS
inline _LIBCPP_INLINE_VISIBILITY to_chars_result
__to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
false_type)
Expand Down Expand Up @@ -380,13 +387,15 @@ __to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
}

template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 0>
_LIBCPP_AVAILABILITY_TO_CHARS
inline _LIBCPP_INLINE_VISIBILITY to_chars_result
to_chars(char* __first, char* __last, _Tp __value)
{
return __to_chars_itoa(__first, __last, __value, is_signed<_Tp>());
}

template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 0>
_LIBCPP_AVAILABILITY_TO_CHARS
inline _LIBCPP_INLINE_VISIBILITY to_chars_result
to_chars(char* __first, char* __last, _Tp __value, int __base)
{
Expand Down
@@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++98, c++03
// REQUIRES: availability=macosx10.7 || availability=macosx10.8 || availability=macosx10.9 || availability=macosx10.10 || availability=macosx10.11 || availability=macosx10.12 || availability=macosx10.13 || availability=macosx10.14

// Test the availability markup on std::to_chars.

#include <charconv>

int main(int, char**)
{
char buf[100];
int int_value = 33;
long long_value = 33;
int base = 2;
std::to_chars(buf, buf + 100, int_value); // expected-error{{is unavailable: introduced in}}
std::to_chars(buf, buf + 100, int_value, base); // expected-error{{is unavailable: introduced in}}

std::to_chars(buf, buf + 100, long_value); // expected-error{{is unavailable: introduced in}}
std::to_chars(buf, buf + 100, long_value, base); // expected-error{{is unavailable: introduced in}}
}
Expand Up @@ -10,52 +10,20 @@
// UNSUPPORTED: !libc++ && c++11
// UNSUPPORTED: !libc++ && c++14

// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9
// XFAIL: with_system_cxx_lib=macosx10.8
// XFAIL: with_system_cxx_lib=macosx10.7

// <charconv>

// from_chars_result from_chars(const char* first, const char* last,
// Integral& value, int base = 10)

#include <charconv>
#include "test_macros.h"
#include "charconv_test_helpers.h"

template <typename T>
struct test_basics : roundtrip_test_base<T>
struct test_basics
{
using roundtrip_test_base<T>::test;

void operator()()
{
test(0);
test(42);
test(32768);
test(0, 10);
test(42, 10);
test(32768, 10);
test(0xf, 16);
test(0xdeadbeaf, 16);
test(0755, 8);

for (int b = 2; b < 37; ++b)
{
using xl = std::numeric_limits<T>;

test(1, b);
test(-1, b);
test(xl::lowest(), b);
test((xl::max)(), b);
test((xl::max)() / 2, b);
}

using std::from_chars;
std::from_chars_result r;
T x;

Expand All @@ -65,7 +33,7 @@ struct test_basics : roundtrip_test_base<T>
// the expected form of the subject sequence is a sequence of
// letters and digits representing an integer with the radix
// specified by base (C11 7.22.1.4/3)
r = from_chars(s, s + sizeof(s), x);
r = std::from_chars(s, s + sizeof(s), x);
assert(r.ec == std::errc{});
assert(r.ptr == s + 3);
assert(x == 1);
Expand All @@ -76,22 +44,22 @@ struct test_basics : roundtrip_test_base<T>

// The letters from a (or A) through z (or Z) are ascribed the
// values 10 through 35; (C11 7.22.1.4/3)
r = from_chars(s, s + sizeof(s), x, 36);
r = std::from_chars(s, s + sizeof(s), x, 36);
assert(r.ec == std::errc::result_out_of_range);
// The member ptr of the return value points to the first character
// not matching the pattern
assert(r.ptr == s + sizeof(s) - 2);
assert(x == 1);

// no "0x" or "0X" prefix shall appear if the value of base is 16
r = from_chars(s, s + sizeof(s), x, 16);
r = std::from_chars(s, s + sizeof(s), x, 16);
assert(r.ec == std::errc{});
assert(r.ptr == s + 1);
assert(x == 0);

// only letters and digits whose ascribed values are less than that
// of base are permitted. (C11 7.22.1.4/3)
r = from_chars(s + 2, s + sizeof(s), x, 12);
r = std::from_chars(s + 2, s + sizeof(s), x, 12);
// If the parsed value is not in the range representable by the type
// of value,
if (!fits_in<T>(1150))
Expand All @@ -115,46 +83,26 @@ struct test_basics : roundtrip_test_base<T>
};

template <typename T>
struct test_signed : roundtrip_test_base<T>
struct test_signed
{
using roundtrip_test_base<T>::test;

void operator()()
{
test(-1);
test(-12);
test(-1, 10);
test(-12, 10);
test(-21734634, 10);
test(-2647, 2);
test(-0xcc1, 16);

for (int b = 2; b < 37; ++b)
{
using xl = std::numeric_limits<T>;

test(0, b);
test(xl::lowest(), b);
test((xl::max)(), b);
}

using std::from_chars;
std::from_chars_result r;
T x;

{
// If the pattern allows for an optional sign,
// but the string has no digit characters following the sign,
char s[] = "- 9+12";
r = from_chars(s, s + sizeof(s), x);
r = std::from_chars(s, s + sizeof(s), x);
// no characters match the pattern.
assert(r.ptr == s);
assert(r.ec == std::errc::invalid_argument);
}

{
char s[] = "9+12";
r = from_chars(s, s + sizeof(s), x);
r = std::from_chars(s, s + sizeof(s), x);
assert(r.ec == std::errc{});
// The member ptr of the return value points to the first character
// not matching the pattern,
Expand All @@ -164,7 +112,7 @@ struct test_signed : roundtrip_test_base<T>

{
char s[] = "12";
r = from_chars(s, s + 2, x);
r = std::from_chars(s, s + 2, x);
assert(r.ec == std::errc{});
// or has the value last if all characters match.
assert(r.ptr == s + 2);
Expand All @@ -175,7 +123,7 @@ struct test_signed : roundtrip_test_base<T>
// '-' is the only sign that may appear
char s[] = "+30";
// If no characters match the pattern,
r = from_chars(s, s + sizeof(s), x);
r = std::from_chars(s, s + sizeof(s), x);
// value is unmodified,
assert(x == 12);
// the member ptr of the return value is first and
Expand All @@ -191,5 +139,5 @@ int main(int, char**)
run<test_basics>(integrals);
run<test_signed>(all_signed);

return 0;
return 0;
}
@@ -0,0 +1,96 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++98, c++03
// UNSUPPORTED: !libc++ && c++11
// UNSUPPORTED: !libc++ && c++14

// The roundtrip test uses to_chars, which requires functions in the dylib
// that were introduced in Mac OS 10.15.
//
// XFAIL: with_system_cxx_lib=macosx10.14
// XFAIL: with_system_cxx_lib=macosx10.13
// XFAIL: with_system_cxx_lib=macosx10.12
// XFAIL: with_system_cxx_lib=macosx10.11
// XFAIL: with_system_cxx_lib=macosx10.10
// XFAIL: with_system_cxx_lib=macosx10.9
// XFAIL: with_system_cxx_lib=macosx10.8
// XFAIL: with_system_cxx_lib=macosx10.7

// <charconv>

// from_chars_result from_chars(const char* first, const char* last,
// Integral& value, int base = 10)

#include <charconv>
#include "test_macros.h"
#include "charconv_test_helpers.h"

template <typename T>
struct test_basics : roundtrip_test_base<T>
{
using roundtrip_test_base<T>::test;

void operator()()
{
test(0);
test(42);
test(32768);
test(0, 10);
test(42, 10);
test(32768, 10);
test(0xf, 16);
test(0xdeadbeaf, 16);
test(0755, 8);

for (int b = 2; b < 37; ++b)
{
using xl = std::numeric_limits<T>;

test(1, b);
test(-1, b);
test(xl::lowest(), b);
test((xl::max)(), b);
test((xl::max)() / 2, b);
}
}
};

template <typename T>
struct test_signed : roundtrip_test_base<T>
{
using roundtrip_test_base<T>::test;

void operator()()
{
test(-1);
test(-12);
test(-1, 10);
test(-12, 10);
test(-21734634, 10);
test(-2647, 2);
test(-0xcc1, 16);

for (int b = 2; b < 37; ++b)
{
using xl = std::numeric_limits<T>;

test(0, b);
test(xl::lowest(), b);
test((xl::max)(), b);
}
}
};

int main(int, char**)
{
run<test_basics>(integrals);
run<test_signed>(all_signed);

return 0;
}

0 comments on commit da090f6

Please sign in to comment.