LibUnicode: Print error codes when calls to ICU fail

Primary motivation for this change is the `VERIFY(icu_success(status))`
line in `Segmenter::create()` that was failing on multiple systems and
where we had to ask people to apply a patch to even know what the error
was.

Since this seems to be a recurring problem, let's just add a little
helper function and print the error codes returned by library calls.
This commit is contained in:
InvalidUsernameException
2026-02-21 18:12:46 +01:00
committed by Tim Flynn
parent 77a3de4561
commit 1b2bca7831
Notes: github-actions[bot] 2026-02-21 21:56:43 +00:00
9 changed files with 41 additions and 32 deletions

View File

@@ -45,7 +45,7 @@ static NonnullOwnPtr<icu::Locale> apply_usage_to_locale(icu::Locale const& local
break;
}
VERIFY(icu_success(status));
verify_icu_success(status);
return result;
}
@@ -97,12 +97,12 @@ static Sensitivity sensitivity_for_collator(icu::Collator const& collator)
UErrorCode status = U_ZERO_ERROR;
auto attribute = collator.getAttribute(UCOL_STRENGTH, status);
VERIFY(icu_success(status));
verify_icu_success(status);
switch (attribute) {
case UCOL_PRIMARY:
attribute = collator.getAttribute(UCOL_CASE_LEVEL, status);
VERIFY(icu_success(status));
verify_icu_success(status);
return attribute == UCOL_ON ? Sensitivity::Case : Sensitivity::Base;
@@ -156,7 +156,7 @@ static bool ignore_punctuation_for_collator(icu::Collator const& collator)
UErrorCode status = U_ZERO_ERROR;
auto attribute = collator.getAttribute(UCOL_ALTERNATE_HANDLING, status);
VERIFY(icu_success(status));
verify_icu_success(status);
return attribute == UCOL_SHIFTED;
}
@@ -176,7 +176,7 @@ public:
auto rhs_it = icu_string_iterator(rhs);
auto result = m_collator->compare(lhs_it, rhs_it, status);
VERIFY(icu_success(status));
verify_icu_success(status);
switch (result) {
case UCOL_LESS:
@@ -221,11 +221,11 @@ NonnullOwnPtr<Collator> Collator::create(
auto locale_with_usage = apply_usage_to_locale(locale_data->locale(), usage, collation);
auto collator = adopt_own(*icu::Collator::createInstance(*locale_with_usage, status));
VERIFY(icu_success(status));
verify_icu_success(status);
auto set_attribute = [&](UColAttribute attribute, UColAttributeValue value) {
collator->setAttribute(attribute, value, status);
VERIFY(icu_success(status));
verify_icu_success(status);
};
if (!sensitivity.has_value())

View File

@@ -625,7 +625,7 @@ static void apply_time_zone_to_formatter(icu::SimpleDateFormat& formatter, icu::
auto time_zone_data = TimeZoneData::for_time_zone(time_zone_identifier);
auto* calendar = icu::Calendar::createInstance(time_zone_data->time_zone(), locale, status);
VERIFY(icu_success(status));
verify_icu_success(status);
if (calendar->getDynamicClassID() == icu::GregorianCalendar::getStaticClassID()) {
// https://tc39.es/ecma262/#sec-time-values-and-time-range
@@ -634,7 +634,7 @@ static void apply_time_zone_to_formatter(icu::SimpleDateFormat& formatter, icu::
auto* gregorian_calendar = static_cast<icu::GregorianCalendar*>(calendar);
gregorian_calendar->setGregorianChange(ECMA_262_MINIMUM_TIME, status);
VERIFY(icu_success(status));
verify_icu_success(status);
}
formatter.adoptCalendar(calendar);
@@ -903,16 +903,16 @@ NonnullOwnPtr<DateTimeFormat> DateTimeFormat::create_for_date_and_time_style(
formatter->toPattern(pattern);
auto skeleton = icu::DateTimePatternGenerator::staticGetSkeleton(pattern, status);
VERIFY(icu_success(status));
verify_icu_success(status);
if (apply_hour_cycle_to_skeleton(skeleton, hour_cycle, hour12)) {
pattern = locale_data->date_time_pattern_generator().getBestPattern(skeleton, UDATPG_MATCH_ALL_FIELDS_LENGTH, status);
VERIFY(icu_success(status));
verify_icu_success(status);
apply_hour_cycle_to_skeleton(pattern, hour_cycle, hour12);
formatter = adopt_own(*new icu::SimpleDateFormat(pattern, locale_data->locale(), status));
VERIFY(icu_success(status));
verify_icu_success(status);
}
return adopt_own(*new DateTimeFormatImpl(locale_data->locale(), pattern, time_zone_identifier, move(formatter)));
@@ -930,12 +930,12 @@ NonnullOwnPtr<DateTimeFormat> DateTimeFormat::create_for_pattern_options(
auto skeleton = icu_string(options.to_pattern());
auto pattern = locale_data->date_time_pattern_generator().getBestPattern(skeleton, UDATPG_MATCH_ALL_FIELDS_LENGTH, status);
VERIFY(icu_success(status));
verify_icu_success(status);
apply_hour_cycle_to_skeleton(pattern, options.hour_cycle, {});
auto formatter = adopt_own(*new icu::SimpleDateFormat(pattern, locale_data->locale(), status));
VERIFY(icu_success(status));
verify_icu_success(status);
return adopt_own(*new DateTimeFormatImpl(locale_data->locale(), pattern, time_zone_identifier, move(formatter)));
}

View File

@@ -51,7 +51,7 @@ String LocaleData::to_string()
UErrorCode status = U_ZERO_ERROR;
auto result = locale().toLanguageTag<StringBuilder>(status);
VERIFY(icu_success(status));
verify_icu_success(status);
m_locale_string = MUST(result.to_string());
}
@@ -83,7 +83,7 @@ icu::NumberingSystem& LocaleData::numbering_system()
status = U_ZERO_ERROR;
m_numbering_system = adopt_own_if_nonnull(icu::NumberingSystem::createInstance("und", status));
VERIFY(icu_success(status));
verify_icu_success(status);
}
}
@@ -96,7 +96,7 @@ icu::DateTimePatternGenerator& LocaleData::date_time_pattern_generator()
UErrorCode status = U_ZERO_ERROR;
m_date_time_pattern_generator = adopt_own(*icu::DateTimePatternGenerator::createInstance(locale(), status));
VERIFY(icu_success(status));
verify_icu_success(status);
}
return *m_date_time_pattern_generator;
@@ -108,7 +108,7 @@ icu::TimeZoneNames& LocaleData::time_zone_names()
UErrorCode status = U_ZERO_ERROR;
m_time_zone_names = adopt_own(*icu::TimeZoneNames::createInstance(locale(), status));
VERIFY(icu_success(status));
verify_icu_success(status);
}
return *m_time_zone_names;

