summaryrefslogtreecommitdiffstats
path: root/intl/icu-patches
diff options
context:
space:
mode:
Diffstat (limited to 'intl/icu-patches')
-rw-r--r--intl/icu-patches/bug-1198952-workaround-make-3.82-bug.diff42
-rw-r--r--intl/icu-patches/bug-1614941-dsb-hsb-dates.diff62
-rw-r--r--intl/icu-patches/bug-1636984-append-item-dayperiod-fractional-seconds.diff86
-rw-r--r--intl/icu-patches/bug-1636984-display-name-fractional-seconds.diff39
-rw-r--r--intl/icu-patches/bug-1706949-wasi-workaround.diff757
-rw-r--r--intl/icu-patches/bug-1790071-ICU-22132-standardize-vtzone-output.diff28
-rw-r--r--intl/icu-patches/bug-1792775-ICU-22198.diff19
-rw-r--r--intl/icu-patches/bug-1792775-ICU-22206.diff351
-rw-r--r--intl/icu-patches/bug-91573528
-rw-r--r--intl/icu-patches/suppress-warnings.diff80
10 files changed, 1492 insertions, 0 deletions
diff --git a/intl/icu-patches/bug-1198952-workaround-make-3.82-bug.diff b/intl/icu-patches/bug-1198952-workaround-make-3.82-bug.diff
new file mode 100644
index 0000000000..dc4f4e2692
--- /dev/null
+++ b/intl/icu-patches/bug-1198952-workaround-make-3.82-bug.diff
@@ -0,0 +1,42 @@
+diff --git a/intl/icu/source/Makefile.in b/intl/icu/source/Makefile.in
+--- a/intl/icu/source/Makefile.in
++++ b/intl/icu/source/Makefile.in
+@@ -134,32 +134,36 @@ endif
+
+ LOCAL_SUBDIRS = $(SUBDIRS)
+ CLEAN_FIRST_SUBDIRS = $(TOOLS)
+
+ $(LIBDIR) $(BINDIR):
+ -$(MKINSTALLDIRS) $@
+
+ ## Recursive targets
++## Strictly speaking, the $(MAKEOVERRIDES) is not necessary when recursing, but
++## there is a bug in GNU make 3.82 that throws away the original overrides in
++## favor of RECURSIVE=YES when the submake in the subdirectory restarts itself
++## after dependency files have been created.
+ all-recursive install-recursive clean-recursive distclean-recursive dist-recursive check-recursive check-exhaustive-recursive: $(LIBDIR) $(BINDIR)
+ ifneq ($(NEED_ESCAPING),)
+ @echo "building tools/escapesrc (Needed for this platform with NEED_ESCAPING)"
+- @(cd tools/escapesrc && $(MAKE) RECURSIVE=YES $$local_target) || exit
++ @(cd tools/escapesrc && $(MAKE) $(MAKEOVERRIDES) RECURSIVE=YES $$local_target) || exit
+ endif
+ @dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(LOCAL_SUBDIRS)'; for subdir in $$list; do \
+ echo "$(MAKE)[$(MAKELEVEL)]: Making \`$$target' in \`$$subdir'"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-local"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+- (cd $$subdir && $(MAKE) RECURSIVE=YES $$local_target) || exit; \
++ (cd $$subdir && $(MAKE) $(MAKEOVERRIDES) RECURSIVE=YES $$local_target) || exit; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) "$$target-local" || exit; \
+ fi
+
+ clean-recursive-with-twist:
+ $(MAKE) clean-recursive LOCAL_SUBDIRS='$(CLEAN_FIRST_SUBDIRS) $(filter-out $(CLEAN_FIRST_SUBDIRS),$(LOCAL_SUBDIRS))'
+
diff --git a/intl/icu-patches/bug-1614941-dsb-hsb-dates.diff b/intl/icu-patches/bug-1614941-dsb-hsb-dates.diff
new file mode 100644
index 0000000000..222b1e4678
--- /dev/null
+++ b/intl/icu-patches/bug-1614941-dsb-hsb-dates.diff
@@ -0,0 +1,62 @@
+diff --git a/intl/icu/source/data/locales/dsb.txt b/intl/icu/source/data/locales/dsb.txt
+--- a/intl/icu/source/data/locales/dsb.txt
++++ b/intl/icu/source/data/locales/dsb.txt
+@@ -547,23 +547,27 @@ dsb{
+ other{"W. 'tyźeń' MMMM"}
+ two{"W. 'tyźeń' MMMM"}
+ }
+ MMMMd{"d. MMMM"}
+ MMMd{"d. MMM"}
++ MMd{"d. MM"}
++ MMdd{"dd. MM"}
+ Md{"d.M."}
+ d{"d."}
+ h{"h a"}
+ hm{"h:mm a"}
+ hms{"h:mm:ss a"}
+ ms{"mm:ss"}
+ y{"y"}
+ yM{"M.y"}
+ yMEd{"E, d.M.y"}
++ yMM{"MM y"}
+ yMMM{"MMM y"}
+ yMMMEd{"E, d. MMM y"}
+ yMMMM{"LLLL y"}
+ yMMMd{"d. MMM y"}
++ yMMdd{"dd. MM y"}
+ yMd{"d.M.y"}
+ yQQQ{"QQQ y"}
+ yQQQQ{"QQQQ y"}
+ yw{
+ few{"w. 'tyźeń' 'lěta' Y"}
+diff --git a/intl/icu/source/data/locales/hsb.txt b/intl/icu/source/data/locales/hsb.txt
+--- a/intl/icu/source/data/locales/hsb.txt
++++ b/intl/icu/source/data/locales/hsb.txt
+@@ -546,23 +546,27 @@ hsb{
+ other{"W. 'tydźeń' MMMM"}
+ two{"W. 'tydźeń' MMMM"}
+ }
+ MMMMd{"d. MMMM"}
+ MMMd{"d. MMM"}
++ MMd{"d. MM"}
++ MMdd{"dd. MM"}
+ Md{"d.M."}
+ d{"d."}
+ h{"h a"}
+ hm{"h:mm a"}
+ hms{"h:mm:ss a"}
+ ms{"mm:ss"}
+ y{"y"}
+ yM{"M.y"}
+ yMEd{"E, d.M.y"}
++ yMM{"MM y"}
+ yMMM{"MMM y"}
+ yMMMEd{"E, d. MMM y"}
+ yMMMM{"LLLL y"}
+ yMMMd{"d. MMM y"}
++ yMMdd{"dd. MM y"}
+ yMd{"d.M.y"}
+ yQQQ{"QQQ y"}
+ yQQQQ{"QQQQ y"}
+ yw{
+ few{"w. 'tydźeń' 'lěta' Y"}
diff --git a/intl/icu-patches/bug-1636984-append-item-dayperiod-fractional-seconds.diff b/intl/icu-patches/bug-1636984-append-item-dayperiod-fractional-seconds.diff
new file mode 100644
index 0000000000..32ba468950
--- /dev/null
+++ b/intl/icu-patches/bug-1636984-append-item-dayperiod-fractional-seconds.diff
@@ -0,0 +1,86 @@
+# Add <appendItem> entries for "DayPeriod" and "FractionalSeconds" to avoid the
+# "├ ┤" parentheses from ICU and instead use the normal "( )" parentheses.
+#
+# CLDR bug: https://unicode-org.atlassian.net/browse/CLDR-13184
+
+diff --git a/intl/icu/source/data/locales/root.txt b/intl/icu/source/data/locales/root.txt
+--- a/intl/icu/source/data/locales/root.txt
++++ b/intl/icu/source/data/locales/root.txt
+@@ -213,17 +213,19 @@ root{
+ }
+ NoonMarker:alias{"/LOCALE/calendar/gregorian/NoonMarker"}
+ NoonMarkerNarrow:alias{"/LOCALE/calendar/gregorian/NoonMarkerNarrow"}
+ appendItems{
+ Day{"{0} ({2}: {1})"}
++ DayPeriod{"{0} ({2}: {1})"}
+ Day-Of-Week{"{0} {1}"}
+ Era{"{1} {0}"}
+ Hour{"{0} ({2}: {1})"}
+ Minute{"{0} ({2}: {1})"}
+ Month{"{0} ({2}: {1})"}
+ Quarter{"{0} ({2}: {1})"}
+ Second{"{0} ({2}: {1})"}
++ FractionalSecond{"{0} ({2}: {1})"}
+ Timezone{"{0} {1}"}
+ Week{"{0} ({2}: {1})"}
+ Year{"{1} {0}"}
+ }
+ availableFormats{
+@@ -749,17 +751,19 @@ root{
+ }
+ NoonMarker:alias{"/LOCALE/calendar/gregorian/NoonMarker"}
+ NoonMarkerNarrow:alias{"/LOCALE/calendar/gregorian/NoonMarkerNarrow"}
+ appendItems{
+ Day{"{0} ({2}: {1})"}
++ DayPeriod{"{0} ({2}: {1})"}
+ Day-Of-Week{"{0} {1}"}
+ Era{"{1} {0}"}
+ Hour{"{0} ({2}: {1})"}
+ Minute{"{0} ({2}: {1})"}
+ Month{"{0} ({2}: {1})"}
+ Quarter{"{0} ({2}: {1})"}
+ Second{"{0} ({2}: {1})"}
++ FractionalSecond{"{0} ({2}: {1})"}
+ Timezone{"{0} {1}"}
+ Week{"{0} ({2}: {1})"}
+ Year{"{1} {0}"}
+ }
+ availableFormats{
+@@ -1018,17 +1022,19 @@ root{
+ "{1} {0}",
+ "{1} {0}",
+ }
+ appendItems{
+ Day{"{0} ({2}: {1})"}
++ DayPeriod{"{0} ({2}: {1})"}
+ Day-Of-Week{"{0} {1}"}
+ Era{"{1} {0}"}
+ Hour{"{0} ({2}: {1})"}
+ Minute{"{0} ({2}: {1})"}
+ Month{"{0} ({2}: {1})"}
+ Quarter{"{0} ({2}: {1})"}
+ Second{"{0} ({2}: {1})"}
++ FractionalSecond{"{0} ({2}: {1})"}
+ Timezone{"{0} {1}"}
+ Week{"{0} ({2}: {1})"}
+ Year{"{1} {0}"}
+ }
+ availableFormats{
+diff --git a/intl/icu/source/i18n/dtptngen.cpp b/intl/icu/source/i18n/dtptngen.cpp
+--- a/intl/icu/source/i18n/dtptngen.cpp
++++ b/intl/icu/source/i18n/dtptngen.cpp
+@@ -257,12 +257,12 @@ static const dtTypeElem dtTypes[] = {
+ {0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
+ };
+
+ static const char* const CLDR_FIELD_APPEND[] = {
+ "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week",
+- "*", "*", "Day", "*", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
+- "Hour", "Minute", "Second", "*", "Timezone"
++ "*", "*", "Day", "DayPeriod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
++ "Hour", "Minute", "Second", "FractionalSecond", "Timezone"
+ };
+
+ static const char* const CLDR_FIELD_NAME[UDATPG_FIELD_COUNT] = {
+ "era", "year", "quarter", "month", "week", "weekOfMonth", "weekday",
+ "dayOfYear", "weekdayOfMonth", "day", "dayperiod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
diff --git a/intl/icu-patches/bug-1636984-display-name-fractional-seconds.diff b/intl/icu-patches/bug-1636984-display-name-fractional-seconds.diff
new file mode 100644
index 0000000000..1e68a20b42
--- /dev/null
+++ b/intl/icu-patches/bug-1636984-display-name-fractional-seconds.diff
@@ -0,0 +1,39 @@
+# Give fractional seconds a more useful display name than "F14".
+#
+# CLDR bug: https://unicode-org.atlassian.net/browse/CLDR-13623
+
+diff --git a/intl/icu/source/data/locales/root.txt b/intl/icu/source/data/locales/root.txt
+--- a/intl/icu/source/data/locales/root.txt
++++ b/intl/icu/source/data/locales/root.txt
+@@ -2527,10 +2527,15 @@ root{
+ zone{
+ dn{"Zone"}
+ }
+ zone-narrow:alias{"/LOCALE/fields/zone-short"}
+ zone-short:alias{"/LOCALE/fields/zone"}
++ fractionalSecond{
++ dn{"Fractional Second"}
++ }
++ fractionalSecond-narrow:alias{"/LOCALE/fields/fractionalSecond-short"}
++ fractionalSecond-short:alias{"/LOCALE/fields/fractionalSecond"}
+ }
+ layout{
+ characters{"left-to-right"}
+ lines{"top-to-bottom"}
+ }
+diff --git a/intl/icu/source/i18n/dtptngen.cpp b/intl/icu/source/i18n/dtptngen.cpp
+--- a/intl/icu/source/i18n/dtptngen.cpp
++++ b/intl/icu/source/i18n/dtptngen.cpp
+@@ -264,11 +264,11 @@ static const char* const CLDR_FIELD_APPE
+ };
+
+ static const char* const CLDR_FIELD_NAME[UDATPG_FIELD_COUNT] = {
+ "era", "year", "quarter", "month", "week", "weekOfMonth", "weekday",
+ "dayOfYear", "weekdayOfMonth", "day", "dayperiod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
+- "hour", "minute", "second", "*", "zone"
++ "hour", "minute", "second", "fractionalSecond", "zone"
+ };
+
+ static const char* const CLDR_FIELD_WIDTH[] = { // [UDATPG_WIDTH_COUNT]
+ "", "-short", "-narrow"
+ };
diff --git a/intl/icu-patches/bug-1706949-wasi-workaround.diff b/intl/icu-patches/bug-1706949-wasi-workaround.diff
new file mode 100644
index 0000000000..f56432f174
--- /dev/null
+++ b/intl/icu-patches/bug-1706949-wasi-workaround.diff
@@ -0,0 +1,757 @@
+# Handle WASI lack of support for <thread> and <atomic>.
+#
+# WASI issue: https://github.com/WebAssembly/wasi-sdk/issues/180
+
+diff --git a/intl/icu/source/common/putilimp.h b/intl/icu/source/common/putilimp.h
+index 5b95a68..7097232 100644
+--- a/intl/icu/source/common/putilimp.h
++++ b/intl/icu/source/common/putilimp.h
+@@ -103,6 +103,8 @@ typedef size_t uintptr_t;
+ #endif
+ #elif U_PLATFORM == U_PF_OS400
+ /* not defined */
++#elif defined(__wasi__)
++ /* not defined */
+ #else
+ # define U_TZSET tzset
+ #endif
+@@ -128,6 +130,8 @@ typedef size_t uintptr_t;
+ /* not defined */
+ #elif U_PLATFORM == U_PF_IPHONE
+ /* not defined */
++#elif defined(__wasi__)
++ /* not defined */
+ #else
+ # define U_TIMEZONE timezone
+ #endif
+@@ -141,6 +145,8 @@ typedef size_t uintptr_t;
+ #endif
+ #elif U_PLATFORM == U_PF_OS400
+ /* not defined */
++#elif defined(__wasi__)
++ /* not defined */
+ #else
+ # define U_TZNAME tzname
+ #endif
+diff --git a/intl/icu/source/common/umapfile.h b/intl/icu/source/common/umapfile.h
+index 92bd567..4ed1112 100644
+--- a/intl/icu/source/common/umapfile.h
++++ b/intl/icu/source/common/umapfile.h
+@@ -41,6 +41,8 @@ U_CFUNC void uprv_unmapFile(UDataMemory *pData);
+
+ #if UCONFIG_NO_FILE_IO
+ # define MAP_IMPLEMENTATION MAP_NONE
++#elif defined(__wasi__)
++# define MAP_IMPLEMENTATION MAP_STDIO
+ #elif U_PLATFORM_USES_ONLY_WIN32_API
+ # define MAP_IMPLEMENTATION MAP_WIN32
+ #elif U_HAVE_MMAP || U_PLATFORM == U_PF_OS390
+diff --git a/intl/icu/source/common/umutex.cpp b/intl/icu/source/common/umutex.cpp
+index ccbee99..6c3452c 100644
+--- a/intl/icu/source/common/umutex.cpp
++++ b/intl/icu/source/common/umutex.cpp
+@@ -43,6 +43,7 @@ U_NAMESPACE_BEGIN
+ *
+ *************************************************************************************************/
+
++#ifndef __wasi__
+ namespace {
+ std::mutex *initMutex;
+ std::condition_variable *initCondition;
+@@ -55,9 +56,11 @@ std::once_flag initFlag;
+ std::once_flag *pInitFlag = &initFlag;
+
+ } // Anonymous namespace
++#endif
+
+ U_CDECL_BEGIN
+ static UBool U_CALLCONV umtx_cleanup() {
++#ifndef __wasi__
+ initMutex->~mutex();
+ initCondition->~condition_variable();
+ UMutex::cleanup();
+@@ -66,17 +69,21 @@ static UBool U_CALLCONV umtx_cleanup() {
+ // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
+ pInitFlag->~once_flag();
+ pInitFlag = new(&initFlag) std::once_flag();
++#endif
+ return true;
+ }
+
+ static void U_CALLCONV umtx_init() {
++#ifndef __wasi__
+ initMutex = STATIC_NEW(std::mutex);
+ initCondition = STATIC_NEW(std::condition_variable);
+ ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
++#endif
+ }
+ U_CDECL_END
+
+
++#ifndef __wasi__
+ std::mutex *UMutex::getMutex() {
+ std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
+ if (retPtr == nullptr) {
+@@ -93,14 +100,17 @@ std::mutex *UMutex::getMutex() {
+ U_ASSERT(retPtr != nullptr);
+ return retPtr;
+ }
++#endif
+
+ UMutex *UMutex::gListHead = nullptr;
+
+ void UMutex::cleanup() {
+ UMutex *next = nullptr;
+ for (UMutex *m = gListHead; m != nullptr; m = next) {
++#ifndef __wasi__
+ (*m->fMutex).~mutex();
+ m->fMutex = nullptr;
++#endif
+ next = m->fListLink;
+ m->fListLink = nullptr;
+ }
+@@ -110,20 +120,24 @@ void UMutex::cleanup() {
+
+ U_CAPI void U_EXPORT2
+ umtx_lock(UMutex *mutex) {
++#ifndef __wasi__
+ if (mutex == nullptr) {
+ mutex = &globalMutex;
+ }
+ mutex->lock();
++#endif
+ }
+
+
+ U_CAPI void U_EXPORT2
+ umtx_unlock(UMutex* mutex)
+ {
++#ifndef __wasi__
+ if (mutex == nullptr) {
+ mutex = &globalMutex;
+ }
+ mutex->unlock();
++#endif
+ }
+
+
+@@ -143,18 +157,22 @@ umtx_unlock(UMutex* mutex)
+ //
+ U_COMMON_API UBool U_EXPORT2
+ umtx_initImplPreInit(UInitOnce &uio) {
++#ifndef __wasi__
+ std::call_once(*pInitFlag, umtx_init);
+ std::unique_lock<std::mutex> lock(*initMutex);
++#endif
+ if (umtx_loadAcquire(uio.fState) == 0) {
+ umtx_storeRelease(uio.fState, 1);
+ return true; // Caller will next call the init function.
+ } else {
++#ifndef __wasi__
+ while (umtx_loadAcquire(uio.fState) == 1) {
+ // Another thread is currently running the initialization.
+ // Wait until it completes.
+ initCondition->wait(lock);
+ }
+ U_ASSERT(uio.fState == 2);
++#endif
+ return false;
+ }
+ }
+@@ -168,11 +186,13 @@ umtx_initImplPreInit(UInitOnce &uio) {
+
+ U_COMMON_API void U_EXPORT2
+ umtx_initImplPostInit(UInitOnce &uio) {
++#ifndef __wasi__
+ {
+ std::unique_lock<std::mutex> lock(*initMutex);
+ umtx_storeRelease(uio.fState, 2);
+ }
+ initCondition->notify_all();
++#endif
+ }
+
+ U_NAMESPACE_END
+diff --git a/intl/icu/source/common/umutex.h b/intl/icu/source/common/umutex.h
+index 8d76b3f..c1a58db 100644
+--- a/intl/icu/source/common/umutex.h
++++ b/intl/icu/source/common/umutex.h
+@@ -20,9 +20,12 @@
+ #ifndef UMUTEX_H
+ #define UMUTEX_H
+
++#ifndef __wasi__
+ #include <atomic>
+ #include <condition_variable>
+ #include <mutex>
++#endif
++
+ #include <type_traits>
+
+ #include "unicode/utypes.h"
+@@ -37,6 +40,8 @@
+ #error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
+ #endif
+
++#ifndef __wasi__
++
+ // Export an explicit template instantiation of std::atomic<int32_t>.
+ // When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
+ // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
+@@ -61,6 +66,7 @@ template struct std::atomic<std::mutex *>;
+ #endif
+ #endif
+
++#endif
+
+ U_NAMESPACE_BEGIN
+
+@@ -70,6 +76,8 @@ U_NAMESPACE_BEGIN
+ *
+ ****************************************************************************/
+
++#ifndef __wasi__
++
+ typedef std::atomic<int32_t> u_atomic_int32_t;
+ #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
+
+@@ -89,6 +97,28 @@ inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
+ return var->fetch_sub(1) - 1;
+ }
+
++#else
++
++typedef int32_t u_atomic_int32_t;
++#define ATOMIC_INT32_T_INITIALIZER(val) val
++
++inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
++ return var;
++}
++
++inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
++ var = val;
++}
++
++inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
++ return ++(*var);
++}
++
++inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
++ return --(*var);
++}
++
++#endif
+
+ /*************************************************************************************************
+ *
+@@ -231,17 +261,25 @@ class U_COMMON_API UMutex {
+
+ // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
+ void lock() {
++#ifndef __wasi__
+ std::mutex *m = fMutex.load(std::memory_order_acquire);
+ if (m == nullptr) { m = getMutex(); }
+ m->lock();
++#endif
++ }
++ void unlock() {
++#ifndef __wasi__
++ fMutex.load(std::memory_order_relaxed)->unlock();
++#endif
+ }
+- void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
+
+ static void cleanup();
+
+ private:
++#ifndef __wasi__
+ alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
+ std::atomic<std::mutex *> fMutex { nullptr };
++#endif
+
+ /** All initialized UMutexes are kept in a linked list, so that they can be found,
+ * and the underlying std::mutex destructed, by u_cleanup().
+@@ -253,7 +291,9 @@ class U_COMMON_API UMutex {
+ * Initial fast check is inline, in lock(). The returned value may never
+ * be nullptr.
+ */
++#ifndef __wasi__
+ std::mutex *getMutex();
++#endif
+ };
+
+
+diff --git a/intl/icu/source/common/unifiedcache.cpp b/intl/icu/source/common/unifiedcache.cpp
+--- a/intl/icu/source/common/unifiedcache.cpp
++++ b/intl/icu/source/common/unifiedcache.cpp
+@@ -11,19 +11,23 @@
+ */
+
+ #include "unifiedcache.h"
+
+ #include <algorithm> // For std::max()
+-#include <mutex>
++#ifndef __wasi__
++ #include <mutex>
++#endif
+
+ #include "uassert.h"
+ #include "uhash.h"
+ #include "ucln_cmn.h"
+
+ static icu::UnifiedCache *gCache = NULL;
++#ifndef __wasi__
+ static std::mutex *gCacheMutex = nullptr;
+ static std::condition_variable *gInProgressValueAddedCond;
++#endif
+ static icu::UInitOnce gCacheInitOnce {};
+
+ static const int32_t MAX_EVICT_ITERATIONS = 10;
+ static const int32_t DEFAULT_MAX_UNUSED = 1000;
+ static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
+@@ -32,14 +36,16 @@ static const int32_t DEFAULT_PERCENTAGE_OF_IN_USE = 100;
+ U_CDECL_BEGIN
+ static UBool U_CALLCONV unifiedcache_cleanup() {
+ gCacheInitOnce.reset();
+ delete gCache;
+ gCache = nullptr;
++#ifndef __wasi__
+ gCacheMutex->~mutex();
+ gCacheMutex = nullptr;
+ gInProgressValueAddedCond->~condition_variable();
+ gInProgressValueAddedCond = nullptr;
++#endif
+ return true;
+ }
+ U_CDECL_END
+
+
+@@ -70,12 +76,14 @@ CacheKeyBase::~CacheKeyBase() {
+ static void U_CALLCONV cacheInit(UErrorCode &status) {
+ U_ASSERT(gCache == NULL);
+ ucln_common_registerCleanup(
+ UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
+
++#ifndef __wasi__
+ gCacheMutex = STATIC_NEW(std::mutex);
+ gInProgressValueAddedCond = STATIC_NEW(std::condition_variable);
++#endif
+ gCache = new UnifiedCache(status);
+ if (gCache == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ if (U_FAILURE(status)) {
+@@ -133,41 +141,53 @@ void UnifiedCache::setEvictionPolicy(
+ }
+ if (count < 0 || percentageOfInUseItems < 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ fMaxUnused = count;
+ fMaxPercentageOfInUse = percentageOfInUseItems;
+ }
+
+ int32_t UnifiedCache::unusedCount() const {
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ return uhash_count(fHashtable) - fNumValuesInUse;
+ }
+
+ int64_t UnifiedCache::autoEvictedCount() const {
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ return fAutoEvictedCount;
+ }
+
+ int32_t UnifiedCache::keyCount() const {
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ return uhash_count(fHashtable);
+ }
+
+ void UnifiedCache::flush() const {
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+
+ // Use a loop in case cache items that are flushed held hard references to
+ // other cache items making those additional cache items eligible for
+ // flushing.
+ while (_flush(false));
+ }
+
+ void UnifiedCache::handleUnreferencedObject() const {
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ --fNumValuesInUse;
+ _runEvictionSlice();
+ }
+
+ #ifdef UNIFIED_CACHE_DEBUG
+@@ -182,11 +202,13 @@ void UnifiedCache::dump() {
+ }
+ cache->dumpContents();
+ }
+
+ void UnifiedCache::dumpContents() const {
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ _dumpContents();
+ }
+
+ // Dumps content of cache.
+ // On entry, gCacheMutex must be held.
+@@ -222,11 +244,13 @@ UnifiedCache::~UnifiedCache() {
+ flush();
+ {
+ // Now all that should be left in the cache are entries that refer to
+ // each other and entries with hard references from outside the cache.
+ // Nothing we can do about these so proceed to wipe out the cache.
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ _flush(true);
+ }
+ uhash_close(fHashtable);
+ fHashtable = nullptr;
+ delete fNoValue;
+@@ -323,11 +347,13 @@ void UnifiedCache::_putNew(
+
+ void UnifiedCache::_putIfAbsentAndGet(
+ const CacheKeyBase &key,
+ const SharedObject *&value,
+ UErrorCode &status) const {
++#ifndef __wasi__
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
++#endif
+ const UHashElement *element = uhash_find(fHashtable, &key);
+ if (element != NULL && !_inProgress(element)) {
+ _fetch(element, value, status);
+ return;
+ }
+@@ -348,18 +374,22 @@ UBool UnifiedCache::_poll(
+ const CacheKeyBase &key,
+ const SharedObject *&value,
+ UErrorCode &status) const {
+ U_ASSERT(value == NULL);
+ U_ASSERT(status == U_ZERO_ERROR);
++#ifndef __wasi__
+ std::unique_lock<std::mutex> lock(*gCacheMutex);
++#endif
+ const UHashElement *element = uhash_find(fHashtable, &key);
+
+ // If the hash table contains an inProgress placeholder entry for this key,
+ // this means that another thread is currently constructing the value object.
+ // Loop, waiting for that construction to complete.
+ while (element != NULL && _inProgress(element)) {
++#ifndef __wasi__
+ gInProgressValueAddedCond->wait(lock);
++#endif
+ element = uhash_find(fHashtable, &key);
+ }
+
+ // If the hash table contains an entry for the key,
+ // fetch out the contents and return them.
+@@ -426,13 +456,15 @@ void UnifiedCache::_put(
+ UHashElement *ptr = const_cast<UHashElement *>(element);
+ ptr->value.pointer = (void *) value;
+ U_ASSERT(oldValue == fNoValue);
+ removeSoftRef(oldValue);
+
++#ifndef __wasi__
+ // Tell waiting threads that we replace in-progress status with
+ // an error.
+ gInProgressValueAddedCond->notify_all();
++#endif
+ }
+
+ void UnifiedCache::_fetch(
+ const UHashElement *element,
+ const SharedObject *&value,
+diff --git a/intl/icu/source/i18n/decContext.h b/intl/icu/source/i18n/decContext.h
+index 59ab65e..20f3526 100644
+--- a/intl/icu/source/i18n/decContext.h
++++ b/intl/icu/source/i18n/decContext.h
+@@ -61,7 +61,9 @@
+ /* #include <stdint.h> */ /* C99 standard integers */
+ #endif
+ #include <stdio.h> /* for printf, etc. */
++#ifndef __wasi__
+ #include <signal.h> /* for traps */
++#endif
+
+ /* Extended flags setting -- set this to 0 to use only IEEE flags */
+ #if !defined(DECEXTFLAG)
+diff --git a/intl/icu/source/i18n/decimfmt.cpp b/intl/icu/source/i18n/decimfmt.cpp
+index daa1129..c8f1eda 100644
+--- a/intl/icu/source/i18n/decimfmt.cpp
++++ b/intl/icu/source/i18n/decimfmt.cpp
+@@ -480,8 +480,13 @@ DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {
+ DecimalFormat::~DecimalFormat() {
+ if (fields == nullptr) { return; }
+
++#ifndef __wasi__
+ delete fields->atomicParser.exchange(nullptr);
+ delete fields->atomicCurrencyParser.exchange(nullptr);
++#else
++ delete fields->atomicParser;
++ delete fields->atomicCurrencyParser;
++#endif
+ delete fields;
+ }
+
+@@ -1626,8 +1631,13 @@ void DecimalFormat::touch(UErrorCode& status) {
+ setupFastFormat();
+
+ // Delete the parsers if they were made previously
++#ifndef __wasi__
+ delete fields->atomicParser.exchange(nullptr);
+ delete fields->atomicCurrencyParser.exchange(nullptr);
++#else
++ delete fields->atomicParser;
++ delete fields->atomicCurrencyParser;
++#endif
+
+ // In order for the getters to work, we need to populate some fields in NumberFormat.
+ NumberFormat::setCurrency(fields->exportedProperties.currency.get(status).getISOCurrency(), status);
+@@ -1662,7 +1672,11 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
+ }
+
+ // First try to get the pre-computed parser
++#ifndef __wasi__
+ auto* ptr = fields->atomicParser.load();
++#else
++ auto* ptr = fields->atomicParser;
++#endif
+ if (ptr != nullptr) {
+ return ptr;
+ }
+@@ -1681,6 +1695,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
+ // it is set to what is actually stored in the atomic
+ // if another thread beat us to computing the parser object.
+ auto* nonConstThis = const_cast<DecimalFormat*>(this);
++#ifndef __wasi__
+ if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the parser
+ delete temp;
+@@ -1689,13 +1704,21 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& sta
+ // Our copy of the parser got stored in the atomic
+ return temp;
+ }
++#else
++ nonConstThis->fields->atomicParser = temp;
++ return temp;
++#endif
+ }
+
+ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const {
+ if (U_FAILURE(status)) { return nullptr; }
+
+ // First try to get the pre-computed parser
++#ifndef __wasi__
+ auto* ptr = fields->atomicCurrencyParser.load();
++#else
++ auto* ptr = fields->atomicCurrencyParser;
++#endif
+ if (ptr != nullptr) {
+ return ptr;
+ }
+@@ -1710,6 +1733,7 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
+ // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the
+ // atomic if another thread beat us to computing the parser object.
+ auto* nonConstThis = const_cast<DecimalFormat*>(this);
++#ifndef __wasi__
+ if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the parser
+ delete temp;
+@@ -1718,6 +1742,10 @@ const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorC
+ // Our copy of the parser got stored in the atomic
+ return temp;
+ }
++#else
++ nonConstThis->fields->atomicCurrencyParser = temp;
++ return temp;
++#endif
+ }
+
+ void
+diff --git a/intl/icu/source/i18n/number_mapper.h b/intl/icu/source/i18n/number_mapper.h
+index 9ecd776..d094289 100644
+--- a/intl/icu/source/i18n/number_mapper.h
++++ b/intl/icu/source/i18n/number_mapper.h
+@@ -7,7 +7,6 @@
+ #ifndef __NUMBER_MAPPER_H__
+ #define __NUMBER_MAPPER_H__
+
+-#include <atomic>
+ #include "number_types.h"
+ #include "unicode/currpinf.h"
+ #include "standardplural.h"
+@@ -15,6 +14,10 @@
+ #include "number_currencysymbols.h"
+ #include "numparse_impl.h"
+
++#ifndef __wasi__
++#include <atomic>
++#endif
++
+ U_NAMESPACE_BEGIN
+ namespace number {
+ namespace impl {
+@@ -193,10 +196,18 @@ struct DecimalFormatFields : public UMemory {
+ LocalizedNumberFormatter formatter;
+
+ /** The lazy-computed parser for .parse() */
++#ifndef __wasi__
+ std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicParser = {};
++#else
++ ::icu::numparse::impl::NumberParserImpl* atomicParser = nullptr;
++#endif
+
+ /** The lazy-computed parser for .parseCurrency() */
++#ifndef __wasi__
+ std::atomic<::icu::numparse::impl::NumberParserImpl*> atomicCurrencyParser = {};
++#else
++ ::icu::numparse::impl::NumberParserImpl* atomicCurrencyParser = {};
++#endif
+
+ /** Small object ownership warehouse for the formatter and parser */
+ DecimalFormatWarehouse warehouse;
+diff --git a/intl/icu/source/i18n/numrange_fluent.cpp b/intl/icu/source/i18n/numrange_fluent.cpp
+index f1060b3..66e12ee 100644
+--- a/intl/icu/source/i18n/numrange_fluent.cpp
++++ b/intl/icu/source/i18n/numrange_fluent.cpp
+@@ -240,29 +240,49 @@ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_N
+ : NFS<LNF>(std::move(src)) {
+ // Steal the compiled formatter
+ LNF&& _src = static_cast<LNF&&>(src);
++#ifndef __wasi__
+ auto* stolen = _src.fAtomicFormatter.exchange(nullptr);
+ delete fAtomicFormatter.exchange(stolen);
++#else
++ delete fAtomicFormatter;
++ fAtomicFormatter = _src.fAtomicFormatter;
++ _src.fAtomicFormatter = nullptr;
++#endif
+ }
+
+ LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
+ NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
+ // Do not steal; just clear
++#ifndef __wasi__
+ delete fAtomicFormatter.exchange(nullptr);
++#else
++ delete fAtomicFormatter;
++#endif
+ return *this;
+ }
+
+ LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
+ NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
+ // Steal the compiled formatter
++#ifndef __wasi__
+ auto* stolen = src.fAtomicFormatter.exchange(nullptr);
+ delete fAtomicFormatter.exchange(stolen);
++#else
++ delete fAtomicFormatter;
++ fAtomicFormatter = src.fAtomicFormatter;
++ src.fAtomicFormatter = nullptr;
++#endif
+ return *this;
+ }
+
+
+ LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() {
++#ifndef __wasi__
+ delete fAtomicFormatter.exchange(nullptr);
++#else
++ delete fAtomicFormatter;
++#endif
+ }
+
+ LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
+@@ -346,7 +366,11 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
+ }
+
+ // First try to get the pre-computed formatter
++#ifndef __wasi__
+ auto* ptr = fAtomicFormatter.load();
++#else
++ auto* ptr = fAtomicFormatter;
++#endif
+ if (ptr != nullptr) {
+ return ptr;
+ }
+@@ -365,6 +389,7 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
+ // it is set to what is actually stored in the atomic
+ // if another thread beat us to computing the formatter object.
+ auto* nonConstThis = const_cast<LocalizedNumberRangeFormatter*>(this);
++#ifndef __wasi__
+ if (!nonConstThis->fAtomicFormatter.compare_exchange_strong(ptr, temp)) {
+ // Another thread beat us to computing the formatter
+ delete temp;
+@@ -373,6 +398,10 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
+ // Our copy of the formatter got stored in the atomic
+ return temp;
+ }
++#else
++ nonConstThis->fAtomicFormatter = temp;
++ return temp;
++#endif
+
+ }
+
+diff --git a/intl/icu/source/i18n/unicode/numberrangeformatter.h b/intl/icu/source/i18n/unicode/numberrangeformatter.h
+index b9a4600..0ba2fa0 100644
+--- a/intl/icu/source/i18n/unicode/numberrangeformatter.h
++++ b/intl/icu/source/i18n/unicode/numberrangeformatter.h
+@@ -10,7 +10,6 @@
+
+ #if !UCONFIG_NO_FORMATTING
+
+-#include <atomic>
+ #include "unicode/appendable.h"
+ #include "unicode/fieldpos.h"
+ #include "unicode/formattedvalue.h"
+@@ -18,6 +17,10 @@
+ #include "unicode/numberformatter.h"
+ #include "unicode/unumberrangeformatter.h"
+
++#ifndef __wasi__
++#include <atomic>
++#endif
++
+ /**
+ * \file
+ * \brief C++ API: Library for localized formatting of number, currency, and unit ranges.
+@@ -77,7 +80,9 @@ struct UFormattedNumberRangeImpl;
+ } // namespace icu::number
+ U_NAMESPACE_END
+
++#ifndef __wasi__
+ template struct U_I18N_API std::atomic< U_NAMESPACE_QUALIFIER number::impl::NumberRangeFormatterImpl*>;
++#endif
+
+ U_NAMESPACE_BEGIN
+ namespace number { // icu::number
+@@ -546,7 +551,11 @@ class U_I18N_API LocalizedNumberRangeFormatter
+ ~LocalizedNumberRangeFormatter();
+
+ private:
++#ifndef __wasi__
+ std::atomic<impl::NumberRangeFormatterImpl*> fAtomicFormatter = {};
++#else
++ impl::NumberRangeFormatterImpl* fAtomicFormatter = nullptr;
++#endif
+
+ const impl::NumberRangeFormatterImpl* getFormatter(UErrorCode& stauts) const;
+
diff --git a/intl/icu-patches/bug-1790071-ICU-22132-standardize-vtzone-output.diff b/intl/icu-patches/bug-1790071-ICU-22132-standardize-vtzone-output.diff
new file mode 100644
index 0000000000..e31f02d637
--- /dev/null
+++ b/intl/icu-patches/bug-1790071-ICU-22132-standardize-vtzone-output.diff
@@ -0,0 +1,28 @@
+diff --git a/intl/icu/source/i18n/vtzone.cpp b/intl/icu/source/i18n/vtzone.cpp
+--- a/intl/icu/source/i18n/vtzone.cpp
++++ b/intl/icu/source/i18n/vtzone.cpp
+@@ -1735,14 +1735,17 @@ VTimeZone::write(VTZWriter& writer, UErr
+ }
+ }
+ } else {
+- UnicodeString icutzprop;
+- UVector customProps(nullptr, uhash_compareUnicodeString, status);
++ UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
+ if (olsonzid.length() > 0 && icutzver.length() > 0) {
+- icutzprop.append(olsonzid);
+- icutzprop.append(u'[');
+- icutzprop.append(icutzver);
+- icutzprop.append(u']');
+- customProps.addElement(&icutzprop, status);
++ LocalPointer<UnicodeString> icutzprop(new UnicodeString(ICU_TZINFO_PROP), status);
++ if (U_FAILURE(status)) {
++ return;
++ }
++ icutzprop->append(olsonzid);
++ icutzprop->append(u'[');
++ icutzprop->append(icutzver);
++ icutzprop->append(u']');
++ customProps.adoptElement(icutzprop.orphan(), status);
+ }
+ writeZone(writer, *tz, &customProps, status);
+ }
diff --git a/intl/icu-patches/bug-1792775-ICU-22198.diff b/intl/icu-patches/bug-1792775-ICU-22198.diff
new file mode 100644
index 0000000000..ec5211b651
--- /dev/null
+++ b/intl/icu-patches/bug-1792775-ICU-22198.diff
@@ -0,0 +1,19 @@
+# https://github.com/unicode-org/icu/pull/2248
+# https://github.com/unicode-org/icu/pull/2248.diff
+#
+# ICU bug: https://unicode-org.atlassian.net/browse/ICU-22198
+
+diff --git a/intl/icu/source/common/uresbund.cpp b/intl/icu/source/common/uresbund.cpp
+index 17c0177a05c..81fb90e1384 100644
+--- a/intl/icu/source/common/uresbund.cpp
++++ b/intl/icu/source/common/uresbund.cpp
+@@ -202,7 +202,8 @@ typedef enum UResOpenType UResOpenType;
+ */
+ static bool getParentLocaleID(char *name, const char *origName, UResOpenType openType) {
+ // early out if the locale ID has a variant code or ends with _
+- if (name[uprv_strlen(name) - 1] == '_' || hasVariant(name)) {
++ size_t nameLen = uprv_strlen(name);
++ if (!nameLen || name[nameLen - 1] == '_' || hasVariant(name)) {
+ return chopLocale(name);
+ }
+
diff --git a/intl/icu-patches/bug-1792775-ICU-22206.diff b/intl/icu-patches/bug-1792775-ICU-22206.diff
new file mode 100644
index 0000000000..34e3625803
--- /dev/null
+++ b/intl/icu-patches/bug-1792775-ICU-22206.diff
@@ -0,0 +1,351 @@
+# https://github.com/unicode-org/icu/pull/2255
+# https://github.com/unicode-org/icu/pull/2255.diff
+#
+# ICU bug: https://unicode-org.atlassian.net/browse/ICU-22206
+
+diff --git a/intl/icu/source/common/rbbiscan.cpp b/intl/icu/source/common/rbbiscan.cpp
+index 8232bd94e47..87d31f8af40 100644
+--- a/intl/icu/source/common/rbbiscan.cpp
++++ b/intl/icu/source/common/rbbiscan.cpp
+@@ -918,7 +918,7 @@ void RBBIRuleScanner::nextChar(RBBIRuleChar &c) {
+ // Toggle quoting mode.
+ // Return either '(' or ')', because quotes cause a grouping of the quoted text.
+ fQuoteMode = !fQuoteMode;
+- if (fQuoteMode == true) {
++ if (fQuoteMode) {
+ c.fChar = chLParen;
+ } else {
+ c.fChar = chRParen;
+diff --git a/intl/icu/source/common/ucnvisci.cpp b/intl/icu/source/common/ucnvisci.cpp
+index 4d747e1ff84..839f7ff9c62 100644
+--- a/intl/icu/source/common/ucnvisci.cpp
++++ b/intl/icu/source/common/ucnvisci.cpp
+@@ -1472,7 +1472,7 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
+ if (targetUniChar != missingCharMarker) {
+ /* now save the targetUniChar for delayed write */
+ *toUnicodeStatus = (UChar) targetUniChar;
+- if (data->resetToDefaultToUnicode==true) {
++ if (data->resetToDefaultToUnicode) {
+ data->currentDeltaToUnicode = data->defDeltaToUnicode;
+ data->currentMaskToUnicode = data->defMaskToUnicode;
+ data->resetToDefaultToUnicode=false;
+diff --git a/intl/icu/source/common/udata.cpp b/intl/icu/source/common/udata.cpp
+index 2bc74c97898..c5d0a9feb7b 100644
+--- a/intl/icu/source/common/udata.cpp
++++ b/intl/icu/source/common/udata.cpp
+@@ -568,7 +568,7 @@ const char *UDataPathIterator::next(UErrorCode *pErrorCode)
+ /* check for .dat files */
+ pathBasename = findBasename(pathBuffer.data());
+
+- if(checkLastFour == true &&
++ if(checkLastFour &&
+ (pathLen>=4) &&
+ uprv_strncmp(pathBuffer.data() +(pathLen-4), suffix.data(), 4)==0 && /* suffix matches */
+ uprv_strncmp(findBasename(pathBuffer.data()), basename, basenameLen)==0 && /* base matches */
+diff --git a/intl/icu/source/common/uidna.cpp b/intl/icu/source/common/uidna.cpp
+index 1cbdeec3272..7135a166f21 100644
+--- a/intl/icu/source/common/uidna.cpp
++++ b/intl/icu/source/common/uidna.cpp
+@@ -287,7 +287,7 @@ _internal_toASCII(const UChar* src, int32_t srcLength,
+ failPos = j;
+ }
+ }
+- if(useSTD3ASCIIRules == true){
++ if(useSTD3ASCIIRules){
+ // verify 3a and 3b
+ // 3(a) Verify the absence of non-LDH ASCII code points; that is, the
+ // absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
+@@ -731,7 +731,7 @@ uidna_IDNToASCII( const UChar *src, int32_t srcLength,
+ remainingDestCapacity = 0;
+ }
+
+- if(done == true){
++ if(done){
+ break;
+ }
+
+@@ -829,7 +829,7 @@ uidna_IDNToUnicode( const UChar* src, int32_t srcLength,
+ remainingDestCapacity = 0;
+ }
+
+- if(done == true){
++ if(done){
+ break;
+ }
+
+diff --git a/intl/icu/source/common/uresbund.cpp b/intl/icu/source/common/uresbund.cpp
+index 17c0177a05c..c065387bdae 100644
+--- a/intl/icu/source/common/uresbund.cpp
++++ b/intl/icu/source/common/uresbund.cpp
+@@ -2448,7 +2448,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con
+ res = res_getTableItemByKey(&resB->getResData(), resB->fRes, &t, &key);
+ if(res == RES_BOGUS) {
+ key = inKey;
+- if(resB->fHasFallback == true) {
++ if(resB->fHasFallback) {
+ dataEntry = getFallbackData(resB, &key, &res, status);
+ if(U_SUCCESS(*status)) {
+ /* check if resB->fResPath gives the right name here */
+@@ -2503,7 +2503,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c
+
+ if(res == RES_BOGUS) {
+ key = inKey;
+- if(resB->fHasFallback == true) {
++ if(resB->fHasFallback) {
+ dataEntry = getFallbackData(resB, &key, &res, status);
+ if(U_SUCCESS(*status)) {
+ switch (RES_GET_TYPE(res)) {
+diff --git a/intl/icu/source/common/usprep.cpp b/intl/icu/source/common/usprep.cpp
+index 50d16081d1d..8175dc7fa82 100644
+--- a/intl/icu/source/common/usprep.cpp
++++ b/intl/icu/source/common/usprep.cpp
+@@ -160,7 +160,7 @@ usprep_internal_flushCache(UBool noRefCount){
+ key = (UStringPrepKey *) e->key.pointer;
+
+ if ((noRefCount== false && profile->refCount == 0) ||
+- noRefCount== true) {
++ noRefCount) {
+ deletedNum++;
+ uhash_removeElement(SHARED_DATA_HASHTABLE, e);
+
+@@ -746,16 +746,16 @@ usprep_prepare( const UStringPrepProfile* profile,
+ }
+ }
+ }
+- if(profile->checkBiDi == true){
++ if(profile->checkBiDi){
+ // satisfy 2
+- if( leftToRight == true && rightToLeft == true){
++ if( leftToRight && rightToLeft){
+ *status = U_STRINGPREP_CHECK_BIDI_ERROR;
+ uprv_syntaxError(b2,(rtlPos>ltrPos) ? rtlPos : ltrPos, b2Len, parseError);
+ return 0;
+ }
+
+ //satisfy 3
+- if( rightToLeft == true &&
++ if( rightToLeft &&
+ !((firstCharDir == U_RIGHT_TO_LEFT || firstCharDir == U_RIGHT_TO_LEFT_ARABIC) &&
+ (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC))
+ ){
+diff --git a/intl/icu/source/common/utext.cpp b/intl/icu/source/common/utext.cpp
+index 548e6a60f31..89e3d669f6e 100644
+--- a/intl/icu/source/common/utext.cpp
++++ b/intl/icu/source/common/utext.cpp
+@@ -223,7 +223,7 @@ utext_current32(UText *ut) {
+ trail = ut->chunkContents[ut->chunkOffset];
+ }
+ UBool r = ut->pFuncs->access(ut, nativePosition, false); // reverse iteration flag loads preceding chunk
+- U_ASSERT(r==true);
++ U_ASSERT(r);
+ ut->chunkOffset = originalOffset;
+ if(!r) {
+ return U_SENTINEL;
+diff --git a/intl/icu/source/i18n/calendar.cpp b/intl/icu/source/i18n/calendar.cpp
+index f5a40e48395..5431d87bdd2 100644
+--- a/intl/icu/source/i18n/calendar.cpp
++++ b/intl/icu/source/i18n/calendar.cpp
+@@ -3510,7 +3510,7 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
+ switch(bestField) {
+ case UCAL_WEEK_OF_YEAR:
+ if(woy == 1) {
+- if(jan1InPrevYear == true) {
++ if(jan1InPrevYear) {
+ // the first week of January is in the previous year
+ // therefore WOY1 is always solidly within yearWoy
+ return yearWoy;
+diff --git a/intl/icu/source/i18n/dcfmtsym.cpp b/intl/icu/source/i18n/dcfmtsym.cpp
+index 5d06c189fbe..fa5920aaa50 100644
+--- a/intl/icu/source/i18n/dcfmtsym.cpp
++++ b/intl/icu/source/i18n/dcfmtsym.cpp
+@@ -329,11 +329,13 @@ struct CurrencySpacingSink : public ResourceSink {
+ // both beforeCurrency and afterCurrency were found in CLDR.
+ static const char* defaults[] = { "[:letter:]", "[:digit:]", " " };
+ if (!hasBeforeCurrency || !hasAfterCurrency) {
+- for (UBool beforeCurrency = 0; beforeCurrency <= true; beforeCurrency++) {
+- for (int32_t pattern = 0; pattern < UNUM_CURRENCY_SPACING_COUNT; pattern++) {
+- dfs.setPatternForCurrencySpacing((UCurrencySpacing)pattern,
+- beforeCurrency, UnicodeString(defaults[pattern], -1, US_INV));
+- }
++ for (int32_t pattern = 0; pattern < UNUM_CURRENCY_SPACING_COUNT; pattern++) {
++ dfs.setPatternForCurrencySpacing((UCurrencySpacing)pattern,
++ false, UnicodeString(defaults[pattern], -1, US_INV));
++ }
++ for (int32_t pattern = 0; pattern < UNUM_CURRENCY_SPACING_COUNT; pattern++) {
++ dfs.setPatternForCurrencySpacing((UCurrencySpacing)pattern,
++ true, UnicodeString(defaults[pattern], -1, US_INV));
+ }
+ }
+ }
+diff --git a/intl/icu/source/i18n/dtitvinf.cpp b/intl/icu/source/i18n/dtitvinf.cpp
+index f5fb86ce581..0a30cf14419 100644
+--- a/intl/icu/source/i18n/dtitvinf.cpp
++++ b/intl/icu/source/i18n/dtitvinf.cpp
+@@ -504,7 +504,7 @@ DateIntervalInfo::setIntervalPatternInternally(const UnicodeString& skeleton,
+ }
+
+ patternsOfOneSkeleton[index] = intervalPattern;
+- if ( emptyHash == true ) {
++ if ( emptyHash ) {
+ fIntervalPatterns->put(skeleton, patternsOfOneSkeleton, status);
+ }
+ }
+@@ -748,7 +748,7 @@ U_CALLCONV dtitvinfHashTableValueComparator(UHashTok val1, UHashTok val2) {
+ const UnicodeString* pattern2 = (UnicodeString*)val2.pointer;
+ UBool ret = true;
+ int8_t i;
+- for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret == true; ++i ) {
++ for ( i = 0; i < DateIntervalInfo::kMaxIntervalPatternIndex && ret ; ++i ) {
+ ret = (pattern1[i] == pattern2[i]);
+ }
+ return ret;
+diff --git a/intl/icu/source/i18n/gregocal.cpp b/intl/icu/source/i18n/gregocal.cpp
+index 882d25b4a2a..0e00127e314 100644
+--- a/intl/icu/source/i18n/gregocal.cpp
++++ b/intl/icu/source/i18n/gregocal.cpp
+@@ -487,7 +487,7 @@ int32_t GregorianCalendar::handleComputeJulianDay(UCalendarDateFields bestField)
+ // The following check handles portions of the cutover year BEFORE the
+ // cutover itself happens.
+ //if ((fIsGregorian==true) != (jd >= fCutoverJulianDay)) { /* cutoverJulianDay)) { */
+- if ((fIsGregorian==true) != (jd >= fCutoverJulianDay)) { /* cutoverJulianDay)) { */
++ if ((fIsGregorian) != (jd >= fCutoverJulianDay)) { /* cutoverJulianDay)) { */
+ #if defined (U_DEBUG_CAL)
+ fprintf(stderr, "%s:%d: jd [invert] %d\n",
+ __FILE__, __LINE__, jd);
+diff --git a/intl/icu/source/i18n/regexcmp.cpp b/intl/icu/source/i18n/regexcmp.cpp
+index 4b507002d63..adc8f700c7f 100644
+--- a/intl/icu/source/i18n/regexcmp.cpp
++++ b/intl/icu/source/i18n/regexcmp.cpp
+@@ -4065,7 +4065,7 @@ void RegexCompile::nextChar(RegexPatternChar &c) {
+ if (c.fChar == (UChar32)-1) {
+ break; // End of Input
+ }
+- if (c.fChar == chPound && fEOLComments == true) {
++ if (c.fChar == chPound && fEOLComments) {
+ // Start of a comment. Consume the rest of it, until EOF or a new line
+ for (;;) {
+ c.fChar = nextCharLL();
+diff --git a/intl/icu/source/i18n/search.cpp b/intl/icu/source/i18n/search.cpp
+index 56d9b744098..d55902bfa7b 100644
+--- a/intl/icu/source/i18n/search.cpp
++++ b/intl/icu/source/i18n/search.cpp
+@@ -81,10 +81,9 @@ USearchAttributeValue SearchIterator::getAttribute(
+ {
+ switch (attribute) {
+ case USEARCH_OVERLAP :
+- return (m_search_->isOverlap == true ? USEARCH_ON : USEARCH_OFF);
++ return (m_search_->isOverlap ? USEARCH_ON : USEARCH_OFF);
+ case USEARCH_CANONICAL_MATCH :
+- return (m_search_->isCanonicalMatch == true ? USEARCH_ON :
+- USEARCH_OFF);
++ return (m_search_->isCanonicalMatch ? USEARCH_ON : USEARCH_OFF);
+ case USEARCH_ELEMENT_COMPARISON :
+ {
+ int16_t value = m_search_->elementComparisonType;
+@@ -242,7 +241,7 @@ int32_t SearchIterator::next(UErrorCode &status)
+ int32_t matchindex = m_search_->matchedIndex;
+ int32_t matchlength = m_search_->matchedLength;
+ m_search_->reset = false;
+- if (m_search_->isForwardSearching == true) {
++ if (m_search_->isForwardSearching) {
+ int32_t textlength = m_search_->textLength;
+ if (offset == textlength || matchindex == textlength ||
+ (matchindex != USEARCH_DONE &&
+@@ -295,7 +294,7 @@ int32_t SearchIterator::previous(UErrorCode &status)
+ }
+
+ int32_t matchindex = m_search_->matchedIndex;
+- if (m_search_->isForwardSearching == true) {
++ if (m_search_->isForwardSearching) {
+ // switching direction.
+ // if matchedIndex == USEARCH_DONE, it means that either a
+ // setOffset has been called or that next ran off the text
+diff --git a/intl/icu/source/i18n/usearch.cpp b/intl/icu/source/i18n/usearch.cpp
+index 0fecd709e74..39f76a1b985 100644
+--- a/intl/icu/source/i18n/usearch.cpp
++++ b/intl/icu/source/i18n/usearch.cpp
+@@ -819,11 +819,9 @@ U_CAPI USearchAttributeValue U_EXPORT2 usearch_getAttribute(
+ if (strsrch) {
+ switch (attribute) {
+ case USEARCH_OVERLAP :
+- return (strsrch->search->isOverlap == true ? USEARCH_ON :
+- USEARCH_OFF);
++ return (strsrch->search->isOverlap ? USEARCH_ON : USEARCH_OFF);
+ case USEARCH_CANONICAL_MATCH :
+- return (strsrch->search->isCanonicalMatch == true ? USEARCH_ON :
+- USEARCH_OFF);
++ return (strsrch->search->isCanonicalMatch ? USEARCH_ON : USEARCH_OFF);
+ case USEARCH_ELEMENT_COMPARISON :
+ {
+ int16_t value = strsrch->search->elementComparisonType;
+@@ -1249,7 +1247,7 @@ U_CAPI int32_t U_EXPORT2 usearch_previous(UStringSearch *strsrch,
+ }
+
+ int32_t matchedindex = search->matchedIndex;
+- if (search->isForwardSearching == true) {
++ if (search->isForwardSearching) {
+ // switching direction.
+ // if matchedIndex == USEARCH_DONE, it means that either a
+ // setOffset has been called or that next ran off the text
+diff --git a/intl/icu/source/i18n/uspoof_conf.cpp b/intl/icu/source/i18n/uspoof_conf.cpp
+index 5ecc59c12a8..376ac64e3ce 100644
+--- a/intl/icu/source/i18n/uspoof_conf.cpp
++++ b/intl/icu/source/i18n/uspoof_conf.cpp
+@@ -407,7 +407,7 @@ void ConfusabledataBuilder::build(const char * confusables, int32_t confusablesL
+ //
+ void ConfusabledataBuilder::outputData(UErrorCode &status) {
+
+- U_ASSERT(fSpoofImpl->fSpoofData->fDataOwned == true);
++ U_ASSERT(fSpoofImpl->fSpoofData->fDataOwned);
+
+ // The Key Table
+ // While copying the keys to the runtime array,
+diff --git a/intl/icu/source/io/uscanf_p.cpp b/intl/icu/source/io/uscanf_p.cpp
+index 9b27e2ebf8d..26a790dd9b6 100644
+--- a/intl/icu/source/io/uscanf_p.cpp
++++ b/intl/icu/source/io/uscanf_p.cpp
+@@ -323,7 +323,7 @@ u_scanf_skip_leading_ws(UFILE *input,
+ UBool isNotEOF;
+
+ /* skip all leading ws in the input */
+- while( ((isNotEOF = ufile_getch(input, &c)) == true) && (c == pad || u_isWhitespace(c)) )
++ while( ((isNotEOF = ufile_getch(input, &c))==(UBool)true) && (c == pad || u_isWhitespace(c)) )
+ {
+ count++;
+ }
+@@ -357,7 +357,7 @@ u_scanf_skip_leading_positive_sign(UFILE *input,
+
+ if (U_SUCCESS(localStatus)) {
+ /* skip all leading ws in the input */
+- while( ((isNotEOF = ufile_getch(input, &c)) == true) && (count < symbolLen && c == plusSymbol[count]) )
++ while( ((isNotEOF = ufile_getch(input, &c))==(UBool)true) && (count < symbolLen && c == plusSymbol[count]) )
+ {
+ count++;
+ }
+@@ -868,7 +868,7 @@ u_scanf_string_handler(UFILE *input,
+ return -1;
+
+ while( (info->fWidth == -1 || count < info->fWidth)
+- && ((isNotEOF = ufile_getch(input, &c)) == true)
++ && ((isNotEOF = ufile_getch(input, &c))==(UBool)true)
+ && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
+ {
+
+@@ -959,7 +959,7 @@ u_scanf_ustring_handler(UFILE *input,
+ count = 0;
+
+ while( (info->fWidth == -1 || count < info->fWidth)
+- && ((isNotEOF = ufile_getch(input, &c)) == true)
++ && ((isNotEOF = ufile_getch(input, &c))==(UBool)true)
+ && (!info->fIsString || (c != info->fPadChar && !u_isWhitespace(c))))
+ {
+
+@@ -1262,7 +1262,7 @@ u_scanf_scanset_handler(UFILE *input,
+
+ /* grab characters one at a time and make sure they are in the scanset */
+ while(chLeft > 0) {
+- if ( ((isNotEOF = ufile_getch32(input, &c)) == true) && uset_contains(scanset, c) ) {
++ if ( ((isNotEOF = ufile_getch32(input, &c))==(UBool)true) && uset_contains(scanset, c) ) {
+ readCharacter = true;
+ if (!info->fSkipArg) {
+ int32_t idx = 0;
diff --git a/intl/icu-patches/bug-915735 b/intl/icu-patches/bug-915735
new file mode 100644
index 0000000000..c713581f8e
--- /dev/null
+++ b/intl/icu-patches/bug-915735
@@ -0,0 +1,28 @@
+Bug 915735 - Fix linking the ICU libraries on Mac
+
+diff --git a/intl/icu/source/config/mh-darwin b/intl/icu/source/config/mh-darwin
+--- a/intl/icu/source/config/mh-darwin
++++ b/intl/icu/source/config/mh-darwin
+@@ -25,21 +25,17 @@ ARFLAGS += -c
+ COMPILE.c= $(CC) $(DEFS) $(CPPFLAGS) $(CFLAGS) -fno-common -c
+ COMPILE.cc= $(CXX) $(DEFS) $(CPPFLAGS) $(CXXFLAGS) -fno-common -c
+
+ ## Commands to make a shared library
+ SHLIB.c= $(CC) -dynamiclib -dynamic $(CFLAGS) $(LDFLAGS) $(LD_SOOPTIONS)
+ SHLIB.cc= $(CXX) -dynamiclib -dynamic $(CXXFLAGS) $(LDFLAGS) $(LD_SOOPTIONS)
+
+ ## Compiler switches to embed a library name and version information
+-ifeq ($(ENABLE_RPATH),YES)
+-LD_SONAME = -Wl,-compatibility_version -Wl,$(SO_TARGET_VERSION_MAJOR) -Wl,-current_version -Wl,$(SO_TARGET_VERSION) -install_name $(libdir)/$(notdir $(MIDDLE_SO_TARGET))
+-else
+-LD_SONAME = -Wl,-compatibility_version -Wl,$(SO_TARGET_VERSION_MAJOR) -Wl,-current_version -Wl,$(SO_TARGET_VERSION) -install_name $(notdir $(MIDDLE_SO_TARGET)) $(PKGDATA_TRAILING_SPACE)
+-endif
++LD_SONAME = -Wl,-compatibility_version -Wl,$(SO_TARGET_VERSION_MAJOR) -Wl,-current_version -Wl,$(SO_TARGET_VERSION) -install_name @executable_path/$(notdir $(MIDDLE_SO_TARGET)) $(PKGDATA_TRAILING_SPACE)
+
+ ## Compiler switch to embed a runtime search path
+ LD_RPATH=
+ LD_RPATH_PRE= -Wl,-rpath,
+
+ ## Environment variable to set a runtime search path
+ LDLIBRARYPATH_ENVVAR = DYLD_LIBRARY_PATH
+
diff --git a/intl/icu-patches/suppress-warnings.diff b/intl/icu-patches/suppress-warnings.diff
new file mode 100644
index 0000000000..e124a1689d
--- /dev/null
+++ b/intl/icu-patches/suppress-warnings.diff
@@ -0,0 +1,80 @@
+diff --git a/intl/icu/source/acinclude.m4 b/intl/icu/source/acinclude.m4
+--- a/intl/icu/source/acinclude.m4
++++ b/intl/icu/source/acinclude.m4
+@@ -469,30 +469,36 @@ AC_DEFUN([AC_CHECK_STRICT_COMPILE],
+ *)
+ # Do not use -ansi. It limits us to C90, and it breaks some platforms.
+ # We use -std=c11 to disable the gnu99 defaults and its associated warnings
+ CFLAGS="$CFLAGS -std=c11"
+ ;;
+ esac
+
+ CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings"
++
++ # Suppress clang C warnings:
++ CFLAGS="$CFLAGS -Wno-sign-compare -Wno-unused"
+ else
+ case "${host}" in
+ *-*-cygwin)
+ if test "`$CC /help 2>&1 | head -c9`" = "Microsoft"
+ then
+ CFLAGS="$CFLAGS /W4"
+ fi ;;
+ *-*-mingw*)
+ CFLAGS="$CFLAGS -W4" ;;
+ esac
+ fi
+ if test "$GXX" = yes
+ then
+ CXXFLAGS="$CXXFLAGS -W -Wall -pedantic -Wpointer-arith -Wwrite-strings -Wno-long-long"
++
++ # Suppress clang C++ warnings:
++ CXXFLAGS="$CXXFLAGS -Wno-unused -Wno-unused-parameter"
+ else
+ case "${host}" in
+ *-*-cygwin)
+ if test "`$CXX /help 2>&1 | head -c9`" = "Microsoft"
+ then
+ CXXFLAGS="$CXXFLAGS /W4"
+ fi ;;
+ *-*-mingw*)
+diff --git a/intl/icu/source/configure b/intl/icu/source/configure
+--- a/intl/icu/source/configure
++++ b/intl/icu/source/configure
+@@ -4359,30 +4359,36 @@ fi
+ *)
+ # Do not use -ansi. It limits us to C90, and it breaks some platforms.
+ # We use -std=c11 to disable the gnu99 defaults and its associated warnings
+ CFLAGS="$CFLAGS -std=c11"
+ ;;
+ esac
+
+ CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wpointer-arith -Wmissing-prototypes -Wwrite-strings"
++
++ # Suppress clang C warnings:
++ CFLAGS="$CFLAGS -Wno-sign-compare -Wno-unused"
+ else
+ case "${host}" in
+ *-*-cygwin)
+ if test "`$CC /help 2>&1 | head -c9`" = "Microsoft"
+ then
+ CFLAGS="$CFLAGS /W4"
+ fi ;;
+ *-*-mingw*)
+ CFLAGS="$CFLAGS -W4" ;;
+ esac
+ fi
+ if test "$GXX" = yes
+ then
+ CXXFLAGS="$CXXFLAGS -W -Wall -pedantic -Wpointer-arith -Wwrite-strings -Wno-long-long"
++
++ # Suppress clang C++ warnings:
++ CXXFLAGS="$CXXFLAGS -Wno-unused -Wno-unused-parameter"
+ else
+ case "${host}" in
+ *-*-cygwin)
+ if test "`$CXX /help 2>&1 | head -c9`" = "Microsoft"
+ then
+ CXXFLAGS="$CXXFLAGS /W4"
+ fi ;;
+ *-*-mingw*)