diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp --- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp @@ -10732,7 +10732,8 @@ std::string nan= "nan"; std::string NaN = "NAN"; std::string nan_padding25 = "**********************"; -#if defined(TEST_HAS_GLIBC) || defined(_WIN32) +#if defined(TEST_HAS_GLIBC) || defined(_WIN32) || \ + (defined(__BIONIC__) && !defined(ANDROID_PRINTF_NAN_NO_SIGN)) std::string pnan_sign = "+"; std::string pnan_padding25 = "*********************"; #else diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp --- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp @@ -145,6 +145,7 @@ assert(err == ios.goodbit); assert(v == -INFINITY); } +#ifndef ANDROID_BROKEN_STRTOLD_NAN { const char str[] = "nan"; std::hex(ios); @@ -169,6 +170,7 @@ assert(err == ios.goodbit); assert(std::isnan(v)); } +#endif // ANDROID_BROKEN_STRTOLD_NAN { const char str[] = "1.189731495357231765021264e+49321"; std::ios_base::iostate err = ios.goodbit; diff --git a/libcxx/test/std/strings/string.conversions/stold.pass.cpp b/libcxx/test/std/strings/string.conversions/stold.pass.cpp --- a/libcxx/test/std/strings/string.conversions/stold.pass.cpp +++ b/libcxx/test/std/strings/string.conversions/stold.pass.cpp @@ -39,11 +39,13 @@ assert(std::stold("INF", &idx) == INFINITY); assert(idx == 3); } +#ifndef ANDROID_BROKEN_STRTOLD_NAN { size_t idx = 0; assert(std::isnan(std::stold("NAN", &idx))); assert(idx == 3); } +#endif #ifndef TEST_HAS_NO_EXCEPTIONS { @@ -104,11 +106,13 @@ assert(std::stold(L"INF", &idx) == INFINITY); assert(idx == 3); } +#ifndef ANDROID_BROKEN_STRTOLD_NAN { size_t idx = 0; assert(std::isnan(std::stold(L"NAN", &idx))); assert(idx == 3); } +#endif #ifndef TEST_HAS_NO_EXCEPTIONS { size_t idx = 0; diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -146,6 +146,56 @@ } """)), + # For Android, some of libc++'s floating-point conversions are implemented + # using Bionic (libc.so) on the device, which has bugs and behavioral + # differences on older OS versions. We want to adjust test behavior using the + # device version, not __ANDROID_API__, because it is useful/interesting to + # build test programs against an old Android API level and run them on a new + # Android OS. + + # printf's output for NAN has changed between versions of Android. Considering + # NAN and -NAN: + # - Android L (APIs 21 and 22): "%f" and "%+f" print "nan". + # - Android M (API 23) and up: "%f" prints "nan" or "-nan", "%+f" prints + # "+nan" or "-nan". + # Set this feature for L, where the sign is never printed. + Feature(name='android-printf-nan-no-sign', + when=lambda cfg: '__ANDROID__' in compilerMacros(cfg) and not programSucceeds(cfg, """ + #include + #include + #include + int main(int, char**) { + // Never enable the workaround on Android M or newer. + if (android_get_device_api_level() >= 23) return 0; + char buf[100]; + snprintf(buf, sizeof(buf), "%+f", NAN); + return buf[0] != '+'; + } + """), + actions=[AddCompileFlag('-DANDROID_PRINTF_NAN_NO_SIGN')]), + + # strtold does not handle "NAN" correctly on 64-bit Android prior to Android O + # (API 26). (It produces 0.0 instead of NAN.) Set a macro when the device's + # strtold is broken. + # See https://android-review.googlesource.com/q/Id7d46ac2d8acb8770b5e8c445e87cfabfde6f111. + Feature(name='android-broken-strtold-nan', + when=lambda cfg: '__ANDROID__' in compilerMacros(cfg) and not programSucceeds(cfg, """ + #include + #include + int main(int, char**) { + // Never enable the workaround on Android O or newer, or on + // unaffected architectures. + #if defined(__LP64__) + if (android_get_device_api_level() >= 26) return 0; + long double result = strtold("NAN", NULL); + return !isnan(result); + #else + return 0; + #endif + } + """), + actions=[AddCompileFlag('-DANDROID_BROKEN_STRTOLD_NAN')]), + # Whether Bash can run on the executor. # This is not always the case, for example when running on embedded systems. #