View File

@@ -8,6 +8,7 @@
#include <AK/Optional.h>
#include <AK/OwnPtr.h>
#include <AK/SourceLocation.h>
#include <AK/String.h>
#include <AK/StringView.h>
#include <AK/Utf16String.h>
@@ -89,6 +90,14 @@ constexpr bool icu_failure(UErrorCode code)
return static_cast<bool>(U_FAILURE(code));
}
inline void verify_icu_success(UErrorCode code, SourceLocation location = SourceLocation::current())
{
if (icu_failure(code)) [[unlikely]] {
dbgln("\033[31;1mICU error\033[0m: {} {}", u_errorName(code), location);
VERIFY_NOT_REACHED();
}
}
ALWAYS_INLINE icu::StringPiece icu_string_piece(StringView string)
{
return { string.characters_without_null_termination(), static_cast<i32>(string.length()) };

View File

@@ -149,7 +149,7 @@ NonnullOwnPtr<ListFormat> ListFormat::create(StringView locale, ListFormatType t
VERIFY(locale_data.has_value());
auto formatter = adopt_own(*icu::ListFormatter::createInstance(locale_data->locale(), icu_list_format_type(type), icu_list_format_width(style), status));
VERIFY(icu_success(status));
verify_icu_success(status);
return adopt_own(*new ListFormatImpl(move(formatter)));
}

View File

@@ -484,7 +484,7 @@ String canonicalize_unicode_locale_id(StringView locale)
VERIFY(locale_data.has_value());
locale_data->locale().canonicalize(status);
VERIFY(icu_success(status));
verify_icu_success(status);
return locale_data->to_string();
}
@@ -497,13 +497,13 @@ String canonicalize_unicode_extension_values(StringView key, StringView value)
builder.setUnicodeLocaleKeyword(icu_string_piece(key), icu_string_piece(value));
auto locale = builder.build(status);
VERIFY(icu_success(status));
verify_icu_success(status);
locale.canonicalize(status);
VERIFY(icu_success(status));
verify_icu_success(status);
auto result = locale.getUnicodeKeywordValue<StringBuilder>(icu_string_piece(key), status);
VERIFY(icu_success(status));
verify_icu_success(status);
return MUST(result.to_string());
}
@@ -602,7 +602,7 @@ static void apply_extensions_to_locale(icu::Locale& locale, icu::Locale const& l
builder.setVariant(locale.getVariant());
locale = builder.build(status);
VERIFY(icu_success(status));
verify_icu_success(status);
}
Optional<String> add_likely_subtags(StringView locale)

