Submitted By: Marty Jack Date: 2026-10-27 Initial Package Version: 6.11.3 Upstream Status: Unknown Origin: Port of a patch applying to node.js Description: Fixes building qtwebengine with icu-79. # Patch made by Jakob Linke diff -Naur qtwebengine-6.11.3.orig/src/3rdparty/chromium/v8/src/regexp/gen-regexp-special-case.cc qtwebengine-6.11.3/src/3rdparty/chromium/v8/src/regexp/gen-regexp-special-case.cc --- qtwebengine-6.11.3.orig/src/3rdparty/chromium/v8/src/regexp/gen-regexp-special-case.cc 2026-10-20 20:29:58.000000000 -0400 +++ qtwebengine-6.11.3/src/3rdparty/chromium/v8/src/regexp/gen-regexp-special-case.cc 2026-10-27 13:13:55.491370284 -0400 @@ -9,6 +9,7 @@ #include "src/base/strings.h" #include "src/regexp/special-case.h" +#include "unicode/uchar.h" namespace v8 { namespace internal { @@ -17,6 +18,19 @@ static const base::uc32 kSurrogateEnd = 0xdfff; static const base::uc32 kNonBmpStart = 0x10000; +// Removes supplementary code points from |set| and returns whether any were +// present. Since Unicode 18, the case closure of a BMP character can contain +// supplementary code points (U+1DF95 LATIN SMALL LIGATURE LONG S WITH +// DESCENDER S case-folds to U+00DF LATIN SMALL LETTER SHARP S). Non-unicode +// ignoreCase matching compares UTF-16 code units, so a supplementary code +// point never matches a BMP character and does not take part in Canonicalize. +bool RemoveSupplementary(icu::UnicodeSet& set) { + constexpr UChar32 kFirstSupplementary = static_cast(kNonBmpStart); + if (!set.containsSome(kFirstSupplementary, UCHAR_MAX_VALUE)) return false; + set.remove(kFirstSupplementary, UCHAR_MAX_VALUE); + return true; +} + // The following code generates "src/regexp/special-case.cc". void PrintSet(std::ofstream& out, const char* name, const icu::UnicodeSet& set) { @@ -51,6 +65,7 @@ icu::UnicodeSet current; icu::UnicodeSet special_add; icu::UnicodeSet ignore; + icu::UnicodeSet supplementary_equivalents; UErrorCode status = U_ZERO_ERROR; icu::UnicodeSet upper("[\\p{Lu}]", status); CHECK(U_SUCCESS(status)); @@ -63,6 +78,7 @@ } current.set(i, i); current.closeOver(USET_CASE_INSENSITIVE); + if (RemoveSupplementary(current)) supplementary_equivalents.add(i); // Check to see if all characters in the case-folding equivalence // class as defined by UnicodeSet::closeOver all map to the same @@ -112,6 +128,7 @@ UChar32 canonical = RegExpCaseFolding::Canonicalize(c); current.set(c, c); current.closeOver(USET_CASE_INSENSITIVE); + RemoveSupplementary(current); current.removeAll(ignore); for (int32_t j = 0; j < current.getRangeCount(); j++) { for (UChar32 c2 = current.getRangeStart(j); @@ -124,6 +141,7 @@ PrintSet(out, "IgnoreSet", ignore); PrintSet(out, "SpecialAddSet", special_add); + PrintSet(out, "SupplementaryEquivalentsSet", supplementary_equivalents); } void WriteHeader(const char* header_filename) { diff -Naur qtwebengine-6.11.3.orig/src/3rdparty/chromium/v8/src/regexp/regexp-parser.cc qtwebengine-6.11.3/src/3rdparty/chromium/v8/src/regexp/regexp-parser.cc --- qtwebengine-6.11.3.orig/src/3rdparty/chromium/v8/src/regexp/regexp-parser.cc 2026-10-20 20:29:58.000000000 -0400 +++ qtwebengine-6.11.3/src/3rdparty/chromium/v8/src/regexp/regexp-parser.cc 2026-10-27 13:13:55.507886066 -0400 @@ -9,6 +9,7 @@ #include "src/regexp/regexp-ast.h" #include "src/regexp/regexp-macro-assembler.h" #include "src/regexp/regexp.h" +#include "src/regexp/special-case.h" #include "src/strings/char-predicates-inl.h" #include "src/utils/ostreams.h" #include "src/utils/utils.h" @@ -155,6 +156,10 @@ void RegExpTextBuilder::AddCharacter(base::uc16 c) { FlushPendingSurrogate(); + if (NeedsDesugaringForIgnoreCase(c)) { + AddClassRangesForDesugaring(c); + return; + } if (characters_ == nullptr) { characters_ = zone()->New>(4, zone()); } @@ -237,15 +242,18 @@ return false; } -// We only use this for characters made of surrogate pairs. All other -// characters outside of character classes are made case independent in the -// code generation. +// Desugar supplementary characters with case equivalents and BMP characters +// with supplementary equivalents. Other atoms are folded during code +// generation. bool RegExpTextBuilder::NeedsDesugaringForIgnoreCase(base::uc32 c) { #ifdef V8_INTL_SUPPORT if (IsUnicodeMode() && ignore_case()) { + if (c <= unibrow::Utf16::kMaxNonSurrogateCharCode) { + return RegExpCaseFolding::HasSupplementaryEquivalents( + static_cast(c)); + } icu::UnicodeSet set(c, c); - set.closeOver(USET_CASE_INSENSITIVE); - set.removeAllStrings(); + RegExpCaseFolding::CloseOver(set, RegExpCaseFolding::Mode::kUnicode); return set.size() > 1; } // In the case where ICU is not included, we act as if the unicode flag is diff -Naur qtwebengine-6.11.3.orig/src/3rdparty/chromium/v8/src/regexp/special-case.h qtwebengine-6.11.3/src/3rdparty/chromium/v8/src/regexp/special-case.h --- qtwebengine-6.11.3.orig/src/3rdparty/chromium/v8/src/regexp/special-case.h 2026-10-20 20:29:58.000000000 -0400 +++ qtwebengine-6.11.3/src/3rdparty/chromium/v8/src/regexp/special-case.h 2026-10-27 13:13:55.501631975 -0400 @@ -7,8 +7,8 @@ #ifdef V8_INTL_SUPPORT #include "src/base/logging.h" +#include "src/base/strings.h" #include "src/common/globals.h" - #include "unicode/uchar.h" #include "unicode/uniset.h" #include "unicode/unistr.h" @@ -71,9 +71,17 @@ // another character. Characters that match no other characters in // their equivalence class are added to IgnoreSet. Characters that // match at least one other character are added to SpecialAddSet. +// Supplementary code points are ignored throughout: non-unicode matching +// compares UTF-16 code units, so they can never match a BMP character. +// +// The generator additionally emits SupplementaryEquivalentsSet, the BMP +// characters whose Unicode case closure contains supplementary code points. +// This set is used for unicode-mode matching, see HasSupplementaryEquivalents. class RegExpCaseFolding final : public AllStatic { public: + enum class Mode { kNonUnicode, kUnicode }; + static const icu::UnicodeSet& IgnoreSet(); static const icu::UnicodeSet& SpecialAddSet(); @@ -108,6 +116,43 @@ // h. Return cu. return cu; } + + // Close a set of characters under case equivalence, preserving its + // original members. Non-unicode inputs must be UTF-16 code units. + static void CloseOver(icu::UnicodeSet& set, Mode mode) { + if (mode == Mode::kUnicode) { + set.closeOver(USET_SIMPLE_CASE_INSENSITIVE); + return; + } + DCHECK(!set.containsSome(0x10000, 0x10ffff)); + if (IgnoreSet().containsNone(set)) { + CloseOverNonUnicode(set); + return; + } + if (IgnoreSet().containsAll(set)) return; + // Ignored characters neither contribute nor acquire equivalents, but + // must remain in the result if they were explicitly present. + icu::UnicodeSet ignored(set); + ignored.retainAll(IgnoreSet()); + set.removeAll(IgnoreSet()); + CloseOverNonUnicode(set); + set.addAll(ignored); + } + + // Whether c has supplementary Unicode case equivalents. + static bool HasSupplementaryEquivalents(base::uc16 c) { + return SupplementaryEquivalentsSet().contains(c); + } + + private: + static const icu::UnicodeSet& SupplementaryEquivalentsSet(); + + // Requires a set containing no IgnoreSet characters. + static void CloseOverNonUnicode(icu::UnicodeSet& set) { + set.closeOver(USET_SIMPLE_CASE_INSENSITIVE); + set.removeAll(IgnoreSet()); + set.remove(0x10000, 0x10ffff); + } }; } // namespace internal