View File

@@ -441,13 +441,13 @@ static void apply_display_options(icu::number::LocalizedNumberFormatter& formatt
case NumberFormatStyle::Currency:
formatter = formatter.unit(icu::CurrencyUnit(icu_string_piece(*display_options.currency), status));
formatter = formatter.unitWidth(icu_currency_display(*display_options.currency_display));
VERIFY(icu_success(status));
verify_icu_success(status);
break;
case NumberFormatStyle::Unit:
formatter = formatter.unit(icu::MeasureUnit::forIdentifier(icu_string_piece(*display_options.unit), status));
formatter = formatter.unitWidth(icu_unit_width(*display_options.unit_display));
VERIFY(icu_success(status));
verify_icu_success(status);
break;
}
@@ -655,7 +655,7 @@ public:
VERIFY(!m_plural_rules);
m_plural_rules = adopt_own(*icu::PluralRules::forLocale(m_locale, icu_plural_type(plural_form), status));
VERIFY(icu_success(status));
verify_icu_success(status);
}
virtual PluralCategory select_plural(Value const& value) const override
@@ -730,7 +730,7 @@ private:
auto formattable = value.visit(
[&](double number) { return icu::Formattable { number }; },
[&](String const& number) { return icu::Formattable(icu_string_piece(number), status); });
VERIFY(icu_success(status));
verify_icu_success(status);
return formattable;
}

View File

@@ -248,7 +248,7 @@ NonnullOwnPtr<RelativeTimeFormat> RelativeTimeFormat::create(StringView locale,
static_cast<icu::DecimalFormat&>(*number_formatter).setMinimumGroupingDigits(UNUM_MINIMUM_GROUPING_DIGITS_AUTO);
auto formatter = make<icu::RelativeDateTimeFormatter>(locale_data->locale(), number_formatter, icu_relative_date_time_style(style), UDISPCTX_CAPITALIZATION_NONE, status);
VERIFY(icu_success(status));
verify_icu_success(status);
return make<RelativeTimeFormatImpl>(move(formatter));
}

View File

@@ -155,10 +155,10 @@ public:
UText utext = UTEXT_INITIALIZER;
utext_openUTF8(&utext, view.characters_without_null_termination(), static_cast<i64>(view.length()), &status);
VERIFY(icu_success(status));
verify_icu_success(status);
m_segmenter->setText(&utext, status);
VERIFY(icu_success(status));
verify_icu_success(status);
utext_close(&utext);
}
@@ -334,7 +334,7 @@ NonnullOwnPtr<Segmenter> Segmenter::create(StringView locale, SegmenterGranulari
VERIFY_NOT_REACHED();
}());
VERIFY(icu_success(status));
verify_icu_success(status);
return make<SegmenterImpl>(segmenter.release_nonnull(), segmenter_granularity);
}