From 318d0cc07277fd156cd1add0f06fc94b4d0676cc Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Fri, 22 Dec 2023 17:03:23 +0800
Subject: [PATCH 001/105] Implement `sprintf "%g"` in Crystal (#14123)

---
 spec/std/float_printer/ryu_printf_spec.cr     |  947 ++++++++++
 .../float_printer/ryu_printf_test_cases.cr    | 1670 +++++++++++++++++
 spec/std/sprintf_spec.cr                      |  211 ++-
 src/float/printer/ryu_printf.cr               |   77 +
 src/float/printer/ryu_printf_table.cr         |  527 ++++++
 src/string/formatter.cr                       |   33 +-
 6 files changed, 3458 insertions(+), 7 deletions(-)

diff --git a/spec/std/float_printer/ryu_printf_spec.cr b/spec/std/float_printer/ryu_printf_spec.cr
index d4ba77bffd94..4610485f2270 100644
--- a/spec/std/float_printer/ryu_printf_spec.cr
+++ b/spec/std/float_printer/ryu_printf_spec.cr
@@ -4,6 +4,7 @@
 # This file contains test cases derived from:
 #
 # * https://github.com/ulfjack/ryu
+# * https://github.com/microsoft/STL/tree/main/tests/std/tests/P0067R5_charconv
 #
 # The following is their license:
 #
@@ -25,6 +26,7 @@
 #   KIND, either express or implied.
 
 require "spec"
+require "../../support/number"
 require "float/printer/ryu_printf"
 require "big"
 require "./ryu_printf_test_cases"
@@ -118,6 +120,10 @@ private macro expect_exp(float, precision, string)
   Float::Printer::RyuPrintf.d2exp({{ float }}, {{ precision }}).should eq({{ string }})
 end
 
+private macro expect_gen(float, precision, string, *, file = __FILE__, line = __LINE__)
+  Float::Printer::RyuPrintf.d2gen({{ float }}, {{ precision }}).should eq({{ string }}), file: {{ file }}, line: {{ line }}
+end
+
 describe Float::Printer::RyuPrintf do
   describe ".d2fixed" do
     it "Basic" do
@@ -491,4 +497,945 @@ describe Float::Printer::RyuPrintf do
       expect_exp(1e+83, 1, "1.0e+83")
     end
   end
+
+  describe ".d2gen" do
+    it "Basic" do
+      expect_gen(0.0, 4, "0")
+      expect_gen(1.729, 4, "1.729")
+    end
+
+    it "corner cases" do
+      expect_gen(Float64::MIN_SUBNORMAL, 1000,
+        "4.940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625e-324")
+      expect_gen(Float64::MIN_POSITIVE.prev_float, 1000,
+        "2.2250738585072008890245868760858598876504231122409594654935248025624400092282356951787758888037591552642309780950434312085877387158357291821993020294379224223559819827501242041788969571311791082261043971979604000454897391938079198936081525613113376149842043271751033627391549782731594143828136275113838604094249464942286316695429105080201815926642134996606517803095075913058719846423906068637102005108723282784678843631944515866135041223479014792369585208321597621066375401613736583044193603714778355306682834535634005074073040135602968046375918583163124224521599262546494300836851861719422417646455137135420132217031370496583210154654068035397417906022589503023501937519773030945763173210852507299305089761582519159720757232455434770912461317493580281734466552734375e-308")
+      expect_gen(Float64::MIN_POSITIVE, 1000,
+        "2.225073858507201383090232717332404064219215980462331830553327416887204434813918195854283159012511020564067339731035811005152434161553460108856012385377718821130777993532002330479610147442583636071921565046942503734208375250806650616658158948720491179968591639648500635908770118304874799780887753749949451580451605050915399856582470818645113537935804992115981085766051992433352114352390148795699609591288891602992641511063466313393663477586513029371762047325631781485664350872122828637642044846811407613911477062801689853244110024161447421618567166150540154285084716752901903161322778896729707373123334086988983175067838846926092773977972858659654941091369095406136467568702398678315290680984617210924625396728515625e-308")
+      expect_gen(Float64::MAX, 1000,
+        "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368")
+
+      expect_gen(Float64::MIN_SUBNORMAL, 6, "4.94066e-324")
+      expect_gen(Float64::MIN_POSITIVE.prev_float, 6, "2.22507e-308")
+      expect_gen(Float64::MIN_POSITIVE, 6, "2.22507e-308")
+      expect_gen(Float64::MAX, 6, "1.79769e+308")
+    end
+
+    it "maximum-length output" do
+      expect_gen(hexfloat("0x1.fffffffffffffp-1022"), 1000,
+        "4.4501477170144022721148195934182639518696390927032912960468522194496444440421538910330590478162701758282983178260792422137401728773891892910553144148156412434867599762821265346585071045737627442980259622449029037796981144446145705102663115100318287949527959668236039986479250965780342141637013812613333119898765515451440315261253813266652951306000184917766328660755595837392240989947807556594098101021612198814605258742579179000071675999344145086087205681577915435923018910334964869420614052182892431445797605163650903606514140377217442262561590244668525767372446430075513332450079650686719491377688478005309963967709758965844137894433796621993967316936280457084866613206797017728916080020698679408551343728867675409720757232455434770912461317493580281734466552734375e-308")
+      expect_gen(hexfloat("0x1.fffffffffffffp-14"), 1000,
+        "0.000122070312499999986447472843931194574906839989125728607177734375")
+    end
+
+    it "varying precision" do
+      expect_gen(hexfloat("0x1.b04p0"), 0, "2")
+      expect_gen(hexfloat("0x1.b04p0"), 1, "2") # fixed notation trims decimal point
+      expect_gen(hexfloat("0x1.b04p0"), 2, "1.7")
+      expect_gen(hexfloat("0x1.b04p0"), 3, "1.69")
+      expect_gen(hexfloat("0x1.b04p0"), 4, "1.688")
+      expect_gen(hexfloat("0x1.b04p0"), 5, "1.6885")
+      expect_gen(hexfloat("0x1.b04p0"), 6, "1.68848")
+      expect_gen(hexfloat("0x1.b04p0"), 7, "1.688477")
+      expect_gen(hexfloat("0x1.b04p0"), 8, "1.6884766")
+      expect_gen(hexfloat("0x1.b04p0"), 9, "1.68847656")
+      expect_gen(hexfloat("0x1.b04p0"), 10, "1.688476562")  # round to even
+      expect_gen(hexfloat("0x1.b04p0"), 11, "1.6884765625") # exact
+      expect_gen(hexfloat("0x1.b04p0"), 12, "1.6884765625") # trim trailing zeros
+      expect_gen(hexfloat("0x1.b04p0"), 13, "1.6884765625")
+
+      expect_gen(hexfloat("0x1.8p-15"), 0, "5e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 1, "5e-5") # scientific notation trims decimal point
+      expect_gen(hexfloat("0x1.8p-15"), 2, "4.6e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 3, "4.58e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 4, "4.578e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 5, "4.5776e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 6, "4.57764e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 7, "4.577637e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 8, "4.5776367e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 9, "4.57763672e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 10, "4.577636719e-5")
+      expect_gen(hexfloat("0x1.8p-15"), 11, "4.5776367188e-5")  # round to even
+      expect_gen(hexfloat("0x1.8p-15"), 12, "4.57763671875e-5") # exact
+      expect_gen(hexfloat("0x1.8p-15"), 13, "4.57763671875e-5") # trim trailing zeros
+      expect_gen(hexfloat("0x1.8p-15"), 14, "4.57763671875e-5")
+    end
+
+    it "trim trailing zeros" do
+      expect_gen(hexfloat("0x1.80015p0"), 1, "2") # fixed notation trims decimal point
+      expect_gen(hexfloat("0x1.80015p0"), 2, "1.5")
+      expect_gen(hexfloat("0x1.80015p0"), 3, "1.5") # general trims trailing zeros
+      expect_gen(hexfloat("0x1.80015p0"), 4, "1.5")
+      expect_gen(hexfloat("0x1.80015p0"), 5, "1.5")
+      expect_gen(hexfloat("0x1.80015p0"), 6, "1.50002")
+      expect_gen(hexfloat("0x1.80015p0"), 7, "1.50002")
+      expect_gen(hexfloat("0x1.80015p0"), 8, "1.50002")
+      expect_gen(hexfloat("0x1.80015p0"), 9, "1.50002003")
+      expect_gen(hexfloat("0x1.80015p0"), 10, "1.500020027")
+      expect_gen(hexfloat("0x1.80015p0"), 11, "1.5000200272")
+      expect_gen(hexfloat("0x1.80015p0"), 12, "1.50002002716")
+      expect_gen(hexfloat("0x1.80015p0"), 13, "1.500020027161")
+      expect_gen(hexfloat("0x1.80015p0"), 14, "1.5000200271606")
+      expect_gen(hexfloat("0x1.80015p0"), 15, "1.50002002716064")
+      expect_gen(hexfloat("0x1.80015p0"), 16, "1.500020027160645")
+      expect_gen(hexfloat("0x1.80015p0"), 17, "1.5000200271606445")
+      expect_gen(hexfloat("0x1.80015p0"), 18, "1.50002002716064453")
+      expect_gen(hexfloat("0x1.80015p0"), 19, "1.500020027160644531")
+      expect_gen(hexfloat("0x1.80015p0"), 20, "1.5000200271606445312")  # round to even
+      expect_gen(hexfloat("0x1.80015p0"), 21, "1.50002002716064453125") # exact
+    end
+
+    it "trim trailing zeros and decimal point" do
+      expect_gen(hexfloat("0x1.00015p0"), 1, "1") # fixed notation trims decimal point
+      expect_gen(hexfloat("0x1.00015p0"), 2, "1") # general trims decimal point and trailing zeros
+      expect_gen(hexfloat("0x1.00015p0"), 3, "1")
+      expect_gen(hexfloat("0x1.00015p0"), 4, "1")
+      expect_gen(hexfloat("0x1.00015p0"), 5, "1")
+      expect_gen(hexfloat("0x1.00015p0"), 6, "1.00002")
+      expect_gen(hexfloat("0x1.00015p0"), 7, "1.00002")
+      expect_gen(hexfloat("0x1.00015p0"), 8, "1.00002")
+      expect_gen(hexfloat("0x1.00015p0"), 9, "1.00002003")
+      expect_gen(hexfloat("0x1.00015p0"), 10, "1.000020027")
+      expect_gen(hexfloat("0x1.00015p0"), 11, "1.0000200272")
+      expect_gen(hexfloat("0x1.00015p0"), 12, "1.00002002716")
+      expect_gen(hexfloat("0x1.00015p0"), 13, "1.000020027161")
+      expect_gen(hexfloat("0x1.00015p0"), 14, "1.0000200271606")
+      expect_gen(hexfloat("0x1.00015p0"), 15, "1.00002002716064")
+      expect_gen(hexfloat("0x1.00015p0"), 16, "1.000020027160645")
+      expect_gen(hexfloat("0x1.00015p0"), 17, "1.0000200271606445")
+      expect_gen(hexfloat("0x1.00015p0"), 18, "1.00002002716064453")
+      expect_gen(hexfloat("0x1.00015p0"), 19, "1.000020027160644531")
+      expect_gen(hexfloat("0x1.00015p0"), 20, "1.0000200271606445312")  # round to even
+      expect_gen(hexfloat("0x1.00015p0"), 21, "1.00002002716064453125") # exact
+    end
+
+    it "trim trailing zeros, scientific notation" do
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 1, "1e-6") # scientific notation trims decimal point
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 2, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 3, "1.3e-6") # general trims trailing zeros
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 4, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 5, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 6, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 7, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 8, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 9, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 10, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 11, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 12, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 13, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 14, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 15, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 16, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 17, "1.3e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 18, "1.30000000000000005e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 19, "1.300000000000000047e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 20, "1.3000000000000000471e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 21, "1.30000000000000004705e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 22, "1.300000000000000047052e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 23, "1.3000000000000000470517e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 24, "1.30000000000000004705166e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 25, "1.300000000000000047051664e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 26, "1.3000000000000000470516638e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 27, "1.30000000000000004705166378e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 28, "1.30000000000000004705166378e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 29, "1.3000000000000000470516637804e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 30, "1.30000000000000004705166378044e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 31, "1.30000000000000004705166378044e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 32, "1.3000000000000000470516637804397e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 33, "1.30000000000000004705166378043968e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 34, "1.300000000000000047051663780439679e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 35, "1.3000000000000000470516637804396787e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 36, "1.30000000000000004705166378043967867e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 37, "1.300000000000000047051663780439678675e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 38, "1.3000000000000000470516637804396786748e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 39, "1.30000000000000004705166378043967867484e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 40, "1.300000000000000047051663780439678674838e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 41, "1.3000000000000000470516637804396786748384e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 42, "1.30000000000000004705166378043967867483843e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 43, "1.300000000000000047051663780439678674838433e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 44, "1.3000000000000000470516637804396786748384329e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 45, "1.30000000000000004705166378043967867483843293e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 46, "1.300000000000000047051663780439678674838432926e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 47, "1.3000000000000000470516637804396786748384329258e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 48, "1.30000000000000004705166378043967867483843292575e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 49, "1.300000000000000047051663780439678674838432925753e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 50, "1.3000000000000000470516637804396786748384329257533e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 51, "1.3000000000000000470516637804396786748384329257533e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 52, "1.300000000000000047051663780439678674838432925753295e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 53, "1.3000000000000000470516637804396786748384329257532954e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 54, "1.30000000000000004705166378043967867483843292575329542e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 55, "1.300000000000000047051663780439678674838432925753295422e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 56, "1.3000000000000000470516637804396786748384329257532954216e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 57, "1.3000000000000000470516637804396786748384329257532954216e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 58, "1.3000000000000000470516637804396786748384329257532954216e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 59, "1.3000000000000000470516637804396786748384329257532954216003e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 60, "1.30000000000000004705166378043967867483843292575329542160034e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 61, "1.300000000000000047051663780439678674838432925753295421600342e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 62, "1.3000000000000000470516637804396786748384329257532954216003418e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 63, "1.3000000000000000470516637804396786748384329257532954216003418e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 64, "1.300000000000000047051663780439678674838432925753295421600341797e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 65, "1.3000000000000000470516637804396786748384329257532954216003417969e-6")
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 66, "1.30000000000000004705166378043967867483843292575329542160034179688e-6")  # round to even
+      expect_gen(hexfloat("0x1.5cf751db94e6bp-20"), 67, "1.300000000000000047051663780439678674838432925753295421600341796875e-6") # exact
+    end
+
+    it "trim trailing zeros and decimal point, scientific notation" do
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 1, "3e-6") # scientific notation trims decimal point
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 2, "3e-6") # general trims decimal point and trailing zeros
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 3, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 4, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 5, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 6, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 7, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 8, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 9, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 10, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 11, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 12, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 13, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 14, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 15, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 16, "3e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 17, "3.0000000000000001e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 18, "3.00000000000000008e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 19, "3.000000000000000076e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 20, "3.000000000000000076e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 21, "3.000000000000000076e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 22, "3.000000000000000076003e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 23, "3.0000000000000000760026e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 24, "3.00000000000000007600257e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 25, "3.000000000000000076002572e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 26, "3.0000000000000000760025723e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 27, "3.00000000000000007600257229e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 28, "3.000000000000000076002572291e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 29, "3.0000000000000000760025722912e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 30, "3.00000000000000007600257229123e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 31, "3.000000000000000076002572291234e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 32, "3.0000000000000000760025722912339e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 33, "3.00000000000000007600257229123386e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 34, "3.000000000000000076002572291233861e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 35, "3.0000000000000000760025722912338608e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 36, "3.00000000000000007600257229123386082e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 37, "3.000000000000000076002572291233860824e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 38, "3.0000000000000000760025722912338608239e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 39, "3.00000000000000007600257229123386082392e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 40, "3.000000000000000076002572291233860823922e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 41, "3.0000000000000000760025722912338608239224e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 42, "3.00000000000000007600257229123386082392244e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 43, "3.000000000000000076002572291233860823922441e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 44, "3.0000000000000000760025722912338608239224413e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 45, "3.00000000000000007600257229123386082392244134e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 46, "3.000000000000000076002572291233860823922441341e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 47, "3.000000000000000076002572291233860823922441341e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 48, "3.00000000000000007600257229123386082392244134098e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 49, "3.000000000000000076002572291233860823922441340983e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 50, "3.0000000000000000760025722912338608239224413409829e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 51, "3.00000000000000007600257229123386082392244134098291e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 52, "3.000000000000000076002572291233860823922441340982914e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 53, "3.000000000000000076002572291233860823922441340982914e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 54, "3.00000000000000007600257229123386082392244134098291397e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 55, "3.000000000000000076002572291233860823922441340982913971e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 56, "3.0000000000000000760025722912338608239224413409829139709e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 57, "3.00000000000000007600257229123386082392244134098291397095e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 58, "3.000000000000000076002572291233860823922441340982913970947e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 59, "3.0000000000000000760025722912338608239224413409829139709473e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 60, "3.00000000000000007600257229123386082392244134098291397094727e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 61, "3.000000000000000076002572291233860823922441340982913970947266e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 62, "3.0000000000000000760025722912338608239224413409829139709472656e-6")
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 63, "3.00000000000000007600257229123386082392244134098291397094726562e-6")  # round to even
+      expect_gen(hexfloat("0x1.92a737110e454p-19"), 64, "3.000000000000000076002572291233860823922441340982913970947265625e-6") # exact
+    end
+
+    it "large precision with fixed notation and scientific notation" do
+      expect_gen(hexfloat("0x1.ba9fbe76c8b44p+0"), 5000, "1.72900000000000009237055564881302416324615478515625")
+      expect_gen(hexfloat("0x1.d01ff9abb93d1p-20"), 5000, "1.729000000000000090107283613749533657255597063340246677398681640625e-6")
+    end
+
+    it "transitions between fixed notation and scientific notation" do
+      expect_gen(5555555.0, 1, "6e+6")
+      expect_gen(555555.0, 1, "6e+5")
+      expect_gen(55555.0, 1, "6e+4")
+      expect_gen(5555.0, 1, "6e+3")
+      expect_gen(555.0, 1, "6e+2")
+      expect_gen(55.0, 1, "6e+1") # round to even
+      expect_gen(5.0, 1, "5")
+      expect_gen(hexfloat("0x1p-3"), 1, "0.1")     # 0.125
+      expect_gen(hexfloat("0x1p-6"), 1, "0.02")    # 0.015625
+      expect_gen(hexfloat("0x1p-9"), 1, "0.002")   # 0.001953125
+      expect_gen(hexfloat("0x1p-13"), 1, "0.0001") # 0.0001220703125
+      expect_gen(hexfloat("0x1p-16"), 1, "2e-5")   # 1.52587890625e-5
+      expect_gen(hexfloat("0x1p-19"), 1, "2e-6")   # 1.9073486328125e-6
+
+      expect_gen(5555555.0, 2, "5.6e+6")
+      expect_gen(555555.0, 2, "5.6e+5")
+      expect_gen(55555.0, 2, "5.6e+4")
+      expect_gen(5555.0, 2, "5.6e+3")
+      expect_gen(555.0, 2, "5.6e+2") # round to even
+      expect_gen(55.0, 2, "55")
+      expect_gen(5.0, 2, "5")
+      expect_gen(hexfloat("0x1p-3"), 2, "0.12") # round to even
+      expect_gen(hexfloat("0x1p-6"), 2, "0.016")
+      expect_gen(hexfloat("0x1p-9"), 2, "0.002")
+      expect_gen(hexfloat("0x1p-13"), 2, "0.00012")
+      expect_gen(hexfloat("0x1p-16"), 2, "1.5e-5")
+      expect_gen(hexfloat("0x1p-19"), 2, "1.9e-6")
+
+      expect_gen(5555555.0, 3, "5.56e+6")
+      expect_gen(555555.0, 3, "5.56e+5")
+      expect_gen(55555.0, 3, "5.56e+4")
+      expect_gen(5555.0, 3, "5.56e+3") # round to even
+      expect_gen(555.0, 3, "555")
+      expect_gen(55.0, 3, "55")
+      expect_gen(5.0, 3, "5")
+      expect_gen(hexfloat("0x1p-3"), 3, "0.125")
+      expect_gen(hexfloat("0x1p-6"), 3, "0.0156")
+      expect_gen(hexfloat("0x1p-9"), 3, "0.00195")
+      expect_gen(hexfloat("0x1p-13"), 3, "0.000122")
+      expect_gen(hexfloat("0x1p-16"), 3, "1.53e-5")
+      expect_gen(hexfloat("0x1p-19"), 3, "1.91e-6")
+
+      expect_gen(5555555.0, 4, "5.556e+6")
+      expect_gen(555555.0, 4, "5.556e+5")
+      expect_gen(55555.0, 4, "5.556e+4") # round to even
+      expect_gen(5555.0, 4, "5555")
+      expect_gen(555.0, 4, "555")
+      expect_gen(55.0, 4, "55")
+      expect_gen(5.0, 4, "5")
+      expect_gen(hexfloat("0x1p-3"), 4, "0.125")
+      expect_gen(hexfloat("0x1p-6"), 4, "0.01562") # round to even
+      expect_gen(hexfloat("0x1p-9"), 4, "0.001953")
+      expect_gen(hexfloat("0x1p-13"), 4, "0.0001221")
+      expect_gen(hexfloat("0x1p-16"), 4, "1.526e-5")
+      expect_gen(hexfloat("0x1p-19"), 4, "1.907e-6")
+
+      expect_gen(5555555.0, 5, "5.5556e+6")
+      expect_gen(555555.0, 5, "5.5556e+5") # round to even
+      expect_gen(55555.0, 5, "55555")
+      expect_gen(5555.0, 5, "5555")
+      expect_gen(555.0, 5, "555")
+      expect_gen(55.0, 5, "55")
+      expect_gen(5.0, 5, "5")
+      expect_gen(hexfloat("0x1p-3"), 5, "0.125")
+      expect_gen(hexfloat("0x1p-6"), 5, "0.015625")
+      expect_gen(hexfloat("0x1p-9"), 5, "0.0019531")
+      expect_gen(hexfloat("0x1p-13"), 5, "0.00012207")
+      expect_gen(hexfloat("0x1p-16"), 5, "1.5259e-5")
+      expect_gen(hexfloat("0x1p-19"), 5, "1.9073e-6")
+    end
+
+    it "tricky corner cases" do
+      expect_gen(999.999, 1, "1e+3")    # "%.0e" is "1e+3"; X == 3
+      expect_gen(999.999, 2, "1e+3")    # "%.1e" is "1.0e+3"; X == 3
+      expect_gen(999.999, 3, "1e+3")    # "%.2e" is "1.00e+3"; X == 3
+      expect_gen(999.999, 4, "1000")    # "%.3e" is "1.000e+3"; X == 3
+      expect_gen(999.999, 5, "1000")    # "%.4e" is "1.0000e+3"; X == 3
+      expect_gen(999.999, 6, "999.999") # "%.5e" is "9.99999e+2"; X == 2
+
+      expect_gen(999.99, 1, "1e+3")
+      expect_gen(999.99, 2, "1e+3")
+      expect_gen(999.99, 3, "1e+3")
+      expect_gen(999.99, 4, "1000")
+      expect_gen(999.99, 5, "999.99")
+      expect_gen(999.99, 6, "999.99")
+
+      # C11's Standardese is slightly vague about how to perform the trial formatting in scientific notation,
+      # but the intention is to use precision P - 1, which is what's used when scientific notation is actually chosen.
+      # This example verifies this behavior. Here, P == 3 performs trial formatting with "%.2e", triggering rounding.
+      # That increases X to 3, forcing scientific notation to be chosen.
+      # If P == 3 performed trial formatting with "%.3e", rounding wouldn't happen,
+      # X would be 2, and fixed notation would be chosen.
+      expect_gen(999.9, 1, "1e+3")  # "%.0e" is "1e+3"; X == 3
+      expect_gen(999.9, 2, "1e+3")  # "%.1e" is "1.0e+3"; X == 3
+      expect_gen(999.9, 3, "1e+3")  # "%.2e" is "1.00e+3"; X == 3; SPECIAL CORNER CASE
+      expect_gen(999.9, 4, "999.9") # "%.3e" is "9.999e+2"; X == 2
+      expect_gen(999.9, 5, "999.9") # "%.4e" is "9.9990e+2"; X == 2
+      expect_gen(999.9, 6, "999.9") # "%.5e" is "9.99900e+2"; X == 2
+
+      expect_gen(999.0, 1, "1e+3")
+      expect_gen(999.0, 2, "1e+3")
+      expect_gen(999.0, 3, "999")
+      expect_gen(999.0, 4, "999")
+      expect_gen(999.0, 5, "999")
+      expect_gen(999.0, 6, "999")
+
+      expect_gen(99.9999, 1, "1e+2")
+      expect_gen(99.9999, 2, "1e+2")
+      expect_gen(99.9999, 3, "100")
+      expect_gen(99.9999, 4, "100")
+      expect_gen(99.9999, 5, "100")
+      expect_gen(99.9999, 6, "99.9999")
+
+      expect_gen(99.999, 1, "1e+2")
+      expect_gen(99.999, 2, "1e+2")
+      expect_gen(99.999, 3, "100")
+      expect_gen(99.999, 4, "100")
+      expect_gen(99.999, 5, "99.999")
+      expect_gen(99.999, 6, "99.999")
+
+      expect_gen(99.99, 1, "1e+2")
+      expect_gen(99.99, 2, "1e+2")
+      expect_gen(99.99, 3, "100")
+      expect_gen(99.99, 4, "99.99")
+      expect_gen(99.99, 5, "99.99")
+      expect_gen(99.99, 6, "99.99")
+
+      expect_gen(99.9, 1, "1e+2")
+      expect_gen(99.9, 2, "1e+2")
+      expect_gen(99.9, 3, "99.9")
+      expect_gen(99.9, 4, "99.9")
+      expect_gen(99.9, 5, "99.9")
+      expect_gen(99.9, 6, "99.9")
+
+      expect_gen(99.0, 1, "1e+2")
+      expect_gen(99.0, 2, "99")
+      expect_gen(99.0, 3, "99")
+      expect_gen(99.0, 4, "99")
+      expect_gen(99.0, 5, "99")
+      expect_gen(99.0, 6, "99")
+
+      expect_gen(9.99999, 1, "1e+1")
+      expect_gen(9.99999, 2, "10")
+      expect_gen(9.99999, 3, "10")
+      expect_gen(9.99999, 4, "10")
+      expect_gen(9.99999, 5, "10")
+      expect_gen(9.99999, 6, "9.99999")
+
+      expect_gen(9.9999, 1, "1e+1")
+      expect_gen(9.9999, 2, "10")
+      expect_gen(9.9999, 3, "10")
+      expect_gen(9.9999, 4, "10")
+      expect_gen(9.9999, 5, "9.9999")
+      expect_gen(9.9999, 6, "9.9999")
+
+      expect_gen(9.999, 1, "1e+1")
+      expect_gen(9.999, 2, "10")
+      expect_gen(9.999, 3, "10")
+      expect_gen(9.999, 4, "9.999")
+      expect_gen(9.999, 5, "9.999")
+      expect_gen(9.999, 6, "9.999")
+
+      expect_gen(9.99, 1, "1e+1")
+      expect_gen(9.99, 2, "10")
+      expect_gen(9.99, 3, "9.99")
+      expect_gen(9.99, 4, "9.99")
+      expect_gen(9.99, 5, "9.99")
+      expect_gen(9.99, 6, "9.99")
+
+      expect_gen(9.9, 1, "1e+1")
+      expect_gen(9.9, 2, "9.9")
+      expect_gen(9.9, 3, "9.9")
+      expect_gen(9.9, 4, "9.9")
+      expect_gen(9.9, 5, "9.9")
+      expect_gen(9.9, 6, "9.9")
+
+      expect_gen(9.0, 1, "9")
+      expect_gen(9.0, 2, "9")
+      expect_gen(9.0, 3, "9")
+      expect_gen(9.0, 4, "9")
+      expect_gen(9.0, 5, "9")
+      expect_gen(9.0, 6, "9")
+
+      expect_gen(0.999999, 1, "1")
+      expect_gen(0.999999, 2, "1")
+      expect_gen(0.999999, 3, "1")
+      expect_gen(0.999999, 4, "1")
+      expect_gen(0.999999, 5, "1")
+      expect_gen(0.999999, 6, "0.999999")
+
+      expect_gen(0.99999, 1, "1")
+      expect_gen(0.99999, 2, "1")
+      expect_gen(0.99999, 3, "1")
+      expect_gen(0.99999, 4, "1")
+      expect_gen(0.99999, 5, "0.99999")
+      expect_gen(0.99999, 6, "0.99999")
+
+      expect_gen(0.9999, 1, "1")
+      expect_gen(0.9999, 2, "1")
+      expect_gen(0.9999, 3, "1")
+      expect_gen(0.9999, 4, "0.9999")
+      expect_gen(0.9999, 5, "0.9999")
+      expect_gen(0.9999, 6, "0.9999")
+
+      expect_gen(0.999, 1, "1")
+      expect_gen(0.999, 2, "1")
+      expect_gen(0.999, 3, "0.999")
+      expect_gen(0.999, 4, "0.999")
+      expect_gen(0.999, 5, "0.999")
+      expect_gen(0.999, 6, "0.999")
+
+      expect_gen(0.99, 1, "1")
+      expect_gen(0.99, 2, "0.99")
+      expect_gen(0.99, 3, "0.99")
+      expect_gen(0.99, 4, "0.99")
+      expect_gen(0.99, 5, "0.99")
+      expect_gen(0.99, 6, "0.99")
+
+      expect_gen(0.9, 1, "0.9")
+      expect_gen(0.9, 2, "0.9")
+      expect_gen(0.9, 3, "0.9")
+      expect_gen(0.9, 4, "0.9")
+      expect_gen(0.9, 5, "0.9")
+      expect_gen(0.9, 6, "0.9")
+
+      expect_gen(0.0999999, 1, "0.1")
+      expect_gen(0.0999999, 2, "0.1")
+      expect_gen(0.0999999, 3, "0.1")
+      expect_gen(0.0999999, 4, "0.1")
+      expect_gen(0.0999999, 5, "0.1")
+      expect_gen(0.0999999, 6, "0.0999999")
+
+      expect_gen(0.099999, 1, "0.1")
+      expect_gen(0.099999, 2, "0.1")
+      expect_gen(0.099999, 3, "0.1")
+      expect_gen(0.099999, 4, "0.1")
+      expect_gen(0.099999, 5, "0.099999")
+      expect_gen(0.099999, 6, "0.099999")
+
+      expect_gen(0.09999, 1, "0.1")
+      expect_gen(0.09999, 2, "0.1")
+      expect_gen(0.09999, 3, "0.1")
+      expect_gen(0.09999, 4, "0.09999")
+      expect_gen(0.09999, 5, "0.09999")
+      expect_gen(0.09999, 6, "0.09999")
+
+      expect_gen(0.0999, 1, "0.1")
+      expect_gen(0.0999, 2, "0.1")
+      expect_gen(0.0999, 3, "0.0999")
+      expect_gen(0.0999, 4, "0.0999")
+      expect_gen(0.0999, 5, "0.0999")
+      expect_gen(0.0999, 6, "0.0999")
+
+      expect_gen(0.099, 1, "0.1")
+      expect_gen(0.099, 2, "0.099")
+      expect_gen(0.099, 3, "0.099")
+      expect_gen(0.099, 4, "0.099")
+      expect_gen(0.099, 5, "0.099")
+      expect_gen(0.099, 6, "0.099")
+
+      expect_gen(0.09, 1, "0.09")
+      expect_gen(0.09, 2, "0.09")
+      expect_gen(0.09, 3, "0.09")
+      expect_gen(0.09, 4, "0.09")
+      expect_gen(0.09, 5, "0.09")
+      expect_gen(0.09, 6, "0.09")
+
+      expect_gen(0.00999999, 1, "0.01")
+      expect_gen(0.00999999, 2, "0.01")
+      expect_gen(0.00999999, 3, "0.01")
+      expect_gen(0.00999999, 4, "0.01")
+      expect_gen(0.00999999, 5, "0.01")
+      expect_gen(0.00999999, 6, "0.00999999")
+
+      expect_gen(0.0099999, 1, "0.01")
+      expect_gen(0.0099999, 2, "0.01")
+      expect_gen(0.0099999, 3, "0.01")
+      expect_gen(0.0099999, 4, "0.01")
+      expect_gen(0.0099999, 5, "0.0099999")
+      expect_gen(0.0099999, 6, "0.0099999")
+
+      expect_gen(0.009999, 1, "0.01")
+      expect_gen(0.009999, 2, "0.01")
+      expect_gen(0.009999, 3, "0.01")
+      expect_gen(0.009999, 4, "0.009999")
+      expect_gen(0.009999, 5, "0.009999")
+      expect_gen(0.009999, 6, "0.009999")
+
+      expect_gen(0.00999, 1, "0.01")
+      expect_gen(0.00999, 2, "0.01")
+      expect_gen(0.00999, 3, "0.00999")
+      expect_gen(0.00999, 4, "0.00999")
+      expect_gen(0.00999, 5, "0.00999")
+      expect_gen(0.00999, 6, "0.00999")
+
+      expect_gen(0.0099, 1, "0.01")
+      expect_gen(0.0099, 2, "0.0099")
+      expect_gen(0.0099, 3, "0.0099")
+      expect_gen(0.0099, 4, "0.0099")
+      expect_gen(0.0099, 5, "0.0099")
+      expect_gen(0.0099, 6, "0.0099")
+
+      expect_gen(0.009, 1, "0.009")
+      expect_gen(0.009, 2, "0.009")
+      expect_gen(0.009, 3, "0.009")
+      expect_gen(0.009, 4, "0.009")
+      expect_gen(0.009, 5, "0.009")
+      expect_gen(0.009, 6, "0.009")
+
+      expect_gen(0.000999999, 1, "0.001")
+      expect_gen(0.000999999, 2, "0.001")
+      expect_gen(0.000999999, 3, "0.001")
+      expect_gen(0.000999999, 4, "0.001")
+      expect_gen(0.000999999, 5, "0.001")
+      expect_gen(0.000999999, 6, "0.000999999")
+
+      expect_gen(0.00099999, 1, "0.001")
+      expect_gen(0.00099999, 2, "0.001")
+      expect_gen(0.00099999, 3, "0.001")
+      expect_gen(0.00099999, 4, "0.001")
+      expect_gen(0.00099999, 5, "0.00099999")
+      expect_gen(0.00099999, 6, "0.00099999")
+
+      expect_gen(0.0009999, 1, "0.001")
+      expect_gen(0.0009999, 2, "0.001")
+      expect_gen(0.0009999, 3, "0.001")
+      expect_gen(0.0009999, 4, "0.0009999")
+      expect_gen(0.0009999, 5, "0.0009999")
+      expect_gen(0.0009999, 6, "0.0009999")
+
+      expect_gen(0.000999, 1, "0.001")
+      expect_gen(0.000999, 2, "0.001")
+      expect_gen(0.000999, 3, "0.000999")
+      expect_gen(0.000999, 4, "0.000999")
+      expect_gen(0.000999, 5, "0.000999")
+      expect_gen(0.000999, 6, "0.000999")
+
+      expect_gen(0.00099, 1, "0.001")
+      expect_gen(0.00099, 2, "0.00099")
+      expect_gen(0.00099, 3, "0.00099")
+      expect_gen(0.00099, 4, "0.00099")
+      expect_gen(0.00099, 5, "0.00099")
+      expect_gen(0.00099, 6, "0.00099")
+
+      expect_gen(0.0009, 1, "0.0009")
+      expect_gen(0.0009, 2, "0.0009")
+      expect_gen(0.0009, 3, "0.0009")
+      expect_gen(0.0009, 4, "0.0009")
+      expect_gen(0.0009, 5, "0.0009")
+      expect_gen(0.0009, 6, "0.0009")
+
+      # Having a scientific exponent X == -5 triggers scientific notation.
+      # If rounding adjusts this to X == -4, then fixed notation will be selected.
+      expect_gen(0.0000999999, 1, "0.0001")
+      expect_gen(0.0000999999, 2, "0.0001")
+      expect_gen(0.0000999999, 3, "0.0001")
+      expect_gen(0.0000999999, 4, "0.0001")
+      expect_gen(0.0000999999, 5, "0.0001")
+      expect_gen(0.0000999999, 6, "9.99999e-5")
+
+      expect_gen(0.000099999, 1, "0.0001")
+      expect_gen(0.000099999, 2, "0.0001")
+      expect_gen(0.000099999, 3, "0.0001")
+      expect_gen(0.000099999, 4, "0.0001")
+      expect_gen(0.000099999, 5, "9.9999e-5")
+      expect_gen(0.000099999, 6, "9.9999e-5")
+
+      expect_gen(0.00009999, 1, "0.0001")
+      expect_gen(0.00009999, 2, "0.0001")
+      expect_gen(0.00009999, 3, "0.0001")
+      expect_gen(0.00009999, 4, "9.999e-5")
+      expect_gen(0.00009999, 5, "9.999e-5")
+      expect_gen(0.00009999, 6, "9.999e-5")
+
+      expect_gen(0.0000999, 1, "0.0001")
+      expect_gen(0.0000999, 2, "0.0001")
+      expect_gen(0.0000999, 3, "9.99e-5")
+      expect_gen(0.0000999, 4, "9.99e-5")
+      expect_gen(0.0000999, 5, "9.99e-5")
+      expect_gen(0.0000999, 6, "9.99e-5")
+
+      expect_gen(0.000099, 1, "0.0001")
+      expect_gen(0.000099, 2, "9.9e-5")
+      expect_gen(0.000099, 3, "9.9e-5")
+      expect_gen(0.000099, 4, "9.9e-5")
+      expect_gen(0.000099, 5, "9.9e-5")
+      expect_gen(0.000099, 6, "9.9e-5")
+
+      expect_gen(0.00009, 1, "9e-5")
+      expect_gen(0.00009, 2, "9e-5")
+      expect_gen(0.00009, 3, "9e-5")
+      expect_gen(0.00009, 4, "9e-5")
+      expect_gen(0.00009, 5, "9e-5")
+      expect_gen(0.00009, 6, "9e-5")
+
+      # Rounding test cases without exponent-adjusting behavior.
+      expect_gen(2999.999, 1, "3e+3")
+      expect_gen(2999.999, 2, "3e+3")
+      expect_gen(2999.999, 3, "3e+3")
+      expect_gen(2999.999, 4, "3000")
+      expect_gen(2999.999, 5, "3000")
+      expect_gen(2999.999, 6, "3000")
+
+      expect_gen(2999.99, 1, "3e+3")
+      expect_gen(2999.99, 2, "3e+3")
+      expect_gen(2999.99, 3, "3e+3")
+      expect_gen(2999.99, 4, "3000")
+      expect_gen(2999.99, 5, "3000")
+      expect_gen(2999.99, 6, "2999.99")
+
+      expect_gen(2999.9, 1, "3e+3")
+      expect_gen(2999.9, 2, "3e+3")
+      expect_gen(2999.9, 3, "3e+3")
+      expect_gen(2999.9, 4, "3000")
+      expect_gen(2999.9, 5, "2999.9")
+      expect_gen(2999.9, 6, "2999.9")
+
+      expect_gen(2999.0, 1, "3e+3")
+      expect_gen(2999.0, 2, "3e+3")
+      expect_gen(2999.0, 3, "3e+3")
+      expect_gen(2999.0, 4, "2999")
+      expect_gen(2999.0, 5, "2999")
+      expect_gen(2999.0, 6, "2999")
+
+      expect_gen(299.999, 1, "3e+2")
+      expect_gen(299.999, 2, "3e+2")
+      expect_gen(299.999, 3, "300")
+      expect_gen(299.999, 4, "300")
+      expect_gen(299.999, 5, "300")
+      expect_gen(299.999, 6, "299.999")
+
+      expect_gen(299.99, 1, "3e+2")
+      expect_gen(299.99, 2, "3e+2")
+      expect_gen(299.99, 3, "300")
+      expect_gen(299.99, 4, "300")
+      expect_gen(299.99, 5, "299.99")
+      expect_gen(299.99, 6, "299.99")
+
+      expect_gen(299.9, 1, "3e+2")
+      expect_gen(299.9, 2, "3e+2")
+      expect_gen(299.9, 3, "300")
+      expect_gen(299.9, 4, "299.9")
+      expect_gen(299.9, 5, "299.9")
+      expect_gen(299.9, 6, "299.9")
+
+      expect_gen(299.0, 1, "3e+2")
+      expect_gen(299.0, 2, "3e+2")
+      expect_gen(299.0, 3, "299")
+      expect_gen(299.0, 4, "299")
+      expect_gen(299.0, 5, "299")
+      expect_gen(299.0, 6, "299")
+
+      expect_gen(29.999, 1, "3e+1")
+      expect_gen(29.999, 2, "30")
+      expect_gen(29.999, 3, "30")
+      expect_gen(29.999, 4, "30")
+      expect_gen(29.999, 5, "29.999")
+      expect_gen(29.999, 6, "29.999")
+
+      expect_gen(29.99, 1, "3e+1")
+      expect_gen(29.99, 2, "30")
+      expect_gen(29.99, 3, "30")
+      expect_gen(29.99, 4, "29.99")
+      expect_gen(29.99, 5, "29.99")
+      expect_gen(29.99, 6, "29.99")
+
+      expect_gen(29.9, 1, "3e+1")
+      expect_gen(29.9, 2, "30")
+      expect_gen(29.9, 3, "29.9")
+      expect_gen(29.9, 4, "29.9")
+      expect_gen(29.9, 5, "29.9")
+      expect_gen(29.9, 6, "29.9")
+
+      expect_gen(29.0, 1, "3e+1")
+      expect_gen(29.0, 2, "29")
+      expect_gen(29.0, 3, "29")
+      expect_gen(29.0, 4, "29")
+      expect_gen(29.0, 5, "29")
+      expect_gen(29.0, 6, "29")
+
+      expect_gen(2.999, 1, "3")
+      expect_gen(2.999, 2, "3")
+      expect_gen(2.999, 3, "3")
+      expect_gen(2.999, 4, "2.999")
+      expect_gen(2.999, 5, "2.999")
+      expect_gen(2.999, 6, "2.999")
+
+      expect_gen(2.99, 1, "3")
+      expect_gen(2.99, 2, "3")
+      expect_gen(2.99, 3, "2.99")
+      expect_gen(2.99, 4, "2.99")
+      expect_gen(2.99, 5, "2.99")
+      expect_gen(2.99, 6, "2.99")
+
+      expect_gen(2.9, 1, "3")
+      expect_gen(2.9, 2, "2.9")
+      expect_gen(2.9, 3, "2.9")
+      expect_gen(2.9, 4, "2.9")
+      expect_gen(2.9, 5, "2.9")
+      expect_gen(2.9, 6, "2.9")
+
+      expect_gen(2.0, 1, "2")
+      expect_gen(2.0, 2, "2")
+      expect_gen(2.0, 3, "2")
+      expect_gen(2.0, 4, "2")
+      expect_gen(2.0, 5, "2")
+      expect_gen(2.0, 6, "2")
+
+      expect_gen(0.2999, 1, "0.3")
+      expect_gen(0.2999, 2, "0.3")
+      expect_gen(0.2999, 3, "0.3")
+      expect_gen(0.2999, 4, "0.2999")
+      expect_gen(0.2999, 5, "0.2999")
+      expect_gen(0.2999, 6, "0.2999")
+
+      expect_gen(0.299, 1, "0.3")
+      expect_gen(0.299, 2, "0.3")
+      expect_gen(0.299, 3, "0.299")
+      expect_gen(0.299, 4, "0.299")
+      expect_gen(0.299, 5, "0.299")
+      expect_gen(0.299, 6, "0.299")
+
+      expect_gen(0.29, 1, "0.3")
+      expect_gen(0.29, 2, "0.29")
+      expect_gen(0.29, 3, "0.29")
+      expect_gen(0.29, 4, "0.29")
+      expect_gen(0.29, 5, "0.29")
+      expect_gen(0.29, 6, "0.29")
+
+      expect_gen(0.2, 1, "0.2")
+      expect_gen(0.2, 2, "0.2")
+      expect_gen(0.2, 3, "0.2")
+      expect_gen(0.2, 4, "0.2")
+      expect_gen(0.2, 5, "0.2")
+      expect_gen(0.2, 6, "0.2")
+
+      expect_gen(0.02999, 1, "0.03")
+      expect_gen(0.02999, 2, "0.03")
+      expect_gen(0.02999, 3, "0.03")
+      expect_gen(0.02999, 4, "0.02999")
+      expect_gen(0.02999, 5, "0.02999")
+      expect_gen(0.02999, 6, "0.02999")
+
+      expect_gen(0.0299, 1, "0.03")
+      expect_gen(0.0299, 2, "0.03")
+      expect_gen(0.0299, 3, "0.0299")
+      expect_gen(0.0299, 4, "0.0299")
+      expect_gen(0.0299, 5, "0.0299")
+      expect_gen(0.0299, 6, "0.0299")
+
+      expect_gen(0.029, 1, "0.03")
+      expect_gen(0.029, 2, "0.029")
+      expect_gen(0.029, 3, "0.029")
+      expect_gen(0.029, 4, "0.029")
+      expect_gen(0.029, 5, "0.029")
+      expect_gen(0.029, 6, "0.029")
+
+      expect_gen(0.02, 1, "0.02")
+      expect_gen(0.02, 2, "0.02")
+      expect_gen(0.02, 3, "0.02")
+      expect_gen(0.02, 4, "0.02")
+      expect_gen(0.02, 5, "0.02")
+      expect_gen(0.02, 6, "0.02")
+
+      expect_gen(0.002999, 1, "0.003")
+      expect_gen(0.002999, 2, "0.003")
+      expect_gen(0.002999, 3, "0.003")
+      expect_gen(0.002999, 4, "0.002999")
+      expect_gen(0.002999, 5, "0.002999")
+      expect_gen(0.002999, 6, "0.002999")
+
+      expect_gen(0.00299, 1, "0.003")
+      expect_gen(0.00299, 2, "0.003")
+      expect_gen(0.00299, 3, "0.00299")
+      expect_gen(0.00299, 4, "0.00299")
+      expect_gen(0.00299, 5, "0.00299")
+      expect_gen(0.00299, 6, "0.00299")
+
+      expect_gen(0.0029, 1, "0.003")
+      expect_gen(0.0029, 2, "0.0029")
+      expect_gen(0.0029, 3, "0.0029")
+      expect_gen(0.0029, 4, "0.0029")
+      expect_gen(0.0029, 5, "0.0029")
+      expect_gen(0.0029, 6, "0.0029")
+
+      expect_gen(0.002, 1, "0.002")
+      expect_gen(0.002, 2, "0.002")
+      expect_gen(0.002, 3, "0.002")
+      expect_gen(0.002, 4, "0.002")
+      expect_gen(0.002, 5, "0.002")
+      expect_gen(0.002, 6, "0.002")
+
+      expect_gen(0.0002999, 1, "0.0003")
+      expect_gen(0.0002999, 2, "0.0003")
+      expect_gen(0.0002999, 3, "0.0003")
+      expect_gen(0.0002999, 4, "0.0002999")
+      expect_gen(0.0002999, 5, "0.0002999")
+      expect_gen(0.0002999, 6, "0.0002999")
+
+      expect_gen(0.000299, 1, "0.0003")
+      expect_gen(0.000299, 2, "0.0003")
+      expect_gen(0.000299, 3, "0.000299")
+      expect_gen(0.000299, 4, "0.000299")
+      expect_gen(0.000299, 5, "0.000299")
+      expect_gen(0.000299, 6, "0.000299")
+
+      expect_gen(0.00029, 1, "0.0003")
+      expect_gen(0.00029, 2, "0.00029")
+      expect_gen(0.00029, 3, "0.00029")
+      expect_gen(0.00029, 4, "0.00029")
+      expect_gen(0.00029, 5, "0.00029")
+      expect_gen(0.00029, 6, "0.00029")
+
+      expect_gen(0.0002, 1, "0.0002")
+      expect_gen(0.0002, 2, "0.0002")
+      expect_gen(0.0002, 3, "0.0002")
+      expect_gen(0.0002, 4, "0.0002")
+      expect_gen(0.0002, 5, "0.0002")
+      expect_gen(0.0002, 6, "0.0002")
+
+      expect_gen(0.00002999, 1, "3e-5")
+      expect_gen(0.00002999, 2, "3e-5")
+      expect_gen(0.00002999, 3, "3e-5")
+      expect_gen(0.00002999, 4, "2.999e-5")
+      expect_gen(0.00002999, 5, "2.999e-5")
+      expect_gen(0.00002999, 6, "2.999e-5")
+
+      expect_gen(0.0000299, 1, "3e-5")
+      expect_gen(0.0000299, 2, "3e-5")
+      expect_gen(0.0000299, 3, "2.99e-5")
+      expect_gen(0.0000299, 4, "2.99e-5")
+      expect_gen(0.0000299, 5, "2.99e-5")
+      expect_gen(0.0000299, 6, "2.99e-5")
+
+      expect_gen(0.000029, 1, "3e-5")
+      expect_gen(0.000029, 2, "2.9e-5")
+      expect_gen(0.000029, 3, "2.9e-5")
+      expect_gen(0.000029, 4, "2.9e-5")
+      expect_gen(0.000029, 5, "2.9e-5")
+      expect_gen(0.000029, 6, "2.9e-5")
+
+      expect_gen(0.00002, 1, "2e-5")
+      expect_gen(0.00002, 2, "2e-5")
+      expect_gen(0.00002, 3, "2e-5")
+      expect_gen(0.00002, 4, "2e-5")
+      expect_gen(0.00002, 5, "2e-5")
+      expect_gen(0.00002, 6, "2e-5")
+    end
+
+    it "transitions between values of the scientific exponent X" do
+      {% for tc in GEN_TRANSITIONS %}
+        expect_gen(hexfloat({{ tc[0] }}), {{ tc[1] }}, {{ tc[2] }}, file: {{ tc.filename }}, line: {{ tc.line_number }})
+      {% end %}
+    end
+
+    it "UCRT had trouble with rounding this value" do
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 105, "109995565999999994887854821710219658911365648587951921896774663603198787416706536331386569598149846892544")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 19, "1.099955659999999949e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 18, "1.09995565999999995e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 17, "1.0999556599999999e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 16, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 15, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 14, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 13, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 12, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 11, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 10, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 9, "1.09995566e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 8, "1.0999557e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 7, "1.099956e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 6, "1.09996e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 5, "1.1e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 4, "1.1e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 3, "1.1e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 2, "1.1e+104")
+      expect_gen(hexfloat("0x1.88e2d605edc3dp+345"), 1, "1e+104")
+    end
+
+    it "more cases that the UCRT had trouble with (e.g. DevCom-1093399)" do
+      expect_gen(hexfloat("0x1.8p+62"), 17, "6.9175290276410819e+18")
+      expect_gen(hexfloat("0x1.0a2742p+17"), 6, "136271")
+      expect_gen(hexfloat("0x1.f8b0f962cdffbp+205"), 14, "1.0137595739223e+62")
+      expect_gen(hexfloat("0x1.f8b0f962cdffbp+205"), 17, "1.0137595739222531e+62")
+      expect_gen(hexfloat("0x1.f8b0f962cdffbp+205"), 51, "1.01375957392225305727423222620636224221808910954041e+62")
+      expect_gen(hexfloat("0x1.f8b0f962cdffbp+205"), 55, "1.013759573922253057274232226206362242218089109540405973e+62")
+    end
+  end
 end
diff --git a/spec/std/float_printer/ryu_printf_test_cases.cr b/spec/std/float_printer/ryu_printf_test_cases.cr
index 6c1a3a155692..32448af3bc4d 100644
--- a/spec/std/float_printer/ryu_printf_test_cases.cr
+++ b/spec/std/float_printer/ryu_printf_test_cases.cr
@@ -2695,3 +2695,1673 @@ ALL_BINARY_EXPONENTS = [
   {6.123699292104195e+307, 0, 307},
   {1.7026387749989901e+308, 0, 308},
 ] of _
+
+# For brevity, we avoid testing all possible combinations of P and X. Instead, we test:
+# * All values of P where some X can be affected by rounding. (For double, this is [1, 15].)
+# * P == 25, which is arbitrary.
+# * P == numeric_limits::max_exponent10 + 1. This selects fixed notation for numeric_limits::max(),
+#   so it's the largest interesting value of P.
+# * Finally, we test the transitions around X == P - 1, ensuring that we can recognize every value of X.
+GEN_TRANSITIONS = [
+  {"0x1.8e757928e0c9dp-14", 1, "9e-5"},
+  {"0x1.8e757928e0c9ep-14", 1, "0.0001"},
+  {"0x1.f212d77318fc5p-11", 1, "0.0009"},
+  {"0x1.f212d77318fc6p-11", 1, "0.001"},
+  {"0x1.374bc6a7ef9dbp-7", 1, "0.009"},
+  {"0x1.374bc6a7ef9dcp-7", 1, "0.01"},
+  {"0x1.851eb851eb851p-4", 1, "0.09"},
+  {"0x1.851eb851eb852p-4", 1, "0.1"},
+  {"0x1.e666666666666p-1", 1, "0.9"},
+  {"0x1.e666666666667p-1", 1, "1"},
+  {"0x1.2ffffffffffffp+3", 1, "9"},
+  {"0x1.3000000000000p+3", 1, "1e+1"},
+  {"0x1.a1554fbdad751p-14", 2, "9.9e-5"},
+  {"0x1.a1554fbdad752p-14", 2, "0.0001"},
+  {"0x1.04d551d68c692p-10", 2, "0.00099"},
+  {"0x1.04d551d68c693p-10", 2, "0.001"},
+  {"0x1.460aa64c2f837p-7", 2, "0.0099"},
+  {"0x1.460aa64c2f838p-7", 2, "0.01"},
+  {"0x1.978d4fdf3b645p-4", 2, "0.099"},
+  {"0x1.978d4fdf3b646p-4", 2, "0.1"},
+  {"0x1.fd70a3d70a3d7p-1", 2, "0.99"},
+  {"0x1.fd70a3d70a3d8p-1", 2, "1"},
+  {"0x1.3e66666666666p+3", 2, "9.9"},
+  {"0x1.3e66666666667p+3", 2, "10"},
+  {"0x1.8dfffffffffffp+6", 2, "99"},
+  {"0x1.8e00000000000p+6", 2, "1e+2"},
+  {"0x1.a3387ecc8eb96p-14", 3, "9.99e-5"},
+  {"0x1.a3387ecc8eb97p-14", 3, "0.0001"},
+  {"0x1.06034f3fd933ep-10", 3, "0.000999"},
+  {"0x1.06034f3fd933fp-10", 3, "0.001"},
+  {"0x1.4784230fcf80dp-7", 3, "0.00999"},
+  {"0x1.4784230fcf80ep-7", 3, "0.01"},
+  {"0x1.99652bd3c3611p-4", 3, "0.0999"},
+  {"0x1.99652bd3c3612p-4", 3, "0.1"},
+  {"0x1.ffbe76c8b4395p-1", 3, "0.999"},
+  {"0x1.ffbe76c8b4396p-1", 3, "1"},
+  {"0x1.3fd70a3d70a3dp+3", 3, "9.99"},
+  {"0x1.3fd70a3d70a3ep+3", 3, "10"},
+  {"0x1.8fcccccccccccp+6", 3, "99.9"},
+  {"0x1.8fccccccccccdp+6", 3, "100"},
+  {"0x1.f3bffffffffffp+9", 3, "999"},
+  {"0x1.f3c0000000000p+9", 3, "1e+3"},
+  {"0x1.a368d04e0ba6ap-14", 4, "9.999e-5"},
+  {"0x1.a368d04e0ba6bp-14", 4, "0.0001"},
+  {"0x1.06218230c7482p-10", 4, "0.0009999"},
+  {"0x1.06218230c7483p-10", 4, "0.001"},
+  {"0x1.47a9e2bcf91a3p-7", 4, "0.009999"},
+  {"0x1.47a9e2bcf91a4p-7", 4, "0.01"},
+  {"0x1.99945b6c3760bp-4", 4, "0.09999"},
+  {"0x1.99945b6c3760cp-4", 4, "0.1"},
+  {"0x1.fff972474538ep-1", 4, "0.9999"},
+  {"0x1.fff972474538fp-1", 4, "1"},
+  {"0x1.3ffbe76c8b439p+3", 4, "9.999"},
+  {"0x1.3ffbe76c8b43ap+3", 4, "10"},
+  {"0x1.8ffae147ae147p+6", 4, "99.99"},
+  {"0x1.8ffae147ae148p+6", 4, "100"},
+  {"0x1.f3f9999999999p+9", 4, "999.9"},
+  {"0x1.f3f999999999ap+9", 4, "1000"},
+  {"0x1.387bfffffffffp+13", 4, "9999"},
+  {"0x1.387c000000000p+13", 4, "1e+4"},
+  {"0x1.a36da54164f19p-14", 5, "9.9999e-5"},
+  {"0x1.a36da54164f1ap-14", 5, "0.0001"},
+  {"0x1.06248748df16fp-10", 5, "0.00099999"},
+  {"0x1.06248748df170p-10", 5, "0.001"},
+  {"0x1.47ada91b16dcbp-7", 5, "0.0099999"},
+  {"0x1.47ada91b16dccp-7", 5, "0.01"},
+  {"0x1.99991361dc93ep-4", 5, "0.099999"},
+  {"0x1.99991361dc93fp-4", 5, "0.1"},
+  {"0x1.ffff583a53b8ep-1", 5, "0.99999"},
+  {"0x1.ffff583a53b8fp-1", 5, "1"},
+  {"0x1.3fff972474538p+3", 5, "9.9999"},
+  {"0x1.3fff972474539p+3", 5, "10"},
+  {"0x1.8fff7ced91687p+6", 5, "99.999"},
+  {"0x1.8fff7ced91688p+6", 5, "100"},
+  {"0x1.f3ff5c28f5c28p+9", 5, "999.99"},
+  {"0x1.f3ff5c28f5c29p+9", 5, "1000"},
+  {"0x1.387f999999999p+13", 5, "9999.9"},
+  {"0x1.387f99999999ap+13", 5, "10000"},
+  {"0x1.869f7ffffffffp+16", 5, "99999"},
+  {"0x1.869f800000000p+16", 5, "1e+5"},
+  {"0x1.a36e20f35445dp-14", 6, "9.99999e-5"},
+  {"0x1.a36e20f35445ep-14", 6, "0.0001"},
+  {"0x1.0624d49814abap-10", 6, "0.000999999"},
+  {"0x1.0624d49814abbp-10", 6, "0.001"},
+  {"0x1.47ae09be19d69p-7", 6, "0.00999999"},
+  {"0x1.47ae09be19d6ap-7", 6, "0.01"},
+  {"0x1.99998c2da04c3p-4", 6, "0.0999999"},
+  {"0x1.99998c2da04c4p-4", 6, "0.1"},
+  {"0x1.ffffef39085f4p-1", 6, "0.999999"},
+  {"0x1.ffffef39085f5p-1", 6, "1"},
+  {"0x1.3ffff583a53b8p+3", 6, "9.99999"},
+  {"0x1.3ffff583a53b9p+3", 6, "10"},
+  {"0x1.8ffff2e48e8a7p+6", 6, "99.9999"},
+  {"0x1.8ffff2e48e8a8p+6", 6, "100"},
+  {"0x1.f3ffef9db22d0p+9", 6, "999.999"},
+  {"0x1.f3ffef9db22d1p+9", 6, "1000"},
+  {"0x1.387ff5c28f5c2p+13", 6, "9999.99"},
+  {"0x1.387ff5c28f5c3p+13", 6, "10000"},
+  {"0x1.869ff33333333p+16", 6, "99999.9"},
+  {"0x1.869ff33333334p+16", 6, "100000"},
+  {"0x1.e847effffffffp+19", 6, "999999"},
+  {"0x1.e847f00000000p+19", 6, "1e+6"},
+  {"0x1.a36e2d51ec34bp-14", 7, "9.999999e-5"},
+  {"0x1.a36e2d51ec34cp-14", 7, "0.0001"},
+  {"0x1.0624dc5333a0ep-10", 7, "0.0009999999"},
+  {"0x1.0624dc5333a0fp-10", 7, "0.001"},
+  {"0x1.47ae136800892p-7", 7, "0.009999999"},
+  {"0x1.47ae136800893p-7", 7, "0.01"},
+  {"0x1.9999984200ab7p-4", 7, "0.09999999"},
+  {"0x1.9999984200ab8p-4", 7, "0.1"},
+  {"0x1.fffffe5280d65p-1", 7, "0.9999999"},
+  {"0x1.fffffe5280d66p-1", 7, "1"},
+  {"0x1.3ffffef39085fp+3", 7, "9.999999"},
+  {"0x1.3ffffef390860p+3", 7, "10"},
+  {"0x1.8ffffeb074a77p+6", 7, "99.99999"},
+  {"0x1.8ffffeb074a78p+6", 7, "100"},
+  {"0x1.f3fffe5c91d14p+9", 7, "999.9999"},
+  {"0x1.f3fffe5c91d15p+9", 7, "1000"},
+  {"0x1.387ffef9db22dp+13", 7, "9999.999"},
+  {"0x1.387ffef9db22ep+13", 7, "10000"},
+  {"0x1.869ffeb851eb8p+16", 7, "99999.99"},
+  {"0x1.869ffeb851eb9p+16", 7, "100000"},
+  {"0x1.e847fe6666666p+19", 7, "999999.9"},
+  {"0x1.e847fe6666667p+19", 7, "1000000"},
+  {"0x1.312cfefffffffp+23", 7, "9999999"},
+  {"0x1.312cff0000000p+23", 7, "1e+7"},
+  {"0x1.a36e2e8e94ffcp-14", 8, "9.9999999e-5"},
+  {"0x1.a36e2e8e94ffdp-14", 8, "0.0001"},
+  {"0x1.0624dd191d1fdp-10", 8, "0.00099999999"},
+  {"0x1.0624dd191d1fep-10", 8, "0.001"},
+  {"0x1.47ae145f6467dp-7", 8, "0.0099999999"},
+  {"0x1.47ae145f6467ep-7", 8, "0.01"},
+  {"0x1.999999773d81cp-4", 8, "0.099999999"},
+  {"0x1.999999773d81dp-4", 8, "0.1"},
+  {"0x1.ffffffd50ce23p-1", 8, "0.99999999"},
+  {"0x1.ffffffd50ce24p-1", 8, "1"},
+  {"0x1.3fffffe5280d6p+3", 8, "9.9999999"},
+  {"0x1.3fffffe5280d7p+3", 8, "10"},
+  {"0x1.8fffffde7210bp+6", 8, "99.999999"},
+  {"0x1.8fffffde7210cp+6", 8, "100"},
+  {"0x1.f3ffffd60e94ep+9", 8, "999.99999"},
+  {"0x1.f3ffffd60e94fp+9", 8, "1000"},
+  {"0x1.387fffe5c91d1p+13", 8, "9999.9999"},
+  {"0x1.387fffe5c91d2p+13", 8, "10000"},
+  {"0x1.869fffdf3b645p+16", 8, "99999.999"},
+  {"0x1.869fffdf3b646p+16", 8, "100000"},
+  {"0x1.e847ffd70a3d7p+19", 8, "999999.99"},
+  {"0x1.e847ffd70a3d8p+19", 8, "1000000"},
+  {"0x1.312cffe666666p+23", 8, "9999999.9"},
+  {"0x1.312cffe666667p+23", 8, "10000000"},
+  {"0x1.7d783fdffffffp+26", 8, "99999999"},
+  {"0x1.7d783fe000000p+26", 8, "1e+8"},
+  {"0x1.a36e2eae3f7a7p-14", 9, "9.99999999e-5"},
+  {"0x1.a36e2eae3f7a8p-14", 9, "0.0001"},
+  {"0x1.0624dd2ce7ac8p-10", 9, "0.000999999999"},
+  {"0x1.0624dd2ce7ac9p-10", 9, "0.001"},
+  {"0x1.47ae14782197bp-7", 9, "0.00999999999"},
+  {"0x1.47ae14782197cp-7", 9, "0.01"},
+  {"0x1.9999999629fd9p-4", 9, "0.0999999999"},
+  {"0x1.9999999629fdap-4", 9, "0.1"},
+  {"0x1.fffffffbb47d0p-1", 9, "0.999999999"},
+  {"0x1.fffffffbb47d1p-1", 9, "1"},
+  {"0x1.3ffffffd50ce2p+3", 9, "9.99999999"},
+  {"0x1.3ffffffd50ce3p+3", 9, "10"},
+  {"0x1.8ffffffca501ap+6", 9, "99.9999999"},
+  {"0x1.8ffffffca501bp+6", 9, "100"},
+  {"0x1.f3fffffbce421p+9", 9, "999.999999"},
+  {"0x1.f3fffffbce422p+9", 9, "1000"},
+  {"0x1.387ffffd60e94p+13", 9, "9999.99999"},
+  {"0x1.387ffffd60e95p+13", 9, "10000"},
+  {"0x1.869ffffcb923ap+16", 9, "99999.9999"},
+  {"0x1.869ffffcb923bp+16", 9, "100000"},
+  {"0x1.e847fffbe76c8p+19", 9, "999999.999"},
+  {"0x1.e847fffbe76c9p+19", 9, "1000000"},
+  {"0x1.312cfffd70a3dp+23", 9, "9999999.99"},
+  {"0x1.312cfffd70a3ep+23", 9, "10000000"},
+  {"0x1.7d783ffccccccp+26", 9, "99999999.9"},
+  {"0x1.7d783ffcccccdp+26", 9, "100000000"},
+  {"0x1.dcd64ffbfffffp+29", 9, "999999999"},
+  {"0x1.dcd64ffc00000p+29", 9, "1e+9"},
+  {"0x1.a36e2eb16a205p-14", 10, "9.999999999e-5"},
+  {"0x1.a36e2eb16a206p-14", 10, "0.0001"},
+  {"0x1.0624dd2ee2543p-10", 10, "0.0009999999999"},
+  {"0x1.0624dd2ee2544p-10", 10, "0.001"},
+  {"0x1.47ae147a9ae94p-7", 10, "0.009999999999"},
+  {"0x1.47ae147a9ae95p-7", 10, "0.01"},
+  {"0x1.9999999941a39p-4", 10, "0.09999999999"},
+  {"0x1.9999999941a3ap-4", 10, "0.1"},
+  {"0x1.ffffffff920c8p-1", 10, "0.9999999999"},
+  {"0x1.ffffffff920c9p-1", 10, "1"},
+  {"0x1.3fffffffbb47dp+3", 10, "9.999999999"},
+  {"0x1.3fffffffbb47ep+3", 10, "10"},
+  {"0x1.8fffffffaa19cp+6", 10, "99.99999999"},
+  {"0x1.8fffffffaa19dp+6", 10, "100"},
+  {"0x1.f3ffffff94a03p+9", 10, "999.9999999"},
+  {"0x1.f3ffffff94a04p+9", 10, "1000"},
+  {"0x1.387fffffbce42p+13", 10, "9999.999999"},
+  {"0x1.387fffffbce43p+13", 10, "10000"},
+  {"0x1.869fffffac1d2p+16", 10, "99999.99999"},
+  {"0x1.869fffffac1d3p+16", 10, "100000"},
+  {"0x1.e847ffff97247p+19", 10, "999999.9999"},
+  {"0x1.e847ffff97248p+19", 10, "1000000"},
+  {"0x1.312cffffbe76cp+23", 10, "9999999.999"},
+  {"0x1.312cffffbe76dp+23", 10, "10000000"},
+  {"0x1.7d783fffae147p+26", 10, "99999999.99"},
+  {"0x1.7d783fffae148p+26", 10, "100000000"},
+  {"0x1.dcd64fff99999p+29", 10, "999999999.9"},
+  {"0x1.dcd64fff9999ap+29", 10, "1000000000"},
+  {"0x1.2a05f1ffbffffp+33", 10, "9999999999"},
+  {"0x1.2a05f1ffc0000p+33", 10, "1e+10"},
+  {"0x1.a36e2eb1bb30fp-14", 11, "9.9999999999e-5"},
+  {"0x1.a36e2eb1bb310p-14", 11, "0.0001"},
+  {"0x1.0624dd2f14fe9p-10", 11, "0.00099999999999"},
+  {"0x1.0624dd2f14feap-10", 11, "0.001"},
+  {"0x1.47ae147ada3e3p-7", 11, "0.0099999999999"},
+  {"0x1.47ae147ada3e4p-7", 11, "0.01"},
+  {"0x1.9999999990cdcp-4", 11, "0.099999999999"},
+  {"0x1.9999999990cddp-4", 11, "0.1"},
+  {"0x1.fffffffff5014p-1", 11, "0.99999999999"},
+  {"0x1.fffffffff5015p-1", 11, "1"},
+  {"0x1.3ffffffff920cp+3", 11, "9.9999999999"},
+  {"0x1.3ffffffff920dp+3", 11, "10"},
+  {"0x1.8ffffffff768fp+6", 11, "99.999999999"},
+  {"0x1.8ffffffff7690p+6", 11, "100"},
+  {"0x1.f3fffffff5433p+9", 11, "999.99999999"},
+  {"0x1.f3fffffff5434p+9", 11, "1000"},
+  {"0x1.387ffffff94a0p+13", 11, "9999.9999999"},
+  {"0x1.387ffffff94a1p+13", 11, "10000"},
+  {"0x1.869ffffff79c8p+16", 11, "99999.999999"},
+  {"0x1.869ffffff79c9p+16", 11, "100000"},
+  {"0x1.e847fffff583ap+19", 11, "999999.99999"},
+  {"0x1.e847fffff583bp+19", 11, "1000000"},
+  {"0x1.312cfffff9724p+23", 11, "9999999.9999"},
+  {"0x1.312cfffff9725p+23", 11, "10000000"},
+  {"0x1.7d783ffff7cedp+26", 11, "99999999.999"},
+  {"0x1.7d783ffff7ceep+26", 11, "100000000"},
+  {"0x1.dcd64ffff5c28p+29", 11, "999999999.99"},
+  {"0x1.dcd64ffff5c29p+29", 11, "1000000000"},
+  {"0x1.2a05f1fff9999p+33", 11, "9999999999.9"},
+  {"0x1.2a05f1fff999ap+33", 11, "10000000000"},
+  {"0x1.74876e7ff7fffp+36", 11, "99999999999"},
+  {"0x1.74876e7ff8000p+36", 11, "1e+11"},
+  {"0x1.a36e2eb1c34c3p-14", 12, "9.99999999999e-5"},
+  {"0x1.a36e2eb1c34c4p-14", 12, "0.0001"},
+  {"0x1.0624dd2f1a0fap-10", 12, "0.000999999999999"},
+  {"0x1.0624dd2f1a0fbp-10", 12, "0.001"},
+  {"0x1.47ae147ae0938p-7", 12, "0.00999999999999"},
+  {"0x1.47ae147ae0939p-7", 12, "0.01"},
+  {"0x1.9999999998b86p-4", 12, "0.0999999999999"},
+  {"0x1.9999999998b87p-4", 12, "0.1"},
+  {"0x1.fffffffffee68p-1", 12, "0.999999999999"},
+  {"0x1.fffffffffee69p-1", 12, "1"},
+  {"0x1.3fffffffff501p+3", 12, "9.99999999999"},
+  {"0x1.3fffffffff502p+3", 12, "10"},
+  {"0x1.8fffffffff241p+6", 12, "99.9999999999"},
+  {"0x1.8fffffffff242p+6", 12, "100"},
+  {"0x1.f3fffffffeed1p+9", 12, "999.999999999"},
+  {"0x1.f3fffffffeed2p+9", 12, "1000"},
+  {"0x1.387fffffff543p+13", 12, "9999.99999999"},
+  {"0x1.387fffffff544p+13", 12, "10000"},
+  {"0x1.869fffffff294p+16", 12, "99999.9999999"},
+  {"0x1.869fffffff295p+16", 12, "100000"},
+  {"0x1.e847fffffef39p+19", 12, "999999.999999"},
+  {"0x1.e847fffffef3ap+19", 12, "1000000"},
+  {"0x1.312cffffff583p+23", 12, "9999999.99999"},
+  {"0x1.312cffffff584p+23", 12, "10000000"},
+  {"0x1.7d783fffff2e4p+26", 12, "99999999.9999"},
+  {"0x1.7d783fffff2e5p+26", 12, "100000000"},
+  {"0x1.dcd64ffffef9dp+29", 12, "999999999.999"},
+  {"0x1.dcd64ffffef9ep+29", 12, "1000000000"},
+  {"0x1.2a05f1ffff5c2p+33", 12, "9999999999.99"},
+  {"0x1.2a05f1ffff5c3p+33", 12, "10000000000"},
+  {"0x1.74876e7fff333p+36", 12, "99999999999.9"},
+  {"0x1.74876e7fff334p+36", 12, "100000000000"},
+  {"0x1.d1a94a1ffefffp+39", 12, "999999999999"},
+  {"0x1.d1a94a1fff000p+39", 12, "1e+12"},
+  {"0x1.a36e2eb1c41bbp-14", 13, "9.999999999999e-5"},
+  {"0x1.a36e2eb1c41bcp-14", 13, "0.0001"},
+  {"0x1.0624dd2f1a915p-10", 13, "0.0009999999999999"},
+  {"0x1.0624dd2f1a916p-10", 13, "0.001"},
+  {"0x1.47ae147ae135ap-7", 13, "0.009999999999999"},
+  {"0x1.47ae147ae135bp-7", 13, "0.01"},
+  {"0x1.9999999999831p-4", 13, "0.09999999999999"},
+  {"0x1.9999999999832p-4", 13, "0.1"},
+  {"0x1.ffffffffffe3dp-1", 13, "0.9999999999999"},
+  {"0x1.ffffffffffe3ep-1", 13, "1"},
+  {"0x1.3fffffffffee6p+3", 13, "9.999999999999"},
+  {"0x1.3fffffffffee7p+3", 13, "10"},
+  {"0x1.8fffffffffea0p+6", 13, "99.99999999999"},
+  {"0x1.8fffffffffea1p+6", 13, "100"},
+  {"0x1.f3ffffffffe48p+9", 13, "999.9999999999"},
+  {"0x1.f3ffffffffe49p+9", 13, "1000"},
+  {"0x1.387fffffffeedp+13", 13, "9999.999999999"},
+  {"0x1.387fffffffeeep+13", 13, "10000"},
+  {"0x1.869fffffffea8p+16", 13, "99999.99999999"},
+  {"0x1.869fffffffea9p+16", 13, "100000"},
+  {"0x1.e847ffffffe52p+19", 13, "999999.9999999"},
+  {"0x1.e847ffffffe53p+19", 13, "1000000"},
+  {"0x1.312cffffffef3p+23", 13, "9999999.999999"},
+  {"0x1.312cffffffef4p+23", 13, "10000000"},
+  {"0x1.7d783fffffeb0p+26", 13, "99999999.99999"},
+  {"0x1.7d783fffffeb1p+26", 13, "100000000"},
+  {"0x1.dcd64fffffe5cp+29", 13, "999999999.9999"},
+  {"0x1.dcd64fffffe5dp+29", 13, "1000000000"},
+  {"0x1.2a05f1ffffef9p+33", 13, "9999999999.999"},
+  {"0x1.2a05f1ffffefap+33", 13, "10000000000"},
+  {"0x1.74876e7fffeb8p+36", 13, "99999999999.99"},
+  {"0x1.74876e7fffeb9p+36", 13, "100000000000"},
+  {"0x1.d1a94a1fffe66p+39", 13, "999999999999.9"},
+  {"0x1.d1a94a1fffe67p+39", 13, "1000000000000"},
+  {"0x1.2309ce53ffeffp+43", 13, "9999999999999"},
+  {"0x1.2309ce53fff00p+43", 13, "1e+13"},
+  {"0x1.a36e2eb1c4307p-14", 14, "9.9999999999999e-5"},
+  {"0x1.a36e2eb1c4308p-14", 14, "0.0001"},
+  {"0x1.0624dd2f1a9e4p-10", 14, "0.00099999999999999"},
+  {"0x1.0624dd2f1a9e5p-10", 14, "0.001"},
+  {"0x1.47ae147ae145ep-7", 14, "0.0099999999999999"},
+  {"0x1.47ae147ae145fp-7", 14, "0.01"},
+  {"0x1.9999999999975p-4", 14, "0.099999999999999"},
+  {"0x1.9999999999976p-4", 14, "0.1"},
+  {"0x1.fffffffffffd2p-1", 14, "0.99999999999999"},
+  {"0x1.fffffffffffd3p-1", 14, "1"},
+  {"0x1.3ffffffffffe3p+3", 14, "9.9999999999999"},
+  {"0x1.3ffffffffffe4p+3", 14, "10"},
+  {"0x1.8ffffffffffdcp+6", 14, "99.999999999999"},
+  {"0x1.8ffffffffffddp+6", 14, "100"},
+  {"0x1.f3fffffffffd4p+9", 14, "999.99999999999"},
+  {"0x1.f3fffffffffd5p+9", 14, "1000"},
+  {"0x1.387ffffffffe4p+13", 14, "9999.9999999999"},
+  {"0x1.387ffffffffe5p+13", 14, "10000"},
+  {"0x1.869ffffffffddp+16", 14, "99999.999999999"},
+  {"0x1.869ffffffffdep+16", 14, "100000"},
+  {"0x1.e847fffffffd5p+19", 14, "999999.99999999"},
+  {"0x1.e847fffffffd6p+19", 14, "1000000"},
+  {"0x1.312cfffffffe5p+23", 14, "9999999.9999999"},
+  {"0x1.312cfffffffe6p+23", 14, "10000000"},
+  {"0x1.7d783ffffffdep+26", 14, "99999999.999999"},
+  {"0x1.7d783ffffffdfp+26", 14, "100000000"},
+  {"0x1.dcd64ffffffd6p+29", 14, "999999999.99999"},
+  {"0x1.dcd64ffffffd7p+29", 14, "1000000000"},
+  {"0x1.2a05f1fffffe5p+33", 14, "9999999999.9999"},
+  {"0x1.2a05f1fffffe6p+33", 14, "10000000000"},
+  {"0x1.74876e7ffffdfp+36", 14, "99999999999.999"},
+  {"0x1.74876e7ffffe0p+36", 14, "100000000000"},
+  {"0x1.d1a94a1ffffd7p+39", 14, "999999999999.99"},
+  {"0x1.d1a94a1ffffd8p+39", 14, "1000000000000"},
+  {"0x1.2309ce53fffe6p+43", 14, "9999999999999.9"},
+  {"0x1.2309ce53fffe7p+43", 14, "10000000000000"},
+  {"0x1.6bcc41e8fffdfp+46", 14, "99999999999999"},
+  {"0x1.6bcc41e8fffe0p+46", 14, "1e+14"},
+  {"0x1.a36e2eb1c4328p-14", 15, "9.99999999999999e-5"},
+  {"0x1.a36e2eb1c4329p-14", 15, "0.0001"},
+  {"0x1.0624dd2f1a9f9p-10", 15, "0.000999999999999999"},
+  {"0x1.0624dd2f1a9fap-10", 15, "0.001"},
+  {"0x1.47ae147ae1477p-7", 15, "0.00999999999999999"},
+  {"0x1.47ae147ae1478p-7", 15, "0.01"},
+  {"0x1.9999999999995p-4", 15, "0.0999999999999999"},
+  {"0x1.9999999999996p-4", 15, "0.1"},
+  {"0x1.ffffffffffffbp-1", 15, "0.999999999999999"},
+  {"0x1.ffffffffffffcp-1", 15, "1"},
+  {"0x1.3fffffffffffdp+3", 15, "9.99999999999999"},
+  {"0x1.3fffffffffffep+3", 15, "10"},
+  {"0x1.8fffffffffffcp+6", 15, "99.9999999999999"},
+  {"0x1.8fffffffffffdp+6", 15, "100"},
+  {"0x1.f3ffffffffffbp+9", 15, "999.999999999999"},
+  {"0x1.f3ffffffffffcp+9", 15, "1000"},
+  {"0x1.387fffffffffdp+13", 15, "9999.99999999999"},
+  {"0x1.387fffffffffep+13", 15, "10000"},
+  {"0x1.869fffffffffcp+16", 15, "99999.9999999999"},
+  {"0x1.869fffffffffdp+16", 15, "100000"},
+  {"0x1.e847ffffffffbp+19", 15, "999999.999999999"},
+  {"0x1.e847ffffffffcp+19", 15, "1000000"},
+  {"0x1.312cffffffffdp+23", 15, "9999999.99999999"},
+  {"0x1.312cffffffffep+23", 15, "10000000"},
+  {"0x1.7d783fffffffcp+26", 15, "99999999.9999999"},
+  {"0x1.7d783fffffffdp+26", 15, "100000000"},
+  {"0x1.dcd64fffffffbp+29", 15, "999999999.999999"},
+  {"0x1.dcd64fffffffcp+29", 15, "1000000000"},
+  {"0x1.2a05f1ffffffdp+33", 15, "9999999999.99999"},
+  {"0x1.2a05f1ffffffep+33", 15, "10000000000"},
+  {"0x1.74876e7fffffcp+36", 15, "99999999999.9999"},
+  {"0x1.74876e7fffffdp+36", 15, "100000000000"},
+  {"0x1.d1a94a1fffffbp+39", 15, "999999999999.999"},
+  {"0x1.d1a94a1fffffcp+39", 15, "1000000000000"},
+  {"0x1.2309ce53ffffdp+43", 15, "9999999999999.99"},
+  {"0x1.2309ce53ffffep+43", 15, "10000000000000"},
+  {"0x1.6bcc41e8ffffcp+46", 15, "99999999999999.9"},
+  {"0x1.6bcc41e8ffffdp+46", 15, "100000000000000"},
+  {"0x1.c6bf52633fffbp+49", 15, "999999999999999"},
+  {"0x1.c6bf52633fffcp+49", 15, "1e+15"},
+  {"0x1.1c37937e07fffp+53", 16, "9999999999999998"},
+  {"0x1.1c37937e08000p+53", 16, "1e+16"},
+  {"0x1.6345785d89fffp+56", 17, "99999999999999984"},
+  {"0x1.6345785d8a000p+56", 17, "1e+17"},
+  {"0x1.bc16d674ec7ffp+59", 18, "999999999999999872"},
+  {"0x1.bc16d674ec800p+59", 18, "1e+18"},
+  {"0x1.158e460913cffp+63", 19, "9999999999999997952"},
+  {"0x1.158e460913d00p+63", 19, "1e+19"},
+  {"0x1.5af1d78b58c3fp+66", 20, "99999999999999983616"},
+  {"0x1.5af1d78b58c40p+66", 20, "1e+20"},
+  {"0x1.b1ae4d6e2ef4fp+69", 21, "999999999999999868928"},
+  {"0x1.b1ae4d6e2ef50p+69", 21, "1e+21"},
+  {"0x1.0f0cf064dd591p+73", 22, "9999999999999997902848"},
+  {"0x1.0f0cf064dd592p+73", 22, "1e+22"},
+  {"0x1.52d02c7e14af6p+76", 23, "99999999999999991611392"},
+  {"0x1.52d02c7e14af7p+76", 23, "1.0000000000000000838861e+23"},
+  {"0x1.a784379d99db4p+79", 24, "999999999999999983222784"},
+  {"0x1.a784379d99db5p+79", 24, "1.00000000000000011744051e+24"},
+  {"0x1.a36e2eb1c432cp-14", 25, "9.999999999999999123964645e-5"},
+  {"0x1.a36e2eb1c432dp-14", 25, "0.0001000000000000000047921736"},
+  {"0x1.0624dd2f1a9fbp-10", 25, "0.0009999999999999998039762472"},
+  {"0x1.0624dd2f1a9fcp-10", 25, "0.001000000000000000020816682"},
+  {"0x1.47ae147ae147ap-7", 25, "0.009999999999999998473443341"},
+  {"0x1.47ae147ae147bp-7", 25, "0.01000000000000000020816682"},
+  {"0x1.9999999999999p-4", 25, "0.09999999999999999167332732"},
+  {"0x1.999999999999ap-4", 25, "0.1000000000000000055511151"},
+  {"0x1.fffffffffffffp-1", 25, "0.9999999999999998889776975"},
+  {"0x1.0000000000000p+0", 25, "1"},
+  {"0x1.3ffffffffffffp+3", 25, "9.999999999999998223643161"},
+  {"0x1.4000000000000p+3", 25, "10"},
+  {"0x1.8ffffffffffffp+6", 25, "99.99999999999998578914528"},
+  {"0x1.9000000000000p+6", 25, "100"},
+  {"0x1.f3fffffffffffp+9", 25, "999.9999999999998863131623"},
+  {"0x1.f400000000000p+9", 25, "1000"},
+  {"0x1.387ffffffffffp+13", 25, "9999.999999999998181010596"},
+  {"0x1.3880000000000p+13", 25, "10000"},
+  {"0x1.869ffffffffffp+16", 25, "99999.99999999998544808477"},
+  {"0x1.86a0000000000p+16", 25, "100000"},
+  {"0x1.e847fffffffffp+19", 25, "999999.9999999998835846782"},
+  {"0x1.e848000000000p+19", 25, "1000000"},
+  {"0x1.312cfffffffffp+23", 25, "9999999.999999998137354851"},
+  {"0x1.312d000000000p+23", 25, "10000000"},
+  {"0x1.7d783ffffffffp+26", 25, "99999999.99999998509883881"},
+  {"0x1.7d78400000000p+26", 25, "100000000"},
+  {"0x1.dcd64ffffffffp+29", 25, "999999999.9999998807907104"},
+  {"0x1.dcd6500000000p+29", 25, "1000000000"},
+  {"0x1.2a05f1fffffffp+33", 25, "9999999999.999998092651367"},
+  {"0x1.2a05f20000000p+33", 25, "10000000000"},
+  {"0x1.74876e7ffffffp+36", 25, "99999999999.99998474121094"},
+  {"0x1.74876e8000000p+36", 25, "100000000000"},
+  {"0x1.d1a94a1ffffffp+39", 25, "999999999999.9998779296875"},
+  {"0x1.d1a94a2000000p+39", 25, "1000000000000"},
+  {"0x1.2309ce53fffffp+43", 25, "9999999999999.998046875"},
+  {"0x1.2309ce5400000p+43", 25, "10000000000000"},
+  {"0x1.6bcc41e8fffffp+46", 25, "99999999999999.984375"},
+  {"0x1.6bcc41e900000p+46", 25, "100000000000000"},
+  {"0x1.c6bf52633ffffp+49", 25, "999999999999999.875"},
+  {"0x1.c6bf526340000p+49", 25, "1000000000000000"},
+  {"0x1.1c37937e07fffp+53", 25, "9999999999999998"},
+  {"0x1.1c37937e08000p+53", 25, "10000000000000000"},
+  {"0x1.6345785d89fffp+56", 25, "99999999999999984"},
+  {"0x1.6345785d8a000p+56", 25, "100000000000000000"},
+  {"0x1.bc16d674ec7ffp+59", 25, "999999999999999872"},
+  {"0x1.bc16d674ec800p+59", 25, "1000000000000000000"},
+  {"0x1.158e460913cffp+63", 25, "9999999999999997952"},
+  {"0x1.158e460913d00p+63", 25, "10000000000000000000"},
+  {"0x1.5af1d78b58c3fp+66", 25, "99999999999999983616"},
+  {"0x1.5af1d78b58c40p+66", 25, "100000000000000000000"},
+  {"0x1.b1ae4d6e2ef4fp+69", 25, "999999999999999868928"},
+  {"0x1.b1ae4d6e2ef50p+69", 25, "1000000000000000000000"},
+  {"0x1.0f0cf064dd591p+73", 25, "9999999999999997902848"},
+  {"0x1.0f0cf064dd592p+73", 25, "10000000000000000000000"},
+  {"0x1.52d02c7e14af6p+76", 25, "99999999999999991611392"},
+  {"0x1.52d02c7e14af7p+76", 25, "100000000000000008388608"},
+  {"0x1.a784379d99db4p+79", 25, "999999999999999983222784"},
+  {"0x1.a784379d99db5p+79", 25, "1000000000000000117440512"},
+  {"0x1.08b2a2c280290p+83", 25, "9999999999999998758486016"},
+  {"0x1.08b2a2c280291p+83", 25, "1.000000000000000090596966e+25"},
+  {"0x1.4adf4b7320334p+86", 26, "99999999999999987584860160"},
+  {"0x1.4adf4b7320335p+86", 26, "1.0000000000000000476472934e+26"},
+  {"0x1.9d971e4fe8401p+89", 27, "999999999999999875848601600"},
+  {"0x1.9d971e4fe8402p+89", 27, "1.00000000000000001328755507e+27"},
+  {"0x1.027e72f1f1281p+93", 28, "9999999999999999583119736832"},
+  {"0x1.027e72f1f1282p+93", 28, "1.000000000000000178214299238e+28"},
+  {"0x1.431e0fae6d721p+96", 29, "99999999999999991433150857216"},
+  {"0x1.431e0fae6d722p+96", 29, "1.0000000000000000902533690163e+29"},
+  {"0x1.93e5939a08ce9p+99", 30, "999999999999999879147136483328"},
+  {"0x1.93e5939a08ceap+99", 30, "1.00000000000000001988462483866e+30"},
+  {"0x1.f8def8808b024p+102", 31, "9999999999999999635896294965248"},
+  {"0x1.f8def8808b025p+102", 31, "1.000000000000000076179620180787e+31"},
+  {"0x1.3b8b5b5056e16p+106", 32, "99999999999999987351763694911488"},
+  {"0x1.3b8b5b5056e17p+106", 32, "1.0000000000000000536616220439347e+32"},
+  {"0x1.8a6e32246c99cp+109", 33, "999999999999999945575230987042816"},
+  {"0x1.8a6e32246c99dp+109", 33, "1.00000000000000008969041906289869e+33"},
+  {"0x1.ed09bead87c03p+112", 34, "9999999999999999455752309870428160"},
+  {"0x1.ed09bead87c04p+112", 34, "1.000000000000000060867381447727514e+34"},
+  {"0x1.3426172c74d82p+116", 35, "99999999999999996863366107917975552"},
+  {"0x1.3426172c74d83p+116", 35, "1.0000000000000001531011018162752717e+35"},
+  {"0x1.812f9cf7920e2p+119", 36, "999999999999999894846684784341549056"},
+  {"0x1.812f9cf7920e3p+119", 36, "1.00000000000000004242063737401796198e+36"},
+  {"0x1.e17b84357691bp+122", 37, "9999999999999999538762658202121142272"},
+  {"0x1.e17b84357691cp+122", 37, "1.00000000000000007193542789195324457e+37"},
+  {"0x1.2ced32a16a1b1p+126", 38, "99999999999999997748809823456034029568"},
+  {"0x1.2ced32a16a1b2p+126", 38, "1.0000000000000001663827575493461488435e+38"},
+  {"0x1.78287f49c4a1dp+129", 39, "999999999999999939709166371603178586112"},
+  {"0x1.78287f49c4a1ep+129", 39, "1.00000000000000009082489382343182542438e+39"},
+  {"0x1.d6329f1c35ca4p+132", 40, "9999999999999999094860208812374492184576"},
+  {"0x1.d6329f1c35ca5p+132", 40, "1.000000000000000030378602842700366689075e+40"},
+  {"0x1.25dfa371a19e6p+136", 41, "99999999999999981277195531206711524196352"},
+  {"0x1.25dfa371a19e7p+136", 41, "1.0000000000000000062000864504077831949517e+41"},
+  {"0x1.6f578c4e0a060p+139", 42, "999999999999999890143207767403382423158784"},
+  {"0x1.6f578c4e0a061p+139", 42, "1.00000000000000004488571267807591678554931e+42"},
+  {"0x1.cb2d6f618c878p+142", 43, "9999999999999998901432077674033824231587840"},
+  {"0x1.cb2d6f618c879p+142", 43, "1.000000000000000013937211695941409913071206e+43"},
+  {"0x1.1efc659cf7d4bp+146", 44, "99999999999999989014320776740338242315878400"},
+  {"0x1.1efc659cf7d4cp+146", 44, "1.0000000000000000882136140530642264070186598e+44"},
+  {"0x1.66bb7f0435c9ep+149", 45, "999999999999999929757289024535551219930759168"},
+  {"0x1.66bb7f0435c9fp+149", 45, "1.00000000000000008821361405306422640701865984e+45"},
+  {"0x1.c06a5ec5433c6p+152", 46, "9999999999999999931398190359470212947659194368"},
+  {"0x1.c06a5ec5433c7p+152", 46, "1.000000000000000119904879058769961444436239974e+46"},
+  {"0x1.18427b3b4a05bp+156", 47, "99999999999999984102174700855949311516153479168"},
+  {"0x1.18427b3b4a05cp+156", 47, "1.0000000000000000438458430450761973546340476518e+47"},
+  {"0x1.5e531a0a1c872p+159", 48, "999999999999999881586566215862833963056037363712"},
+  {"0x1.5e531a0a1c873p+159", 48, "1.00000000000000004384584304507619735463404765184e+48"},
+  {"0x1.b5e7e08ca3a8fp+162", 49, "9999999999999999464902769475481793196872414789632"},
+  {"0x1.b5e7e08ca3a90p+162", 49, "1.000000000000000076297698410918870032949649709466e+49"},
+  {"0x1.11b0ec57e6499p+166", 50, "99999999999999986860582406952576489172979654066176"},
+  {"0x1.11b0ec57e649ap+166", 50, "1.0000000000000000762976984109188700329496497094656e+50"},
+  {"0x1.561d276ddfdc0p+169", 51, "999999999999999993220948674361627976461708441944064"},
+  {"0x1.561d276ddfdc1p+169", 51, "1.00000000000000015937444814747611208943759097698714e+51"},
+  {"0x1.aba4714957d30p+172", 52, "9999999999999999932209486743616279764617084419440640"},
+  {"0x1.aba4714957d31p+172", 52, "1.000000000000000126143748252853215266842414469978522e+52"},
+  {"0x1.0b46c6cdd6e3ep+176", 53, "99999999999999999322094867436162797646170844194406400"},
+  {"0x1.0b46c6cdd6e3fp+176", 53, "1.0000000000000002058974279999481676410708380867991962e+53"},
+  {"0x1.4e1878814c9cdp+179", 54, "999999999999999908150356944127012110618056584002011136"},
+  {"0x1.4e1878814c9cep+179", 54, "1.00000000000000007829154040459624384230536029988611686e+54"},
+  {"0x1.a19e96a19fc40p+182", 55, "9999999999999998741221202520331657642805958408251899904"},
+  {"0x1.a19e96a19fc41p+182", 55, "1.000000000000000010235067020408551149630438813532474573e+55"},
+  {"0x1.05031e2503da8p+186", 56, "99999999999999987412212025203316576428059584082518999040"},
+  {"0x1.05031e2503da9p+186", 56, "1.0000000000000000919028350814337823808403445971568453222e+56"},
+  {"0x1.4643e5ae44d12p+189", 57, "999999999999999874122120252033165764280595840825189990400"},
+  {"0x1.4643e5ae44d13p+189", 57, "1.00000000000000004834669211555365905752839484589051425587e+57"},
+  {"0x1.97d4df19d6057p+192", 58, "9999999999999999438119489974413630815797154428513196965888"},
+  {"0x1.97d4df19d6058p+192", 58, "1.000000000000000083191606488257757716177954646903579108966e+58"},
+  {"0x1.fdca16e04b86dp+195", 59, "99999999999999997168788049560464200849936328366177157906432"},
+  {"0x1.fdca16e04b86ep+195", 59, "1.0000000000000000831916064882577577161779546469035791089664e+59"},
+  {"0x1.3e9e4e4c2f344p+199", 60, "999999999999999949387135297074018866963645011013410073083904"},
+  {"0x1.3e9e4e4c2f345p+199", 60, "1.00000000000000012779309688531900399924939119220030212092723e+60"},
+  {"0x1.8e45e1df3b015p+202", 61, "9999999999999999493871352970740188669636450110134100730839040"},
+  {"0x1.8e45e1df3b016p+202", 61, "1.000000000000000092111904567670006972792241955962923711358566e+61"},
+  {"0x1.f1d75a5709c1ap+205", 62, "99999999999999992084218144295482124579792562202350734542897152"},
+  {"0x1.f1d75a5709c1bp+205", 62, "1.0000000000000000350219968594316117304608031779831182560487014e+62"},
+  {"0x1.3726987666190p+209", 63, "999999999999999875170255276364105051932774599639662981181079552"},
+  {"0x1.3726987666191p+209", 63, "1.00000000000000005785795994272696982739337868917504043817264742e+63"},
+  {"0x1.84f03e93ff9f4p+212", 64, "9999999999999998751702552763641050519327745996396629811810795520"},
+  {"0x1.84f03e93ff9f5p+212", 64, "1.00000000000000002132041900945439687230125787126796494677433385e+64"},
+  {"0x1.e62c4e38ff872p+215", 65, "99999999999999999209038626283633850822756121694230455365568299008"},
+  {"0x1.e62c4e38ff873p+215", 65, "1.0000000000000001090105172493085719645223478342449461261302864282e+65"},
+  {"0x1.2fdbb0e39fb47p+219", 66, "999999999999999945322333868247445125709646570021247924665841614848"},
+  {"0x1.2fdbb0e39fb48p+219", 66, "1.00000000000000013239454344660301865578130515770547444062520711578e+66"},
+  {"0x1.7bd29d1c87a19p+222", 67, "9999999999999999827367757839185598317239782875580932278577147150336"},
+  {"0x1.7bd29d1c87a1ap+222", 67, "1.000000000000000132394543446603018655781305157705474440625207115776e+67"},
+  {"0x1.dac74463a989fp+225", 68, "99999999999999995280522225138166806691251291352861698530421623488512"},
+  {"0x1.dac74463a98a0p+225", 68, "1.000000000000000072531436381529235126158374409646521955518210155479e+68"},
+  {"0x1.28bc8abe49f63p+229", 69, "999999999999999880969493773293127831364996015857874003175819882528768"},
+  {"0x1.28bc8abe49f64p+229", 69, "1.00000000000000007253143638152923512615837440964652195551821015547904e+69"},
+  {"0x1.72ebad6ddc73cp+232", 70, "9999999999999999192818822949403492903236716946156035936442979371188224"},
+  {"0x1.72ebad6ddc73dp+232", 70, "1.00000000000000007253143638152923512615837440964652195551821015547904e+70"},
+  {"0x1.cfa698c95390bp+235", 71, "99999999999999991928188229494034929032367169461560359364429793711882240"},
+  {"0x1.cfa698c95390cp+235", 71, "1.0000000000000000418815255642114579589914338666403382831434277118069965e+71"},
+  {"0x1.21c81f7dd43a7p+239", 72, "999999999999999943801810948794571024057224129020550531544123892056457216"},
+  {"0x1.21c81f7dd43a8p+239", 72, "1.00000000000000013996124017962834489392564360426012603474273153155753574e+72"},
+  {"0x1.6a3a275d49491p+242", 73, "9999999999999999830336967949613257980309080240684656321838454199566729216"},
+  {"0x1.6a3a275d49492p+242", 73, "1.000000000000000139961240179628344893925643604260126034742731531557535744e+73"},
+  {"0x1.c4c8b1349b9b5p+245", 74, "99999999999999995164818811802792197885196090803013355167206819763650035712"},
+  {"0x1.c4c8b1349b9b6p+245", 74, "1.000000000000000077190222825761537255567749372183461873719177086917190615e+74"},
+  {"0x1.1afd6ec0e1411p+249", 75, "999999999999999926539781176481198923508803215199467887262646419780362305536"},
+  {"0x1.1afd6ec0e1412p+249", 75, "1.00000000000000012740703670885498336625406475784479320253802064262946671821e+75"},
+  {"0x1.61bcca7119915p+252", 76, "9999999999999998863663300700064420349597509066704028242075715752105414230016"},
+  {"0x1.61bcca7119916p+252", 76, "1.000000000000000047060134495905469589155960140786663076427870953489824953139e+76"},
+  {"0x1.ba2bfd0d5ff5bp+255", 77, "99999999999999998278261272554585856747747644714015897553975120217811154108416"},
+  {"0x1.ba2bfd0d5ff5cp+255", 77, "1.0000000000000001113376562662650806108344438344331671773159907048015383651942e+77"},
+  {"0x1.145b7e285bf98p+259", 78, "999999999999999802805551768538947706777722104929947493053015898505313987330048"},
+  {"0x1.145b7e285bf99p+259", 78, "1.00000000000000000849362143368970297614886992459876061589499910270279690590618e+78"},
+  {"0x1.59725db272f7fp+262", 79, "9999999999999999673560075006595519222746403606649979913266024618633003221909504"},
+  {"0x1.59725db272f80p+262", 79, "1.000000000000000131906463232780156137771558616400048489600189025221286657051853e+79"},
+  {"0x1.afcef51f0fb5ep+265", 80, "99999999999999986862573406138718939297648940722396769236245052384850852127440896"},
+  {"0x1.afcef51f0fb5fp+265", 80, "1.0000000000000000002660986470836727653740240118120080909813197745348975891631309e+80"},
+  {"0x1.0de1593369d1bp+269", 81, "999999999999999921281879895665782741935503249059183851809998224123064148429897728"},
+  {"0x1.0de1593369d1cp+269", 81, "1.0000000000000001319064632327801561377715586164000484896001890252212866570518528e+81"},
+  {"0x1.5159af8044462p+272", 82, "9999999999999999634067965630886574211027143225273567793680363843427086501542887424"},
+  {"0x1.5159af8044463p+272", 82, "1.0000000000000001319064632327801561377715586164000484896001890252212866570518528e+82"},
+  {"0x1.a5b01b605557ap+275", 83, "99999999999999989600692989521205793443517660497828009527517532799127744739526311936"},
+  {"0x1.a5b01b605557bp+275", 83, "1.0000000000000000308066632309652569077702520400764334634608974406941398529133143654e+83"},
+  {"0x1.078e111c3556cp+279", 84, "999999999999999842087036560910778345101146430939018748000886482910132485188042620928"},
+  {"0x1.078e111c3556dp+279", 84, "1.00000000000000005776660989811589670243726712709606413709804186323471233401692461466e+84"},
+  {"0x1.4971956342ac7p+282", 85, "9999999999999998420870365609107783451011464309390187480008864829101324851880426209280"},
+  {"0x1.4971956342ac8p+282", 85, "1.00000000000000001463069523067487303097004298786465505927861078716979636425114821591e+85"},
+  {"0x1.9bcdfabc13579p+285", 86, "99999999999999987659576829486359728227492574232414601025643134376206526100066373992448"},
+  {"0x1.9bcdfabc1357ap+285", 86, "1.0000000000000000146306952306748730309700429878646550592786107871697963642511482159104e+86"},
+  {"0x1.0160bcb58c16cp+289", 87, "999999999999999959416724456350362731491996089648451439669739009806703922950954425516032"},
+  {"0x1.0160bcb58c16dp+289", 87, "1.0000000000000001802726075536484039294041836825132659181052261192590736881517295870935e+87"},
+  {"0x1.41b8ebe2ef1c7p+292", 88, "9999999999999999594167244563503627314919960896484514396697390098067039229509544255160320"},
+  {"0x1.41b8ebe2ef1c8p+292", 88, "1.00000000000000013610143093418879568982174616394030302241812869736859973511157455477801e+88"},
+  {"0x1.922726dbaae39p+295", 89, "99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752"},
+  {"0x1.922726dbaae3ap+295", 89, "1.0000000000000001361014309341887956898217461639403030224181286973685997351115745547780096e+89"},
+  {"0x1.f6b0f092959c7p+298", 90, "999999999999999966484112715463900049825186092620125502979674597309179755437379230686511104"},
+  {"0x1.f6b0f092959c8p+298", 90, "1.00000000000000007956232486128049714315622614016691051593864399734879307522017611341417677e+90"},
+  {"0x1.3a2e965b9d81cp+302", 91, "9999999999999998986371854279739417938265620640920544952042929572854117635677011010499117056"},
+  {"0x1.3a2e965b9d81dp+302", 91, "1.000000000000000079562324861280497143156226140166910515938643997348793075220176113414176768e+91"},
+  {"0x1.88ba3bf284e23p+305", 92, "99999999999999989863718542797394179382656206409205449520429295728541176356770110104991170560"},
+  {"0x1.88ba3bf284e24p+305", 92, "1.0000000000000000433772969746191860732902933249519393117917737893361168128896811109413237555e+92"},
+  {"0x1.eae8caef261acp+308", 93, "999999999999999927585207737302990649719308316264031458521789123695552773432097103028194115584"},
+  {"0x1.eae8caef261adp+308", 93, "1.00000000000000004337729697461918607329029332495193931179177378933611681288968111094132375552e+93"},
+  {"0x1.32d17ed577d0bp+312", 94, "9999999999999998349515363474500343108625203093137051759058013911831015418660298966976904036352"},
+  {"0x1.32d17ed577d0cp+312", 94, "1.000000000000000020218879127155946988576096323214357741137776856208004004998164309358697827533e+94"},
+  {"0x1.7f85de8ad5c4ep+315", 95, "99999999999999987200500490339121684640523551209383568895219648418808203449245677922989188841472"},
+  {"0x1.7f85de8ad5c4fp+315", 95, "1.0000000000000000202188791271559469885760963232143577411377768562080040049981643093586978275328e+95"},
+  {"0x1.df67562d8b362p+318", 96, "999999999999999931290554592897108903273579836542044509826428632996050822694739791281414264061952"},
+  {"0x1.df67562d8b363p+318", 96, "1.00000000000000004986165397190889301701026848543846215157489293061198839909930581538445901535642e+96"},
+  {"0x1.2ba095dc7701dp+322", 97, "9999999999999998838621148412923952577789043769834774531270429139496757921329133816401963635441664"},
+  {"0x1.2ba095dc7701ep+322", 97, "1.000000000000000073575873847711249839757606215217745679924585790135175914380219020205067965615309e+97"},
+  {"0x1.7688bb5394c25p+325", 98, "99999999999999999769037024514370800696612547992403838920556863966097586548129676477911932478685184"},
+  {"0x1.7688bb5394c26p+325", 98, "1.0000000000000001494613774502787916725490869505114529706436029406093759632791412756310166064437658e+98"},
+  {"0x1.d42aea2879f2ep+328", 99, "999999999999999967336168804116691273849533185806555472917961779471295845921727862608739868455469056"},
+  {"0x1.d42aea2879f2fp+328", 99, "1.00000000000000008875297456822475820631590236227648713806838922023001592416000347129025769378100019e+99"},
+  {"0x1.249ad2594c37cp+332", 100, "9999999999999998216360018871870109548898901740426374747374488505608317520357971321909184780648316928"},
+  {"0x1.249ad2594c37dp+332", 100, "1.00000000000000001590289110975991804683608085639452813897813275577478387721703810608134699858568151e+100"},
+  {"0x1.6dc186ef9f45cp+335", 101, "99999999999999997704951326524533662844684271992415000612999597473199345218078991130326129448151154688"},
+  {"0x1.6dc186ef9f45dp+335", 101, "1.000000000000000132463024643303662302003795265805662537522543098903155152325782690415604110898191401e+101"},
+  {"0x1.c931e8ab87173p+338", 102, "999999999999999977049513265245336628446842719924150006129995974731993452180789911303261294481511546880"},
+  {"0x1.c931e8ab87174p+338", 102, "1.00000000000000010138032236769199716729240475662936003124403367406892281229678413459313554761485543014e+102"},
+  {"0x1.1dbf316b346e7p+342", 103, "9999999999999998029863805218200118740630558685368559709703431956602923480183979986974373400948301103104"},
+  {"0x1.1dbf316b346e8p+342", 103, "1.000000000000000001915675085734668736215955127265192011152803514599379324203988755961236145108180323533e+103"},
+  {"0x1.652efdc6018a1p+345", 104, "99999999999999984277223943460294324649363572028252317900683525944810974325551615015019710109750015295488"},
+  {"0x1.652efdc6018a2p+345", 104, "1.0000000000000000019156750857346687362159551272651920111528035145993793242039887559612361451081803235328e+104"},
+  {"0x1.be7abd3781ecap+348", 105, "999999999999999938258300825281978540327027364472124478294416212538871491824599713636820527503908255301632"},
+  {"0x1.be7abd3781ecbp+348", 105, "1.00000000000000006557304934618735893210488289005825954401119081665988715658337779828565176271245239176397e+105"},
+  {"0x1.170cb642b133ep+352", 106, "9999999999999998873324014169198263836158851542376704520077063708904652259210884797772880334204906007166976"},
+  {"0x1.170cb642b133fp+352", 106, "1.000000000000000091035999050368435010460453995175486557154545737484090289535133415215418009754161219056435e+106"},
+  {"0x1.5ccfe3d35d80ep+355", 107, "99999999999999996881384047029926983435371269061279689406644211752791525136670645395254002395395884805259264"},
+  {"0x1.5ccfe3d35d80fp+355", 107, "1.0000000000000001317767185770581567358293677633630497781839136108028153022579424023030440050208953427243827e+107"},
+  {"0x1.b403dcc834e11p+358", 108, "999999999999999903628689227595715073763450661512695740419453520217955231010212074612338431527184250183876608"},
+  {"0x1.b403dcc834e12p+358", 108, "1.00000000000000003399899171300282459494397471971289804771343071483787527172320083329274161638073344592130867e+108"},
+  {"0x1.108269fd210cbp+362", 109, "9999999999999999818508707188399807864717650964328171247958398369899072554380053298205803424393137676263358464"},
+  {"0x1.108269fd210ccp+362", 109, "1.000000000000000190443354695491356020360603589553140816466203348381779320578787343709225438204992480806227149e+109"},
+  {"0x1.54a3047c694fdp+365", 110, "99999999999999985669538033284915564613846200056062290979362173015478401635353612148739328497990653971840106496"},
+  {"0x1.54a3047c694fep+365", 110, "1.0000000000000000235693675141702558332495327950568818631299125392682816684661617325983093615924495102623141069e+110"},
+  {"0x1.a9cbc59b83a3dp+368", 111, "999999999999999956819772641641815758405104477258378281795396215622882607621111488153942930947432322044748890112"},
+  {"0x1.a9cbc59b83a3ep+368", 111, "1.00000000000000009031896238669869590809396111285538544446442886291368072931121197704267579223746669847987932365e+111"},
+  {"0x1.0a1f5b8132466p+372", 112, "9999999999999999301199346926304397284673331501389768492615896861647229832830913903761963586894254467577228034048"},
+  {"0x1.0a1f5b8132467p+372", 112, "1.000000000000000143718638284721447967969503767094188309532041921829999977987252172598168936753480449053931497062e+112"},
+  {"0x1.4ca732617ed7fp+375", 113, "99999999999999984468045325579403643266646490335689226515340879189861218540142707748740732746380344583923932594176"},
+  {"0x1.4ca732617ed80p+375", 113, "1.0000000000000000155594161294668430242682013969210614333697705804308337811647557032649853899150474476762062808678e+113"},
+  {"0x1.9fd0fef9de8dfp+378", 114, "999999999999999878856245830528597750986812202069726098796681149605056504554092802642922939954052246206632716926976"},
+  {"0x1.9fd0fef9de8e0p+378", 114, "1.00000000000000001555941612946684302426820139692106143336977058043083378116475570326498538991504744767620628086784e+114"},
+  {"0x1.03e29f5c2b18bp+382", 115, "9999999999999997968343436511656505870179786851589248980528274911095901385876950622696854699774551253248885785624576"},
+  {"0x1.03e29f5c2b18cp+382", 115, "1.00000000000000001555941612946684302426820139692106143336977058043083378116475570326498538991504744767620628086784e+115"},
+  {"0x1.44db473335deep+385", 116, "99999999999999984057935814682588907446802322751135220511621610897383886710310719046874545396497358979515211902353408"},
+  {"0x1.44db473335defp+385", 116, "1.00000000000000001555941612946684302426820139692106143336977058043083378116475570326498538991504744767620628086784e+116"},
+  {"0x1.961219000356ap+388", 117, "999999999999999910571381339882270654388094495275235896417637897556636832727766595587241428345003132947573783761256448"},
+  {"0x1.961219000356bp+388", 117, "1.00000000000000005055542772599503381422823703080300327902048147472223276397708540582423337710506221925241711323670118e+117"},
+  {"0x1.fb969f40042c5p+391", 118, "9999999999999999665649998943273759183241515094863428494587753284228752052274941196820382078490267674695111155514343424"},
+  {"0x1.fb969f40042c6p+391", 118, "1.000000000000000078552237003217586446196265537908556755541050190155351950226949167871631766857074036513385779131790131e+118"},
+  {"0x1.3d3e2388029bbp+395", 119, "99999999999999994416755247254933381274972870380190006824232035607637985622760311004411949604741731366073618283536318464"},
+  {"0x1.3d3e2388029bcp+395", 119, "1.0000000000000001233471318467736706573451111492774423179739601348483426482267311871474691904602929441309356445639324467e+119"},
+  {"0x1.8c8dac6a0342ap+398", 120, "999999999999999980003468347394201181668805192897008518188648311830772414627428725464789434929992439754776075181077037056"},
+  {"0x1.8c8dac6a0342bp+398", 120, "1.00000000000000012334713184677367065734511114927744231797396013484834264822673118714746919046029294413093564456393244672e+120"},
+  {"0x1.efb1178484134p+401", 121, "9999999999999999226660029476424133913982828103448349982745235826237443211877077407917175327178722380043122474279348731904"},
+  {"0x1.efb1178484135p+401", 121, "1.000000000000000037340933747145988971939327575449182038102773041037800508067149710137861337142112641505239902934219200922e+121"},
+  {"0x1.35ceaeb2d28c0p+405", 122, "99999999999999983092605830803955292696544699826135736641192401589249937168415416531480248917847991520357012302290741100544"},
+  {"0x1.35ceaeb2d28c1p+405", 122, "1.0000000000000000144059475872452738558311186224283126301371231493549892706912613162686325762572645608050543718329623353754e+122"},
+  {"0x1.83425a5f872f1p+408", 123, "999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376"},
+  {"0x1.83425a5f872f2p+408", 123, "1.00000000000000012449388115476870641315052159692848578837224262943248321009552560684093062850453534816594492111899528999731e+123"},
+  {"0x1.e412f0f768fadp+411", 124, "9999999999999999483531874467312143214394768377282087351960514613084929070487027419252537449089020883885200422613425626021888"},
+  {"0x1.e412f0f768faep+411", 124, "1.000000000000000065780316585422875715913506677195060103980178906724486442413251318535705000639324261573469961499777714198938e+124"},
+  {"0x1.2e8bd69aa19ccp+415", 125, "99999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005841365553228283904"},
+  {"0x1.2e8bd69aa19cdp+415", 125, "1.0000000000000001127511682408995402737031186129818006514938298848908838565590707491798855029314931308474499291951517748376371e+125"},
+  {"0x1.7a2ecc414a03fp+418", 126, "999999999999999924867761618992882042544670869834838461439225972225294199975793026603163493762817653751530058413655532282839040"},
+  {"0x1.7a2ecc414a040p+418", 126, "1.0000000000000000751744869165182086274714290643524082134829091023577659252424152046645411010977580354282659550388525263266775e+126"},
+  {"0x1.d8ba7f519c84fp+421", 127, "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772377386949310916067328"},
+  {"0x1.d8ba7f519c850p+421", 127, "1.000000000000000075174486916518208627471429064352408213482909102357765925242415204664541101097758035428265955038852526326677504e+127"},
+  {"0x1.27748f9301d31p+425", 128, "99999999999999988278187853568579059876517857536991893086699469578820211690113881674597776370903434688204400735860037395056427008"},
+  {"0x1.27748f9301d32p+425", 128, "1.000000000000000075174486916518208627471429064352408213482909102357765925242415204664541101097758035428265955038852526326677504e+128"},
+  {"0x1.7151b377c247ep+428", 129, "999999999999999998217443564185241415988928868759412500436543339729940401905904649497115766142268560009777175966751665376232210432"},
+  {"0x1.7151b377c247fp+428", 129, "1.00000000000000015213153026885117583895392925994540392652927486498559144857892575983196643605324751084675473411095338727712279757e+129"},
+  {"0x1.cda62055b2d9dp+431", 130, "9999999999999999366518088823188676468029287122850159299994507296276799832366962053631754981778769796749861527090709766158759755776"},
+  {"0x1.cda62055b2d9ep+431", 130, "1.000000000000000059783078246051615185174929025233809070873635949832200820575113093631056034106660140344568199224432354136588445286e+130"},
+  {"0x1.2087d4358fc82p+435", 131, "99999999999999991202555500957231813912852864969525730182461368558677581576901282770959939099212034754106974340599870111173348163584"},
+  {"0x1.2087d4358fc83p+435", 131, "1.0000000000000001090355859915447142005237291504133263272233100379140091555104798489382082484781734046124010178305769051448734331699e+131"},
+  {"0x1.68a9c942f3ba3p+438", 132, "999999999999999990829567402361276563686608849982484911984092226517669151665599636201042933986541570369602253175829982724989462249472"},
+  {"0x1.68a9c942f3ba4p+438", 132, "1.00000000000000014843759218793919341280276925055694013230304930837945582345877325318393001997538401602666727271549254595150142347674e+132"},
+  {"0x1.c2d43b93b0a8bp+441", 133, "9999999999999998962647525310145264542169126096378117797927179774005971485896954660113106823932361029753632414520324447890822855131136"},
+  {"0x1.c2d43b93b0a8cp+441", 133, "1.000000000000000022351172359476859933509840930097375956047883642890026486024234359597620351184310059501015257083762495370291854494925e+133"},
+  {"0x1.19c4a53c4e697p+445", 134, "99999999999999992148203649670699315007549827372972461504375111049848301607660324472857261615145089428049364457837845490532419930947584"},
+  {"0x1.19c4a53c4e698p+445", 134, "1.0000000000000001232203082222467267169441835864650272970520161752815699559718654744666680862171692247215368695891465358352595096803738e+134"},
+  {"0x1.6035ce8b6203dp+448", 135, "999999999999999961829690841814939863449235336276785151445404123455100404055655690676191710164594560368702289580532071091311261383655424"},
+  {"0x1.6035ce8b6203ep+448", 135, "1.00000000000000012322030822224672671694418358646502729705201617528156995597186547446666808621716922472153686958914653583525950968037376e+135"},
+  {"0x1.b843422e3a84cp+451", 136, "9999999999999999295515673657285824927502456862391367223240817130898064936724137339180964349540796274981353735788091781425216117243117568"},
+  {"0x1.b843422e3a84dp+451", 136, "1.000000000000000058664061270074011975546204286389730438809371354550982135205381560950477535796139358980403037585700749937680210361686426e+136"},
+  {"0x1.132a095ce492fp+455", 137, "99999999999999982626157224225223890651347880611866174913584999992086598044603947229219155428043184231232124237329592070639473281441202176"},
+  {"0x1.132a095ce4930p+455", 137, "1.0000000000000000328415624892049260789870125663596116955123134262587470068987879955440013156277274126839495047843224355786484906342114918e+137"},
+  {"0x1.57f48bb41db7bp+458", 138, "999999999999999867577570291642776341008185558166851738411142685188442185736589176942553506549890956386646894855501223680845484378371915776"},
+  {"0x1.57f48bb41db7cp+458", 138, "1.00000000000000003284156248920492607898701256635961169551231342625874700689878799554400131562772741268394950478432243557864849063421149184e+138"},
+  {"0x1.adf1aea12525ap+461", 139, "9999999999999999006303687311552062886039509598054037298313768334025031499690289406628430683654582476461074168412654660604060856295398309888"},
+  {"0x1.adf1aea12525bp+461", 139, "1.00000000000000003284156248920492607898701256635961169551231342625874700689878799554400131562772741268394950478432243557864849063421149184e+139"},
+  {"0x1.0cb70d24b7378p+465", 140, "99999999999999984774589122793531837245072631718372054355900219626000560719712531871037976946055058163097058166404267825310912362767116664832"},
+  {"0x1.0cb70d24b7379p+465", 140, "1.0000000000000000592838012408148700370636248876704532886485007448299957782847398065202329650801812456915179223729338294822969716351458240102e+140"},
+  {"0x1.4fe4d06de5056p+468", 141, "999999999999999847745891227935318372450726317183720543559002196260005607197125318710379769460550581630970581664042678253109123627671166648320"},
+  {"0x1.4fe4d06de5057p+468", 141, "1.00000000000000001697621923823895970414104517357310673963060103511599774406721690895826232595625511287940845423115559923645940203365089253786e+141"},
+  {"0x1.a3de04895e46cp+471", 142, "9999999999999999154380224320567749051268538597394750219876417318024024619451619548095327920588323941303457306908878466464492349900630570041344"},
+  {"0x1.a3de04895e46dp+471", 142, "1.000000000000000050822284840299687970479108944850983978844920802887196171441235227007838837255396019129096028744578183433129457714846837715763e+142"},
+  {"0x1.066ac2d5daec3p+475", 143, "99999999999999980713061250546244445284504979165026785650181847493456749434830333705088795590158149413134549224793557721710505681023603243483136"},
+  {"0x1.066ac2d5daec4p+475", 143, "1.0000000000000000237454323586511053574086579278286821874734649886702374295420205725681776282160832941293459691338401160757934131698900815734374e+143"},
+  {"0x1.4805738b51a74p+478", 144, "999999999999999850453576476100176633757771418885950722696147777681701481387046784154345890364481854130945587625116484988842728082166842262552576"},
+  {"0x1.4805738b51a75p+478", 144, "1.00000000000000002374543235865110535740865792782868218747346498867023742954202057256817762821608329412934596913384011607579341316989008157343744e+144"},
+  {"0x1.9a06d06e26112p+481", 145, "9999999999999999890870611821409196126784806260401358945180015464725302399110258148854112806457630061296658928320953898584032761523454337112604672"},
+  {"0x1.9a06d06e26113p+481", 145, "1.000000000000000127720545888181662591599189833194321066339855315263358998435004845616476670927044158128386198039074294727963824222524025159968358e+145"},
+  {"0x1.00444244d7cabp+485", 146, "99999999999999993363366729972462242111019694317846182578926003895619873650143420259298512453325054533017777074930382791057905692427399713177731072"},
+  {"0x1.00444244d7cacp+485", 146, "1.0000000000000001554472428293898111873833316746251581007042260690215247501398006517626897489833003885281302590804700757018759338365597434497099366e+146"},
+  {"0x1.405552d60dbd6p+488", 147, "999999999999999977996382405657660174364823889467801080772253244969263939229107492426926049423260513969768268415537077468838432306731146395363835904"},
+  {"0x1.405552d60dbd7p+488", 147, "1.00000000000000015544724282938981118738333167462515810070422606902152475013980065176268974898330038852813025908047007570187593383655974344970993664e+147"},
+  {"0x1.906aa78b912cbp+491", 148, "9999999999999999070160382361647997691574207754048582727994641153483596148648302286926205695992445641464234721495638781756234316947997075736253956096"},
+  {"0x1.906aa78b912ccp+491", 148, "1.000000000000000048976726575150520579572227003530743888745042374590168263593384756161231529247276463793113064681510276762053432918662585217102276198e+148"},
+  {"0x1.f485516e7577ep+494", 149, "99999999999999993540817590396194393124038202103003539598857976719672134461054113418634276152885094407576139065595315789290943193957228310232077172736"},
+  {"0x1.f485516e7577fp+494", 149, "1.0000000000000000489767265751505205795722270035307438887450423745901682635933847561612315292472764637931130646815102767620534329186625852171022761984e+149"},
+  {"0x1.38d352e5096afp+498", 150, "999999999999999980835596172437374590573120014030318793091164810154100112203678582976298268616221151962702060266176005440567032331208403948233373515776"},
+  {"0x1.38d352e5096b0p+498", 150, "1.00000000000000016254527724633909722790407198603145238150150498198361518257622837813612029696570198351046473870706739563119743389775288733188378066944e+150"},
+  {"0x1.8708279e4bc5ap+501", 151, "9999999999999998718097875280963410081745488308296386400449607070563910699801487058804050516065326530340444532016411713261887913912817139180431292235776"},
+  {"0x1.8708279e4bc5bp+501", 151, "1.000000000000000017177532387217719118039310408430545510773232844520003126278188542008262674286117318272254595954354283478693112644517300624963454946509e+151"},
+  {"0x1.e8ca3185deb71p+504", 152, "99999999999999992995688547174489225212045346187000138833626956204183589249936464033154810067836651912932851030272641618719051989257594860081125951275008"},
+  {"0x1.e8ca3185deb72p+504", 152, "1.000000000000000046251081359041994740012262723950726884918887272012725537537796509233834198822034251319896624504896905909193976895164417966347520091095e+152"},
+  {"0x1.317e5ef3ab327p+508", 153, "999999999999999999733403004123153744855539019118436686285840188024369679522423761672919759564567158443669378824028710020392594094129030220133015859757056"},
+  {"0x1.317e5ef3ab328p+508", 153, "1.00000000000000018580411642379851772548243383844759748081802852397779311158391475191657751659443552994857836154750149357559812529827058120499103278510899e+153"},
+  {"0x1.7dddf6b095ff0p+511", 154, "9999999999999998880909749523179353564794021275209402095665271864523156202855291675267251053466461355407239891899450398872692753716440996292182057045458944"},
+  {"0x1.7dddf6b095ff1p+511", 154, "1.000000000000000036947545688058226540980917982984268845192277855215054365934721959721651310970540832744651175368723266731433700334957340417104619244827443e+154"},
+  {"0x1.dd55745cbb7ecp+514", 155, "99999999999999988809097495231793535647940212752094020956652718645231562028552916752672510534664613554072398918994503988726927537164409962921820570454589440"},
+  {"0x1.dd55745cbb7edp+514", 155, "1.0000000000000000071762315409101683040806148118916031180671277214625066168048834012826660698457618933038657381329676213626008153422946922595273365367711334e+155"},
+  {"0x1.2a5568b9f52f4p+518", 156, "999999999999999983359180223191721714560372275017470536367007614460468417501012554531477876945938741751237388344363105067534507348164573733465510370326085632"},
+  {"0x1.2a5568b9f52f5p+518", 156, "1.0000000000000001738955907649392944307223125700105311899679684704767740119319793285409834201445239541722641866531992354280649713012055219419601197018864681e+156"},
+  {"0x1.74eac2e8727b1p+521", 157, "9999999999999999833591802231917217145603722750174705363670076144604684175010125545314778769459387417512373883443631050675345073481645737334655103703260856320"},
+  {"0x1.74eac2e8727b2p+521", 157, "1.000000000000000135788308656589779887489924511011919059247776299273512893045785973739082311504806911688058826991432009355958878510597332300261197835574391603e+157"},
+  {"0x1.d22573a28f19dp+524", 158, "99999999999999995287335453651211007997446182781858083179085387749785952239205787068995699003416510776387310061494932420984963311567802202010637287727642443776"},
+  {"0x1.d22573a28f19ep+524", 158, "1.0000000000000000748166572832305566183181036166141396500954688253482951028278766060560405376812596437133302515326044476405891300456242288735429228494750692147e+158"},
+  {"0x1.2357684599702p+528", 159, "999999999999999928484693987168420772305733470059469068129930887927772406304894123616740280504746200573981670431418299523701733729688780649419062882836695482368"},
+  {"0x1.2357684599703p+528", 159, "1.0000000000000001235939783819179352336555603321323631774173148044884693350022041002024739567400974580931131118996664970128849288176027116149175428383545271255e+159"},
+  {"0x1.6c2d4256ffcc2p+531", 160, "9999999999999998504409802292686149877658027252303114244149773213034936348259701329824468100106056975663290938441190205280284556945232082632196709006295628251136"},
+  {"0x1.6c2d4256ffcc3p+531", 160, "1.000000000000000006528407745068226556845664214888626711844884454552051177783818114251033750998886703581634247018717578519375011764854353035618454865043828139622e+160"},
+  {"0x1.c73892ecbfbf3p+534", 161, "99999999999999991287595123558845961539774732109363753938694017460291665200910932548988158640591809997245115511395844372456707812265566617217918448639526895091712"},
+  {"0x1.c73892ecbfbf4p+534", 161, "1.0000000000000000377458932482281488706616365128202897693308658812017626863753877105047511391965429047846952776536372901176443229789205819900982116579266812025242e+161"},
+  {"0x1.1c835bd3f7d78p+538", 162, "999999999999999937849939638116397466450525159438967985375725315922685858882365002492855496964043060934899979621894213003182527093908649335762989920701551401238528"},
+  {"0x1.1c835bd3f7d79p+538", 162, "1.00000000000000013764184685833990027487274786620161155328600644648083951386841041851664678142904274863449057568538036723210611886393251464443343339515181100380979e+162"},
+  {"0x1.63a432c8f5cd6p+541", 163, "9999999999999999378499396381163974664505251594389679853757253159226858588823650024928554969640430609348999796218942130031825270939086493357629899207015514012385280"},
+  {"0x1.63a432c8f5cd7p+541", 163, "1.000000000000000097683465414295199713188303324849082839703950220369208782871201335311888524536042811094572456472683136386321400509927741582699344700261759083295539e+163"},
+  {"0x1.bc8d3f7b3340bp+544", 164, "99999999999999987391652932764487656775541389327492204364443535414407668928683046936524228593524316087103098888157864364992697772750101243698844800887746832841572352"},
+  {"0x1.bc8d3f7b3340cp+544", 164, "1.0000000000000000017833499485879183651456364256030139271070152777012950284778995356204687079928429609987689703622097823564380764603162862345375318325256344740613325e+164"},
+  {"0x1.15d847ad00087p+548", 165, "999999999999999899489893451833484927233458399740540420336951338855520357125044282616287570346763120896578585177704871391229197474064067196498264773607101557544845312"},
+  {"0x1.15d847ad00088p+548", 165, "1.00000000000000010407680644534235180305781445146548743387707921654706969983075478862464984563892280110095935554671469332164695544656850527257679889144416739057781965e+165"},
+  {"0x1.5b4e5998400a9p+551", 166, "9999999999999999404072760505352583023983296100855298230449769143938302256661863838179600254051950569374547392515068357773127490685649548117139715971745147241514401792"},
+  {"0x1.5b4e5998400aap+551", 166, "1.000000000000000104076806445342351803057814451465487433877079216547069699830754788624649845638922801100959355546714693321646955446568505272576798891444167390577819648e+166"},
+  {"0x1.b221effe500d3p+554", 167, "99999999999999990767336997157383960226643264180953830087855645396318233083327270285662206135844950810475381599246526426844590779296424471954140613832058419086616428544"},
+  {"0x1.b221effe500d4p+554", 167, "1.0000000000000000386089942874195144027940205149135043895442382956857739101649274267019739175454317034355575090286315503039132728953670850882316679737363063240072678605e+167"},
+  {"0x1.0f5535fef2084p+558", 168, "999999999999999933860494834742974562371950216430331518611692822307700646699603647625692432595845947170914554599698521475539380813444812793279458505403728617494385000448"},
+  {"0x1.0f5535fef2085p+558", 168, "1.00000000000000014335749374009605424321609081339667726047678376906384717363025120577825540249501745970020046345756457913228716497728935738318387744206888403052015072051e+168"},
+  {"0x1.532a837eae8a5p+561", 169, "9999999999999999338604948347429745623719502164303315186116928223077006466996036476256924325958459471709145545996985214755393808134448127932794585054037286174943850004480"},
+  {"0x1.532a837eae8a6p+561", 169, "1.000000000000000101458093959025438307047262694003408112103765579712617868244121694147742808515183157194343281685991367600937608144520448465202993654735852947914997576499e+169"},
+  {"0x1.a7f5245e5a2cep+564", 170, "99999999999999990034097500988648181343688772091571619991327827082671720239070003832128235741197850516622880918243995225045973534722968565889475147553730375141026248523776"},
+  {"0x1.a7f5245e5a2cfp+564", 170, "1.0000000000000000344190543093124528091771377029741774747069364767506509796263144755389226581474482731849717908514742291507783172120901941964335795950030032157467525460787e+170"},
+  {"0x1.08f936baf85c1p+568", 171, "999999999999999953972206729656870211732987713739100709830741553196290713284945813208338477706166412373726001850053663010587168093173889073910282723323583537144858509574144"},
+  {"0x1.08f936baf85c2p+568", 171, "1.00000000000000016849713360873842380491738768503263874950059468267458475686192891275656295888291804120371477252050850605109689907695070273397240771446870268008324260691968e+171"},
+  {"0x1.4b378469b6731p+571", 172, "9999999999999999110672213538405594930961077194803931018967709273006319045695491932986935814708160866077282477159626944024852218964185263418978577250945597085571816901050368"},
+  {"0x1.4b378469b6732p+571", 172, "1.000000000000000082687162857105802367643627696515223533632653430883267139431135672937273166412217389671719264252326568834893006683439977269947557718010655022907888967981466e+172"},
+  {"0x1.9e056584240fdp+574", 173, "99999999999999987674323305318751091818660372407342701554959442658410485759723189737097766448253582599493004440868991951600366493901423615628791772651134064568704023452975104"},
+  {"0x1.9e056584240fep+574", 173, "1.0000000000000000140391862557997052178246197057012913609383004294502130454865010810818413324356568684461228576377810190619298927686313968987276777208442168971676060568308941e+173"},
+  {"0x1.02c35f729689ep+578", 174, "999999999999999849284042412665072058259000527747854146471853226010883220019378060628804930891911617504691481762871699606818419373090804007799965727644765395390927070069522432"},
+  {"0x1.02c35f729689fp+578", 174, "1.0000000000000000689575675368445829376798260983524370990937828305966563206422087545661867996169052854265999829294174588803003839004782611957035817185773673977598323857513513e+174"},
+  {"0x1.4374374f3c2c6p+581", 175, "9999999999999999371534524623368764100273307559896873275206250678451924602685103382037576783819090846734548822294900033162112051840457868829614121240178061963384891963422539776"},
+  {"0x1.4374374f3c2c7p+581", 175, "1.000000000000000112892272561680485113563991212473353689618168751513810940766774893353663173361904019010981683162726610734996776805955752633284304916763887798233613448887717069e+175"},
+  {"0x1.945145230b377p+584", 176, "99999999999999986685792442259943292861266657339622078268160759437774506806920451614379548038991111093844416185619536034869697653528180058283225500691937355558043949532406874112"},
+  {"0x1.945145230b378p+584", 176, "1.0000000000000000074489805020743198914419949385831538723596425413126398524678161602637198763739070584084656026027846462837254338328097731830905692411162388370965388973604392141e+176"},
+  {"0x1.f965966bce055p+587", 177, "999999999999999894976135638494410321178532246433607400617214583764724024948926844967780359586710300432448450005513217535702667994787395102883917853758746611883659375731342835712"},
+  {"0x1.f965966bce056p+587", 177, "1.00000000000000000744898050207431989144199493858315387235964254131263985246781616026371987637390705840846560260278464628372543383280977318309056924111623883709653889736043921408e+177"},
+  {"0x1.3bdf7e0360c35p+591", 178, "9999999999999998724815666657784284071258397080036981062687289922551408594451489819085924562292709488372450194860589317860981148271829194868425875762872481668410834714055235600384"},
+  {"0x1.3bdf7e0360c36p+591", 178, "1.000000000000000052438118447506283719547380015442972461056613724331806183475371886382095683088785761598872463641693217782934540168018724415173229796059235727181690706012077765427e+178"},
+  {"0x1.8ad75d8438f43p+594", 179, "99999999999999998045549773481514159457876389246726271914145983150114005386328272459269439234497983649422148597943950338419997003168440244384097290815044070304544781216945608327168"},
+  {"0x1.8ad75d8438f44p+594", 179, "1.0000000000000001244207391601974258445159961384186822029717676171624723130874610481714969738325916867035234413039469321816691103043530463865054866839680307513179335998546994475827e+179"},
+  {"0x1.ed8d34e547313p+597", 180, "999999999999999894076352879585771044616424544896411028843275160104340698328775730445412843452412726368640312784735046105718485868083216078242264642659886674081956339558310064685056"},
+  {"0x1.ed8d34e547314p+597", 180, "1.00000000000000000924854601989159844456621034165754661590752138863340650570811838930845490864250220653608187704434098914369379808621813123237387566331395871269994496970650475613389e+180"},
+  {"0x1.3478410f4c7ecp+601", 181, "9999999999999999171107915076469365246063817042486381462561244058101538598046442622180212564904306224021286256366562347133135483117101991090685868467907010818055540655879490029748224"},
+  {"0x1.3478410f4c7edp+601", 181, "1.000000000000000101386300532136260364526038979066455085558918371456659151611592516398888560794573790670035128452025743574074047860726063355679164479837216343594335873825060509292954e+181"},
+  {"0x1.819651531f9e7p+604", 182, "99999999999999991711079150764693652460638170424863814625612440581015385980464426221802125649043062240212862563665623471331354831171019910906858684679070108180555406558794900297482240"},
+  {"0x1.819651531f9e8p+604", 182, "1.0000000000000000645311987272383955965421075241028916976983595783273580932502028655627150999337451570164538278889518418019219479509228905063570489532279132912365795121776382080293274e+182"},
+  {"0x1.e1fbe5a7e7861p+607", 183, "999999999999999946594872951565228338993526868219488856544571440313594706493755982886960025179093529324993666087115356131035228239552737388526279268078143523691759154905886843985723392"},
+  {"0x1.e1fbe5a7e7862p+607", 183, "1.00000000000000006453119872723839559654210752410289169769835957832735809325020286556271509993374515701645382788895184180192194795092289050635704895322791329123657951217763820802932736e+183"},
+  {"0x1.2d3d6f88f0b3cp+611", 184, "9999999999999998286585471758920610814449462123360860153907833022998313197373091002112049504244419016335335042852788704601485085281825842706955095829283737561469387976341354799421194240"},
+  {"0x1.2d3d6f88f0b3dp+611", 184, "1.000000000000000017356668416969128693522675261749530561236844323121852738547624112492413070031884505939869763168217247533567260066374829259224741079168005384218651369268937662411885773e+184"},
+  {"0x1.788ccb6b2ce0cp+614", 185, "99999999999999997961704416875371517110712945186684165206763211895744845478556111003617144611039598507860251139162957211888350975873638026151889477992007905860430885494197722591793250304"},
+  {"0x1.788ccb6b2ce0dp+614", 185, "1.0000000000000001305755411616153692607693126913975972887444809356150655898338131198611379417963500685236715184979802737776185109892901762523422799769117843610616789122498189718937455821e+185"},
+  {"0x1.d6affe45f818fp+617", 186, "999999999999999979617044168753715171107129451866841652067632118957448454785561110036171446110395985078602511391629572118883509758736380261518894779920079058604308854941977225917932503040"},
+  {"0x1.d6affe45f8190p+617", 186, "1.00000000000000010038384176304303844283687604349144616140911117228354216282416271789614464265915925183465771707671013344587151074317941705417760293751344330057020490078825062269858296627e+186"},
+  {"0x1.262dfeebbb0f9p+621", 187, "9999999999999999071569656121801212080692814968920789464627446869617922299624001453201875281811380250249693879805812353226907091680705581859236698853640605134247712274342131878495422251008"},
+  {"0x1.262dfeebbb0fap+621", 187, "1.000000000000000100383841763043038442836876043491446161409111172283542162824162717896144642659159251834657717076710133445871510743179417054177602937513443300570204900788250622698582966272e+187"},
+  {"0x1.6fb97ea6a9d37p+624", 188, "99999999999999986851159038200753776111576258757220550347347138989744224339004763080499610528553377966303172216135545569805454885304878641227288327493418395599568449276340570087973407686656"},
+  {"0x1.6fb97ea6a9d38p+624", 188, "1.0000000000000000230930913026978715489298382248516992754305645781548421896794576888657617968679507611107823854382585741965991901131358735068760297166536901857120314314466356487589666698035e+188"},
+  {"0x1.cba7de5054485p+627", 189, "999999999999999899427890566145604518678577715028104257864890027548922232647929642417149243602017175952581854816736079397763477105066203831193512563278085201938953880500051690455580595453952"},
+  {"0x1.cba7de5054486p+627", 189, "1.00000000000000002309309130269787154892983822485169927543056457815484218967945768886576179686795076111078238543825857419659919011313587350687602971665369018571203143144663564875896666980352e+189"},
+  {"0x1.1f48eaf234ad3p+631", 190, "9999999999999998746948504188351511126283256130633852543517551174277382412416240331274267329488304589209417486924315804379963345034522698960570091326029642051843383703107348987949033805840384"},
+  {"0x1.1f48eaf234ad4p+631", 190, "1.000000000000000072559171597318778361030342428781137282456834398397210172492068907445206818174324195174062597686867572116133475316363741377149036578003932179221262451825269232080321099543347e+190"},
+  {"0x1.671b25aec1d88p+634", 191, "99999999999999991426771465453187656230872897620693565997277097362163262749171300799098274999392920617156591849131877877362376266603456419227541462168315779999172318661364176545198692437590016"},
+  {"0x1.671b25aec1d89p+634", 191, "1.0000000000000000725591715973187783610303424287811372824568343983972101724920689074452068181743241951740625976868675721161334753163637413771490365780039321792212624518252692320803210995433472e+191"},
+  {"0x1.c0e1ef1a724eap+637", 192, "999999999999999914267714654531876562308728976206935659972770973621632627491713007990982749993929206171565918491318778773623762666034564192275414621683157799991723186613641765451986924375900160"},
+  {"0x1.c0e1ef1a724ebp+637", 192, "1.00000000000000004090088020876139800128601973826629695796002171344209466349199772755436200453824519737356326184775781344763153278629790594017431218673977730337535459878294373875465426450985779e+192"},
+  {"0x1.188d357087712p+641", 193, "9999999999999998636144484328400679867178126713831911407778706776934478130915991201656310481762028096907669811487431649040206546179292274931158555956605099986382706217459209761309199883223171072"},
+  {"0x1.188d357087713p+641", 193, "1.000000000000000066227513319607302289081477890678169217557471861406187070692054671467037855447108395613962730519045620382433086810350574289754091699751101204052080881216804133415187732536649318e+193"},
+  {"0x1.5eb082cca94d7p+644", 194, "99999999999999994465967438754696170766327875910118237148971115117854351613178134068619377108456504406004528089686414709538562749489776621177115003729674648080379472553427423904462708600804999168"},
+  {"0x1.5eb082cca94d8p+644", 194, "1.0000000000000001067501262969607491495542109345371648329133920981487349222121457817273192169012895127986018803931061114781155732488348436490817389205692194451348429331109807648720412813795157606e+194"},
+  {"0x1.b65ca37fd3a0dp+647", 195, "999999999999999977077764769429719196041465194188378863774447340572581797347854228894418860247909937807756600796112539971931616645685181699233267813951241073670004367049615544210109925082343145472"},
+  {"0x1.b65ca37fd3a0ep+647", 195, "1.00000000000000010675012629696074914955421093453716483291339209814873492221214578172731921690128951279860188039310611147811557324883484364908173892056921944513484293311098076487204128137951576064e+195"},
+  {"0x1.11f9e62fe4448p+651", 196, "9999999999999999511432924639235132053389160461186216699466583890573511723749959183278387889172340228095875448767138256706948253250552493092635735926276453993770366538373425000777236538229086224384"},
+  {"0x1.11f9e62fe4449p+651", 196, "1.000000000000000158619070907973161130959309230676679220568970001179196172157862402860479359562641342794939992231903540080589155890094708429021127363216410793720778359535526853136813823898384806707e+196"},
+  {"0x1.56785fbbdd55ap+654", 197, "99999999999999995114329246392351320533891604611862166994665838905735117237499591832783878891723402280958754487671382567069482532505524930926357359262764539937703665383734250007772365382290862243840"},
+  {"0x1.56785fbbdd55bp+654", 197, "1.0000000000000001171239152191632315458352305937650677104445076787548271722012891059539512454335598787978695027608655971986102897770868166050696166090986577148520300183958899825249957898832895698534e+197"},
+  {"0x1.ac1677aad4ab0p+657", 198, "999999999999999884751043361827625869140390227060043253747518673178360772444478643277393806310703680414274761723053117059528639544242622390941156386039240473187039308013923507098814799398756243472384"},
+  {"0x1.ac1677aad4ab1p+657", 198, "1.00000000000000001753554156601940054153744186517720008614579810493634157230551319337828377152376436520490032803037453428186101110586787622758599079921605032556703399966076149305663250824706100140442e+198"},
+  {"0x1.0b8e0acac4eaep+661", 199, "9999999999999998847510433618276258691403902270600432537475186731783607724444786432773938063107036804142747617230531170595286395442426223909411563860392404731870393080139235070988147993987562434723840"},
+  {"0x1.0b8e0acac4eafp+661", 199, "1.000000000000000097206240488534465344975672848047494185584765763991130052222133923438817750651600776079275667814767384615260434042843028529572891447122136236995030814648864284631323133556043856163635e+199"},
+  {"0x1.4e718d7d7625ap+664", 200, "99999999999999996973312221251036165947450327545502362648241750950346848435554075534196338404706251868027512415973882408182135734368278484639385041047239877871023591066789981811181813306167128854888448"},
+  {"0x1.4e718d7d7625bp+664", 200, "1.0000000000000001396972799138758332401427293722449843719522151821536839081776649794711025395197801952122758490331102381264067929425631097572992384593387153897566291159758524401378248003875013787018854e+200"},
+  {"0x1.a20df0dcd3af0p+667", 201, "999999999999999901747459131964173027207212836739039328294498440443382314826691065690307721857975448067474834210390258463987183104130654882031695190925872134291678628544718769301415466131339252487684096"},
+  {"0x1.a20df0dcd3af1p+667", 201, "1.00000000000000003771878529305655029174179371417100792467033657856355465388439044499361904623614958929307541410908738969965553158323491481075600563001892542312879319279108086692222079999200332461008486e+201"},
+  {"0x1.0548b68a044d6p+671", 202, "9999999999999999017474591319641730272072128367390393282944984404433823148266910656903077218579754480674748342103902584639871831041306548820316951909258721342916786285447187693014154661313392524876840960"},
+  {"0x1.0548b68a044d7p+671", 202, "1.000000000000000119301580989711976650462542240630189082495839461435658057319010072575605840863054074028435762048305668441056540670697470767990591893474757396431061931338898125494704000308401767883525325e+202"},
+  {"0x1.469ae42c8560cp+674", 203, "99999999999999998876910787506329447650934459829549922997503484884029261182361866844442696946000689845185920534555642245481492613075738123641525387194542623914743194966239051177873087980216425864602058752"},
+  {"0x1.469ae42c8560dp+674", 203, "1.0000000000000001628124053612615373751136081214084190333361076656341132058174738739526654646640697992206279476158887504364704121840108339451823712339845344488589385918977339967333617071438142709626935706e+203"},
+  {"0x1.98419d37a6b8fp+677", 204, "999999999999999988769107875063294476509344598295499229975034848840292611823618668444426969460006898451859205345556422454814926130757381236415253871945426239147431949662390511778730879802164258646020587520"},
+  {"0x1.98419d37a6b90p+677", 204, "1.00000000000000012800374586402188879539275541678583507266389310227534908701870283285101776562325721906687419916182228484013931497336014340342894776157671280691663726345066529974243554167548426849935897395e+204"},
+  {"0x1.fe52048590672p+680", 205, "9999999999999999052283250816881378851792981072012977243617198967792587267065681698004724917620567060828502090557969050236202928251957239362070375381666542984859087613894256390005080826781722527340175556608"},
+  {"0x1.fe52048590673p+680", 205, "1.000000000000000016616035472855013340286026761993566398512806499527303906862635501325745128692656962574862204108809594931879803899277933669817992649871683552701273012420045469371471812176828260616688264806e+205"},
+  {"0x1.3ef342d37a407p+684", 206, "99999999999999986067324092522138770313660664528439025470128525568004065464414123719036343698981660348604541103459182906031648839556284004276265549348464259679976306097717770685212259087870984958094927200256"},
+  {"0x1.3ef342d37a408p+684", 206, "1.0000000000000000388935775510883884313073724929520201333430238200769129428938489676307996560787770138732646031194121329135317061140943756165401836722126894035443458626261694354456645580765594621932224066355e+206"},
+  {"0x1.8eb0138858d09p+687", 207, "999999999999999896317308250394787848770759814817916230429632968559415112294082783278450680807608685563489249451555889830959531939269147157518161129230251958148679621306976052570830984318279772103403898929152"},
+  {"0x1.8eb0138858d0ap+687", 207, "1.00000000000000003889357755108838843130737249295202013334302382007691294289384896763079965607877701387326460311941213291353170611409437561654018367221268940354434586262616943544566455807655946219322240663552e+207"},
+  {"0x1.f25c186a6f04cp+690", 208, "9999999999999999818630698308109481982927274216983785721776674794699138106539424938898600659703096825493544616522696356805028364441642842329313746550197144253860793660984920822957311285732475861572950035529728"},
+  {"0x1.f25c186a6f04dp+690", 208, "1.000000000000000095924085271365828664322017564205661694508380160683912075133755441371739246187244345197174744586554630146560575784024467000148992689405664381702612359153846788595597987579871338229149809718067e+208"},
+  {"0x1.37798f428562fp+694", 209, "99999999999999989061425747836704382546929530769255207431309733449871519907009213590435672179676195243109823530484164010765664497227613801915728022751095446033285297165420831725583764136794858449981115862089728"},
+  {"0x1.37798f4285630p+694", 209, "1.0000000000000000731118821832548525711161595357042050700422376244411124222377928518753634101438574126676106879996976312533490279160524304467054690825284743904393057605427758473356246157785465878147788484850483e+209"},
+  {"0x1.8557f31326bbbp+697", 210, "999999999999999927113782419344605574598668153294882673458925392487194643703632279098558059466181044478400725843812838336795121561031396504666917998514458446354143529431921823271795036250068185162804696593727488"},
+  {"0x1.8557f31326bbcp+697", 210, "1.00000000000000007311188218325485257111615953570420507004223762444111242223779285187536341014385741266761068799969763125334902791605243044670546908252847439043930576054277584733562461577854658781477884848504832e+210"},
+  {"0x1.e6adefd7f06aap+700", 211, "9999999999999999563134023721266549739021664297767471527755878388779781994104643936539191296017163181162427182749897969201059028320356032930746282153172616351711759756540926280845609521557638656931995269719916544"},
+  {"0x1.e6adefd7f06abp+700", 211, "1.00000000000000007311188218325485257111615953570420507004223762444111242223779285187536341014385741266761068799969763125334902791605243044670546908252847439043930576054277584733562461577854658781477884848504832e+211"},
+  {"0x1.302cb5e6f642ap+704", 212, "99999999999999990959401044767537593501656918740576398586892792465272451027953301036534141738485988029569553038510666318680865279842887243162229186843277653306392406169861934038413548670665077684456779836676898816"},
+  {"0x1.302cb5e6f642bp+704", 212, "1.0000000000000000964715781454804920905589581568896966534955675815537392668032585435196522662522856315778842819446391981199976529328557958774316372559707169414929317175205124911858373485031031322390947127876596531e+212"},
+  {"0x1.7c37e360b3d35p+707", 213, "999999999999999984345037526797422397233524775199337052919583787413130412889023223627065756931830180808571031008919677160084252852199641809946030023447952696435527124027376600704816231425231719002378564135125254144"},
+  {"0x1.7c37e360b3d36p+707", 213, "1.00000000000000013384709168504151532166743595078648318702089551293394221810800365015051443602577078183432203225654570510663545295974118056659350633347830502317873324868489112134617772086239360331800009567183778611e+213"},
+  {"0x1.db45dc38e0c82p+710", 214, "9999999999999999544446266951486038123467425400819078260993214423089680518452271383223760211130420606034208307593944715707740128306913340586165347614418822310868858990958736965765439335377993421392542578277827477504"},
+  {"0x1.db45dc38e0c83p+710", 214, "1.000000000000000074046270021743878151893871480551624733380370822725617496020411479541134964388194541424021631757495293928014972916724565063934515809466164092481450798821885313089633125087528849591751483057152773325e+214"},
+  {"0x1.290ba9a38c7d1p+714", 215, "99999999999999990660396936451049407652789096389402106318690169014230827417515340183487244380298106827518051036015414262787762879627804165648934234223216948652905993920546904997130825691790753915825536773603473752064"},
+  {"0x1.290ba9a38c7d2p+714", 215, "1.0000000000000000979665986870629330198032972686455681148365806988089473848554483477848867530432250375881417919571154583994631649339312112649981120190710204647603637787670876363922509633974747510822509281030267784397e+215"},
+  {"0x1.734e940c6f9c5p+717", 216, "999999999999999868331443500000006287872809702943711652856965888408980452039094412644869581954932274412588254040761879473560521568747407734787588406864399290882799171293145332687119715621994096773456255662636329336832"},
+  {"0x1.734e940c6f9c6p+717", 216, "1.00000000000000002142154695804195744249313474674494929417670909534229174058333036940488102934712744986295727931833093209082895047886994342159460414833548007346784224294244020182387388080564786631265270395622996207206e+216"},
+  {"0x1.d022390f8b837p+720", 217, "9999999999999999601855055748251769806450047292244542376488118125689672251656359867008764503902493796828096692073033110439215789148209291468717978517470477604338250142827222541691722147321863584969741246387925089779712"},
+  {"0x1.d022390f8b838p+720", 217, "1.000000000000000082657588341258737904341264764265444350704606378115616256001024752108885608304005520043104889429358553137736322042918957696317410444923912386501859471602158149478575546879109374128331283273667415166157e+217"},
+  {"0x1.221563a9b7322p+724", 218, "99999999999999988670225591496504042642724870819986016981533507324097780666440272745607095564199569546663253707407016578763273303796211201720443029584092898479300433989106071698353021544403254911815982945786756526505984"},
+  {"0x1.221563a9b7323p+724", 218, "1.0000000000000000826575883412587379043412647642654443507046063781156162560010247521088856083040055200431048894293585531377363220429189576963174104449239123865018594716021581494785755468791093741283312832736674151661568e+218"},
+  {"0x1.6a9abc9424febp+727", 219, "999999999999999965084388885482519417592855130626093842171043595190833186399051537317196816706799625297221478016185520727674168639944850288849622355474122345476546392575499689981548348018063279122228410984187505225498624"},
+  {"0x1.6a9abc9424fecp+727", 219, "1.00000000000000012184865482651747739992406797547856118688246063909054394586834915703944853883640748495839935990041623060775703984391032683214000647474050906684363049794437763597758461316612473913036557403682738514637619e+219"},
+  {"0x1.c5416bb92e3e6p+730", 220, "9999999999999999964372420736895110140590976995965873111133270039707753382929110612616471611327211972294570543930316627036907428807379455975076991793273996897499632136492752791807556010476755711238558435947154812096741376"},
+  {"0x1.c5416bb92e3e7p+730", 220, "1.000000000000000121848654826517477399924067975478561186882460639090543945868349157039448538836407484958399359900416230607757039843910326832140006474740509066843630497944377635977584613166124739130365574036827385146376192e+220"},
+  {"0x1.1b48e353bce6fp+734", 221, "99999999999999984594354677029595135102113336853821866019036664182705300920238534632828550788829765195472628778417018121881118652493108811594893042483166843723756247249515245102456078650553656951604416706418119648563167232"},
+  {"0x1.1b48e353bce70p+734", 221, "1.0000000000000000466018071748206975684050858099493768614209804580186827813230862995727677122141957123210339765959854898653172616660068980913606220974926434405874301273673162218994872058950552383264597357715602427843549594e+221"},
+  {"0x1.621b1c28ac20bp+737", 222, "999999999999999886075198851200900594497923856820450300436489405065378963626525536977181948753477264027987825546533242948112401553146250111031268759363863437907536003469585205199546070383440303278127280805657005745376329728"},
+  {"0x1.621b1c28ac20cp+737", 222, "1.00000000000000004660180717482069756840508580994937686142098045801868278132308629957276771221419571232103397659598548986531726166600689809136062209749264344058743012736731622189948720589505523832645973577156024278435495936e+222"},
+  {"0x1.baa1e332d728ep+740", 223, "9999999999999999181805205159248599892793562474462356126333876156560397271658376894962991014456209536865970557564236923315533735757183797070971394269896194384435148282491314085395342974857632902877937717988376531531720556544"},
+  {"0x1.baa1e332d728fp+740", 223, "1.00000000000000004660180717482069756840508580994937686142098045801868278132308629957276771221419571232103397659598548986531726166600689809136062209749264344058743012736731622189948720589505523832645973577156024278435495936e+223"},
+  {"0x1.14a52dffc6799p+744", 224, "99999999999999996954903517948319502092964807244749211214842475260109694882873713352688654575305085714037182409224841134505892881183378706080253249519082903930108094789640533388351546084948006950326015738792668900564521713664"},
+  {"0x1.14a52dffc679ap+744", 224, "1.0000000000000001750230938337165351475308153724525181102085733003813258354803349096492363229827704709554708974355472873990811497562954164756241047679956674427313454264855010352594401143043471863651256997442828324155378630656e+224"},
+  {"0x1.59ce797fb817fp+747", 225, "999999999999999928454223448636526995609414612446486912536395043045051171498417578302416590307106934377352009423588636134254484622941461177838218040629861358615028052178586193608330530158506646130887048916655460323666687950848"},
+  {"0x1.59ce797fb8180p+747", 225, "1.00000000000000009283347037202319909689034845245050771098451388126923428081969579920029641209088262542943126809822773697747226137851076470969547585887373208135923963504986275470907025292240033962037948280174037505158080469402e+225"},
+  {"0x1.b04217dfa61dfp+750", 226, "9999999999999999613300728333138614158656013804472910722260188106898877933626732224819925546638620725877678611585164563028980399740553218842096696042786355031638703687528415058284784747112853848287855356936724432692495112994816"},
+  {"0x1.b04217dfa61e0p+750", 226, "1.000000000000000092833470372023199096890348452450507710984513881269234280819695799200296412090882625429431268098227736977472261378510764709695475858873732081359239635049862754709070252922400339620379482801740375051580804694016e+226"},
+  {"0x1.0e294eebc7d2bp+754", 227, "99999999999999988242803431008825880725075313724536108897092176834227990088845967645101024020764974088276981699468968789815350713138205618891818585152157755624664880897462875650012340778461641195382916742883168419985073526276096"},
+  {"0x1.0e294eebc7d2cp+754", 227, "1.000000000000000092833470372023199096890348452450507710984513881269234280819695799200296412090882625429431268098227736977472261378510764709695475858873732081359239635049862754709070252922400339620379482801740375051580804694016e+227"},
+  {"0x1.51b3a2a6b9c76p+757", 228, "999999999999999924509121522475246865178672200286390413373640190927670776874706901000867474584296317792102107215397297714017257980807797893073643852992008461269166974189675556141912776812173197487139230503413422370196749149011968"},
+  {"0x1.51b3a2a6b9c77p+757", 228, "1.000000000000000092833470372023199096890348452450507710984513881269234280819695799200296412090882625429431268098227736977472261378510764709695475858873732081359239635049862754709070252922400339620379482801740375051580804694016e+228"},
+  {"0x1.a6208b5068394p+760", 229, "9999999999999999918388610622944277578633427011520373324179896670642961784527024602806390495869308408470337715685294734193992593398889846197223766553446979093051960385337504355687757672562640543404353314227442034427503713670135808"},
+  {"0x1.a6208b5068395p+760", 229, "1.000000000000000126498340141932789543232683702883331170506688619337546981608693578840182199592199886956897100274793824830163262058051358073019842260050076805377254167221900194422501748144445768047027533261405765587857615803016806e+229"},
+  {"0x1.07d457124123cp+764", 230, "99999999999999988411127779858373832956786989976700226194703050524569553592790956543300452958271560395914310860351799229078805716535908585708440417158039479244754953558323062848579498254571868337516156995181495372666457581821100032"},
+  {"0x1.07d457124123dp+764", 230, "1.0000000000000000995664443260051171861588155025370724028889488288828968209774953551282735695911460777349244345335409545480104615144188833823603491391090010261628425414842702426517565519668094253057090928936734531588361669158161613e+230"},
+  {"0x1.49c96cd6d16cbp+767", 231, "999999999999999884111277798583738329567869899767002261947030505245695535927909565433004529582715603959143108603517992290788057165359085857084404171580394792447549535583230628485794982545718683375161569951814953726664575818211000320"},
+  {"0x1.49c96cd6d16ccp+767", 231, "1.00000000000000005647541102052084141484062638198305837470056516415545656396757819718921976158945998297976816934753636209656598064460692387730516014560327977941978394030406231981856423808259127691959958830530175327240184869629512909e+231"},
+  {"0x1.9c3bc80c85c7ep+770", 232, "9999999999999999185841044429711589466224211962102134844977374370276477415358432917842475759840644797632681207523216662519436418612086534611285553663849717898419964165273969667523488336530932020840491736225123136358120303938278260736"},
+  {"0x1.9c3bc80c85c7fp+770", 232, "1.000000000000000056475411020520841414840626381983058374700565164155456563967578197189219761589459982979768169347536362096565980644606923877305160145603279779419783940304062319818564238082591276919599588305301753272401848696295129088e+232"},
+  {"0x1.01a55d07d39cfp+774", 233, "99999999999999997374062707399103193390970327051935144057886852787877127050853725394623645022622268104986814019040754458979257737456796162759919727807229498567311142603806310797883499542489243201826933949562808949044795771481474727936"},
+  {"0x1.01a55d07d39d0p+774", 233, "1.0000000000000001943667175980705238830588315677559032649033928912832653863993131025941919471948554861962682179427510579411883194280051942934817649248215877689975714640807276728847796425120893517551500029880911929089916669987624321024e+233"},
+  {"0x1.420eb449c8842p+777", 234, "999999999999999841364972759543336764420226292177420345984153909836074800974071744757463152045042997962028093539001436578955132142505622028069656690022719315678435403212464369035268207172574280176140941400150227439321732144446136385536"},
+  {"0x1.420eb449c8843p+777", 234, "1.00000000000000001786584517880693032373952892996666180544377340055967009368669242367582754961994924207914815574087624726007172578525540816077571080742215354233800343364659602096002392484233181596564547219412071017415669957160428424397e+234"},
+  {"0x1.9292615c3aa53p+780", 235, "9999999999999999119653217272487741881479473472931169297680017061255129180591200163248089110750054956088761184197513608514017695996055364811520783369824930063422626153861170298051704942404772944919427537177384205332557191153093955289088"},
+  {"0x1.9292615c3aa54p+780", 235, "1.000000000000000053166019662659649035603389457524510097335697298704389152229216559459500429134930490902572168181251209396295044513805365387316921630902040387669917039733422351344975068376283323123546378352914806721123693057035913815654e+235"},
+  {"0x1.f736f9b3494e8p+783", 236, "99999999999999994020546131433094915763903576933939556328154082464128816489313932495174721468699049466761532837205133056038042458244550226238504699576640248260779350025557809411313140906763850021826347864477369777082931390365469918625792"},
+  {"0x1.f736f9b3494e9p+783", 236, "1.0000000000000000531660196626596490356033894575245100973356972987043891522292165594595004291349304909025721681812512093962950445138053653873169216309020403876699170397334223513449750683762833231235463783529148067211236930570359138156544e+236"},
+  {"0x1.3a825c100dd11p+787", 237, "999999999999999940205461314330949157639035769339395563281540824641288164893139324951747214686990494667615328372051330560380424582445502262385046995766402482607793500255578094113131409067638500218263478644773697770829313903654699186257920"},
+  {"0x1.3a825c100dd12p+787", 237, "1.00000000000000012094235467165686896238200167043557881776819118314224974463086290016415235780369448864354627206677113669784381647262128326227604641198342313070719116342012890568408126396147021686671611817779947209130032054906464259329229e+237"},
+  {"0x1.8922f31411455p+790", 238, "9999999999999999040580826428657651966904425891201589123842107529410958489455946099092661860636496958724291396331073693328877462044103460624068471125229983529879139676226679317989414380888721568885729507381685429067351125745727105048510464"},
+  {"0x1.8922f31411456p+790", 238, "1.000000000000000048647597328726501040484815309997105515973531039741865112735773470079190300557012891053173894588883214242858459716550970862319646645496614871467432098154308581055701322003937530207335062364589162363111917890900665230478541e+238"},
+  {"0x1.eb6bafd91596bp+793", 239, "99999999999999999081179145438220670296706622164632687453780292502155740721970192601122065475966761298087599260657287627887017431169472094235452683230716826407562484594165232135299736843791138087983021771402091458056119576436948334022754304"},
+  {"0x1.eb6bafd91596cp+793", 239, "1.0000000000000001064834032030707953780025643983478841574092591544621728182518450141471599463543581691254717965711935522068467451214072207822847664586860614788592393503669648407584052755699636795348399070151574101456626400174318471207295386e+239"},
+  {"0x1.33234de7ad7e2p+797", 240, "999999999999999828871535006218182557917368774264146678517764203804695831774701602620905646527100834378441867056103929979702975178097221166452191355376717763378564539746214794185426298453038162762816652692429820789419173810082174047524749312"},
+  {"0x1.33234de7ad7e3p+797", 240, "1.00000000000000001394611380411992443797416585698663833111209417090968048942613054363840851307860572420979515339949701146446548847363722091034057475758294690703234774682671482523407894986432184061083215557424821369358148461498195609632794214e+240"},
+  {"0x1.7fec216198ddbp+800", 241, "9999999999999999029013665253788793099400876073531433395554961906466896948352731790279067931477027903109831815934611625736079804963132210640075447162592094208400778225784148066048873590175516339020228538451571779510840981320420868670460264448"},
+  {"0x1.7fec216198ddcp+800", 241, "1.00000000000000005096102956370027281398552527353113666163096016433067742095641633184190908638890670217606581066817562776141799113274522085911825143802419273576310438824281483144380948014657857618043525615061189227441394677596191250608858071e+241"},
+  {"0x1.dfe729b9ff152p+803", 242, "99999999999999993251329913304315801074917514058874200397058898538348724005950180959070725179594357268399970740840405561116998262359962102302968606061220608382468313571129481157267178324335702235770533430624812081575006786082605199485453729792"},
+  {"0x1.dfe729b9ff153p+803", 242, "1.0000000000000000509610295637002728139855252735311366616309601643306774209564163318419090863889067021760658106681756277614179911327452208591182514380241927357631043882428148314438094801465785761804352561506118922744139467759619125060885807104e+242"},
+  {"0x1.2bf07a143f6d3p+807", 243, "999999999999999885134206960780312089454635087411784140906440513804611167700736000690226517958758320887173266104495426751070779219941381088594259909647411423049314634698686803624216704482068400828613365568502612232284516294771707790360919932928"},
+  {"0x1.2bf07a143f6d4p+807", 243, "1.0000000000000000746505756498316957746327953001196155931630344001201154571357992362921494533074993280744790313201299421914675928345743408263359645135065900661507886387491188354180370195272228869449812405194846465661467225589890846083353893929e+243"},
+  {"0x1.76ec98994f488p+810", 244, "9999999999999999230374806985905888264902671299533504313577592910677120255877486478106111050285065223246344191476223298391501419428679730361426008304192471516696094355087732099829807674910992980518869405586990190990569575476151831539558138249216"},
+  {"0x1.76ec98994f489p+810", 244, "1.000000000000000074650575649831695774632795300119615593163034400120115457135799236292149453307499328074479031320129942191467592834574340826335964513506590066150788638749118835418037019527222886944981240519484646566146722558989084608335389392896e+244"},
+  {"0x1.d4a7bebfa31aap+813", 245, "99999999999999992303748069859058882649026712995335043135775929106771202558774864781061110502850652232463441914762232983915014194286797303614260083041924715166960943550877320998298076749109929805188694055869901909905695754761518315395581382492160"},
+  {"0x1.d4a7bebfa31abp+813", 245, "1.0000000000000000443279566595834743850042896660863625608019793783096347708261891185958417836517007669245101088856284197210041026562330672682972917768891214832545527981010497103310257691199981691663623805273275210727287695567143043174594742793011e+245"},
+  {"0x1.24e8d737c5f0ap+817", 246, "999999999999999874521290314193434603084658115500145579580071256170942927492372459496518833579228824484684143252419893886408557657521935343280724451831297419035632090471862609843762766839539749606096764571247618309588232743975534688554349643169792"},
+  {"0x1.24e8d737c5f0bp+817", 246, "1.00000000000000006858605185178205149670709417331296498669082339575801931987387721275288791937633961584448524683322963769737489479890608611472822996618309634957154147061950501040063476944577794338925746852105322146746313195853412855016020637017702e+246"},
+  {"0x1.6e230d05b76cdp+820", 247, "9999999999999999521471949292288813605336325386252733424243721120057734844449743607990664678980731410286045846847437914107950925140755956518597266575720169912499958425309195700665115678820350271193610461511698595727381924297989722331966923339726848"},
+  {"0x1.6e230d05b76cep+820", 247, "1.00000000000000010739900415929977487543158138487552886811297382367543459835017816340416173653576177411644546754939158645956816222718291626901773106905345613567872334664903349051200916996702558214588960931101434209903811180144584732248137771557847e+247"},
+  {"0x1.c9abd04725480p+823", 248, "99999999999999992109683308321470265755404276937522223728665176967184126166393360027804741417053541441103640811181423240104047857145413152842812577527572916236425034170729678597741204746503691611405533351920096306747820855546959721533975525765152768"},
+  {"0x1.c9abd04725481p+823", 248, "1.0000000000000000452982804672714174694724018463754266578375331390075701527880966423621236290806863208813091144035324684400589343419399880221545293044608804779072323450017879223338101291330293601352781840470765490885181440527870972867675035629361562e+248"},
+  {"0x1.1e0b622c774d0p+827", 249, "999999999999999921096833083214702657554042769375222237286651769671841261663933600278047414170535414411036408111814232401040478571454131528428125775275729162364250341707296785977412047465036916114055333519200963067478208555469597215339755257651527680"},
+  {"0x1.1e0b622c774d1p+827", 249, "1.00000000000000011981914889770544635662341729257554931016806196060900748746259446761256935802677686476347273817856341006347000780423150191839037142197197126723302154697848260414764897813382482654801189436380190070114210535117759732962415254610693325e+249"},
+  {"0x1.658e3ab795204p+830", 250, "9999999999999999210968330832147026575540427693752222372866517696718412616639336002780474141705354144110364081118142324010404785714541315284281257752757291623642503417072967859774120474650369161140553335192009630674782085554695972153397552576515276800"},
+  {"0x1.658e3ab795205p+830", 250, "1.000000000000000080074685734807297616809542387935483895591779922421574242302862294145664969255528574692985472165213574530984101957676027840397922292632722846259267305924245440513601592000067244461220582194881713174409325992035997306767273088415852134e+250"},
+  {"0x1.bef1c9657a685p+833", 251, "99999999999999992109683308321470265755404276937522223728665176967184126166393360027804741417053541441103640811181423240104047857145413152842812577527572916236425034170729678597741204746503691611405533351920096306747820855546959721533975525765152768000"},
+  {"0x1.bef1c9657a686p+833", 251, "1.0000000000000000482791152044887786249584424642234315639307542918716276461750765553721414582385299426365956593545337061049953772804316485780039629891613241094802639130808557096063636830930611787917875324597455631530231025047227172884817695222629872435e+251"},
+  {"0x1.17571ddf6c813p+837", 252, "999999999999999895660376658959887464073162830405580371957831265231883984761705009259228605356936508765924557863270337660249498829658628118512958332498610172941047627432585001251621720339432063578508893731092043050369229765618973200711352404729235767296"},
+  {"0x1.17571ddf6c814p+837", 252, "1.00000000000000009915202805299840901192020234216271529458839530075154219997953373740977907586572775392681935985162149558657733676402265539783429787471556208832666934163027927905794433734427088386288041203596340318724106008442396531773857522810757106893e+252"},
+  {"0x1.5d2ce55747a18p+840", 253, "9999999999999999363587069377675917736425707327570073564839440723358156278052707548893386994586947577981035182609405692455150664165314335743772262409420005560181719702721238568128862437403998276353831973920663150777435958293799716241167969694049028276224"},
+  {"0x1.5d2ce55747a19p+840", 253, "1.000000000000000099152028052998409011920202342162715294588395300751542199979533737409779075865727753926819359851621495586577336764022655397834297874715562088326669341630279279057944337344270883862880412035963403187241060084423965317738575228107571068928e+253"},
+  {"0x1.b4781ead1989ep+843", 254, "99999999999999993635870693776759177364257073275700735648394407233581562780527075488933869945869475779810351826094056924551506641653143357437722624094200055601817197027212385681288624374039982763538319739206631507774359582937997162411679696940490282762240"},
+  {"0x1.b4781ead1989fp+843", 254, "1.0000000000000000665933638299522455642646760202815737069675050550683968855446811409056910005843211547010761915334853103183648826945244110331428835479608497818649698673586481946089327186234966726173809691071839855653415672334151665790142195763670374206669e+254"},
+  {"0x1.10cb132c2ff63p+847", 255, "999999999999999988452569694641453289891412847766833896677368465428848130901034909295879619908945316559292587569958465674654992927728624557883489163749540246356891129106733591931304833693638565628182306078113383272782784390994049606075766012189756664840192"},
+  {"0x1.10cb132c2ff64p+847", 255, "1.00000000000000019682802072213689935488678130780614005745106603780097814328409152692204330170994755160404886480603005139121469897251738849190854085497969900771176776444517253240497919350659351759937874082230165605293953863745036153391164218332917201371136e+255"},
+  {"0x1.54fdd7f73bf3bp+850", 256, "9999999999999998634272990781441856508941917717432502002131499220055701234712009387201814108283439755324388212283155142447191693008553661974684581490114449895439651479036702276471002178058655944454644452316004196046887318431202624493742403095061074555174912"},
+  {"0x1.54fdd7f73bf3cp+850", 256, "1.000000000000000030127659900140542502890486539774695128832107979903274133377646232821112356269145763568243843017172782817966934136686377344688499501995571998627866456174421380026039705656229556022421593026951037828814135240285311991642941246417639734614426e+256"},
+  {"0x1.aa3d4df50af0ap+853", 257, "99999999999999989676737124254345702129345072534953918593694153358511092545248999754036759991650433313959982558608696795936872226802156842691246641960827039136074540955782045812288811537593838676085587479067054324951381252255327235782798049688841391133687808"},
+  {"0x1.aa3d4df50af0bp+853", 257, "1.0000000000000000301276599001405425028904865397746951288321079799032741333776462328211123562691457635682438430171727828179669341366863773446884995019955719986278664561744213800260397056562295560224215930269510378288141352402853119916429412464176397346144256e+257"},
+  {"0x1.0a6650b926d66p+857", 258, "999999999999999843423255779504622828654636399579476808778874955057845642282427503428069697375447760968142218613652642015929437520555644859802053186653349748453896990911180089361627479263821919056229587496158345417793683435460456504301996197076723582025859072"},
+  {"0x1.0a6650b926d67p+857", 258, "1.0000000000000000567997176316599595992098937026597263174111412691669067749626774798772613075396740496539726465033899457896865765104193391282437061184730323200812906654977415644066700237122877898747347366742071367446741997838317199184059333963234848992699351e+258"},
+  {"0x1.4cffe4e7708c0p+860", 259, "9999999999999999287738405203667575368767393208115766122317814807014700953545274940077463414411382764424743897695475635254322931165011225671787143593812227771048544607458046793796444970432082673836316471673778619485458899748089618699435710767754281089234894848"},
+  {"0x1.4cffe4e7708c1p+860", 259, "1.00000000000000009947501000209102695332094516327577621913759453198871900149872747516709962957251930739113873208133740654443800430839207798193203670483696883440676940041505385941567853260198096403843576650981689501005030305350597260122672083617283716271875031e+259"},
+  {"0x1.a03fde214caf0p+863", 260, "99999999999999992877384052036675753687673932081157661223178148070147009535452749400774634144113827644247438976954756352543229311650112256717871435938122277710485446074580467937964449704320826738363164716737786194854588997480896186994357107677542810892348948480"},
+  {"0x1.a03fde214caf1p+863", 260, "1.0000000000000000653347761057461730700321039947829362977564319217312692202698874789352289719462431012014058636189794379406368620700138868989813722357458196229463864124812040234084717254902264247074749426413290883977494204377665704549700908842933553519596981453e+260"},
+  {"0x1.0427ead4cfed6p+867", 261, "999999999999999928773840520366757536876739320811576612231781480701470095354527494007746341441138276442474389769547563525432293116501122567178714359381222777104854460745804679379644497043208267383631647167377861948545889974808961869943571076775428108923489484800"},
+  {"0x1.0427ead4cfed7p+867", 261, "1.00000000000000014727133745697382238992532279916575210907122218634914869521910346989171855024930599605676474792863856258975960344212154549806296696156457773045130558352244362982576806255843731910178091992569982426727153871554113560598600276880411169778142334157e+261"},
+  {"0x1.4531e58a03e8bp+870", 262, "9999999999999998413748417457239315956573059294699064134960051984423986554086971036541574579178711885967582465059111638997013689862529533948250133185078807957662740116351490992011950708371166466963719380640490770210556304785160923755265983999639546733803159420928"},
+  {"0x1.4531e58a03e8cp+870", 262, "1.000000000000000016172839295009583478096172712153246810967557762960541535300357884361335224964405364288190533033183963151163217246749291739532415400254564758443434909856460259558093923249299888070891356270706646876036149471101831364360543753586901544466663027507e+262"},
+  {"0x1.967e5eec84e2ep+873", 263, "99999999999999987633444125558106197214507928600657449299031571134602723138702925979559301132717802373504470381136572374999373863835222106376649373485721758830170619127941133127257484131955329497127582170538059099205173427703324017329338747068854404759758535917568"},
+  {"0x1.967e5eec84e2fp+873", 263, "1.0000000000000000161728392950095834780961727121532468109675577629605415353003578843613352249644053642881905330331839631511632172467492917395324154002545647584434349098564602595580939232492998880708913562707066468760361494711018313643605437535869015444666630275072e+263"},
+  {"0x1.fc1df6a7a61bap+876", 264, "999999999999999932269800471352470574525516656465243420181212531991832952952360709621889896782068959956303035500093019510461530081711049334072862401016156456358397678710230902586782474091451932211122035531511013345645500354660676649720249983847887046345216426508288"},
+  {"0x1.fc1df6a7a61bbp+876", 264, "1.0000000000000000441405189028952877792863913973825812745630061732834443960830236092744836676918508323988196988775476110313971129684287058746855997333340341924717806535718700452151977396352492066908144631837718580528330325099155496025739750101665730438404785611735e+264"},
+  {"0x1.3d92ba28c7d14p+880", 265, "9999999999999998875215130987353436926211667600983082784284950754751883757000955497608523884181562109792963701491111829020872969270239867178277674680890053619130444887655752455354163678739330224192450644706066754627704874925587274685787599733204126473471115726422016"},
+  {"0x1.3d92ba28c7d15p+880", 265, "1.000000000000000066514662589203851220238566345566048845439364901541766684709156189205002421873807206887323031553038529335584229545772237182808147199797609739694457248544197873740880792744008661586752948714224026994270538940966524193144720015430310243339530988106547e+265"},
+  {"0x1.8cf768b2f9c59p+883", 266, "99999999999999988752151309873534369262116676009830827842849507547518837570009554976085238841815621097929637014911118290208729692702398671782776746808900536191304448876557524553541636787393302241924506447060667546277048749255872746857875997332041264734711157264220160"},
+  {"0x1.8cf768b2f9c5ap+883", 266, "1.0000000000000000307160326911101497147150864284725007320371909363284510229073440613161724151826770077057176992722530600488848430220225870898120712534558888641381746965884733480997879077699935337532513718655005566879705286512849648482315280070083307241410471050136781e+266"},
+  {"0x1.f03542dfb8370p+886", 267, "999999999999999973438224854160227305877518561122823750593712591987145964024444656694044404476868689015149167622996309190165824584023146941018349739309135463248122613459314107074039291811569329219648848907543004197890512187794469896370420793533163493423472892065087488"},
+  {"0x1.f03542dfb8371p+886", 267, "1.00000000000000008799384052806007212355265429582217771348066928066975608179024346593830042588848532639628623092150981090760386146002202723860579276760264226502822677971763258912553652372841773828685389482345810917805054511477545980009263522048349795485862131796226867e+267"},
+  {"0x1.362149cbd3226p+890", 268, "9999999999999999734382248541602273058775185611228237505937125919871459640244446566940444044768686890151491676229963091901658245840231469410183497393091354632481226134593141070740392918115693292196488489075430041978905121877944698963704207935331634934234728920650874880"},
+  {"0x1.362149cbd3227p+890", 268, "1.000000000000000156727209932399979014157735736641790091212843293879322152449722751484854038735455308824968468900617911938066683585621355417158258584578746346096289279472623678356434862878526783727176922373007172166146564870964053742325963876653698631719710373500577382e+268"},
+  {"0x1.83a99c3ec7eafp+893", 269, "99999999999999990012263082286432662256543169091523721434606031123027548865433341877772055077343404109122144711194766809100548098338386355056238620120129111010885594705399027856108106338478634741663761952135733701058809111452663635798820356028494943810497789949089153024"},
+  {"0x1.83a99c3ec7eb0p+893", 269, "1.0000000000000000467538188854561279891896054313304102868413648727440164393945558946103682581803033369390768881340449502893261681846624303314743132774169798163873892798646379355869975202383523110226600782937286713851929332610623034347526380267813775487419678846392834458e+269"},
+  {"0x1.e494034e79e5bp+896", 270, "999999999999999929448868435382686895890266438998271828845121223533023678802377913944250092254807900260792535316367124530669618423639576906744771616444428851364562613616119809966264354755499540137842111275831603885509059543833769773341090453584235060232375896520569913344"},
+  {"0x1.e494034e79e5cp+896", 270, "1.00000000000000004675381888545612798918960543133041028684136487274401643939455589461036825818030333693907688813404495028932616818466243033147431327741697981638738927986463793558699752023835231102266007829372867138519293326106230343475263802678137754874196788463928344576e+270"},
+  {"0x1.2edc82110c2f9p+900", 271, "9999999999999999529098585253973751145501342374646995204443699533752222309208135100774737254399069875964494058799026896824009283758441475916906799486389390443691279468658234350904109878520700943148057046794110173854458342872794765056233999682236635579342942941443126198272"},
+  {"0x1.2edc82110c2fap+900", 271, "1.000000000000000140597779245514880863829076625196121053238359792112810647868298279143262790920699686281704370388187210896251407993480713071257946606195020588405650612863452436083584052624634527730514451908046325384940032234845130363881876085339091539549641475134254271693e+271"},
+  {"0x1.7a93a2954f3b7p+903", 272, "99999999999999991537227438137387396469434575991841521388557198562770454753131655626431591234374844785939841297824578543963083245231683449577722661712772273556182341366629763489177637489755720763166395523368395578554699469776634573397170474480057796161122485794632428945408"},
+  {"0x1.7a93a2954f3b8p+903", 272, "1.0000000000000000655226109574678785641174996701035524401207638566177752810893043715169471647283826068076023845848734024107112161464260868794310399431725879707910415464644008356863148267156087543642309530165922021851423530558188688205784856384929203469035026027382776109466e+272"},
+  {"0x1.d9388b3aa30a5p+906", 273, "999999999999999945402341696592674884578976541955442659132610359825718694242914119314842162820675279649039207299571308833846909191138684972507989282336695782607667040225918275050684065261167516978177354790265605065466066369376850351293060923539046438669680406904714953752576"},
+  {"0x1.d9388b3aa30a6p+906", 273, "1.00000000000000006552261095746787856411749967010355244012076385661777528108930437151694716472838260680760238458487340241071121614642608687943103994317258797079104154646440083568631482671560875436423095301659220218514235305581886882057848563849292034690350260273827761094656e+273"},
+  {"0x1.27c35704a5e67p+910", 274, "9999999999999999213782878444176341486712719163258207029349796604673073768736360688744211624391338142173265718425108901184740478000812045911233791501695173449709921389782217629235579129702792695009666351450002856415308090320884466574359759805482716570229159677380024223137792"},
+  {"0x1.27c35704a5e68p+910", 274, "1.000000000000000113570718661817960035932908921362796352516025255334597915827860472397789165491465537671027655498994239841456938928541047642200260207506944846064391348959793859940567131297385249318652392307122841033012867730395676208292655524474469910197031481071702673824154e+274"},
+  {"0x1.71b42cc5cf601p+913", 275, "99999999999999995981677400789769932612359931733321583285118877944076548466448094957909476304960015890806678857380756006307062602577317320133875536163700284518967198097453618232695975663570046546450378657742479671982722077174989256760731188933351130765773907040474247261585408"},
+  {"0x1.71b42cc5cf602p+913", 275, "1.0000000000000001135707186618179600359329089213627963525160252553345979158278604723977891654914655376710276554989942398414569389285410476422002602075069448460643913489597938599405671312973852493186523923071228410330128677303956762082926555244744699101970314810717026738241536e+275"},
+  {"0x1.ce2137f743381p+916", 276, "999999999999999929065985077113647184161737396527299728918221484261998998431805045015355882561227083155474615188770224107393363445219598313166454392463014445014728107377484646804238281703363508693674065431485187857190091380020735839470243162305319587149880588271350432374194176"},
+  {"0x1.ce2137f743382p+916", 276, "1.00000000000000005206914080024985575200918507975096414465009066497706494336250866327031140451471938616584330872891956793010241376743389786585565826915896804571450360176569078889512418143271133577699295001524362330773860894693736275201851807041808646918131451680491859334083379e+276"},
+  {"0x1.20d4c2fa8a030p+920", 277, "9999999999999998060628293539774386163142897133036353131863523035469330535011014267604003606077347801451059216486208802846843131230052987604772505157670608443149526129892785047133523819740156816103551808477267524066415738131041089269219682541925527051184466597377822714075545600"},
+  {"0x1.20d4c2fa8a031p+920", 277, "1.000000000000000002867878510995372324870206006461498378357342992691038565390227215968329195733322464961695831312859830401018793638548178044779976718480586605434593404010408332058769821540972204943665396181740249127519201920170711986999208107172979716368740945391491328954177946e+277"},
+  {"0x1.6909f3b92c83dp+923", 278, "99999999999999996350686867959178558315902274782992576532314485486221746301240205812674342870820492799837784938001204037775189753543960218791943147793788145321066524580618236658968633362758090027700335311493754978334367629875739137498376013657689431411868208826074951744485326848"},
+  {"0x1.6909f3b92c83ep+923", 278, "1.000000000000000120950908005206132550003755782356216217459937406177501872523702689493086496808675075851649777111403200470819481947873905615361612440108702062106377878623086228466020285281146118943651525382148347160045778784410673823045552018961235923118917516783716763482151977e+278"},
+  {"0x1.c34c70a777a4cp+926", 279, "999999999999999932018060814468916189790076140924667674895786344599160581110141931853474815088110898427723463833733808359138380652952741502430995285503717331431522719242801594214419543296867856543673718661495390308003255801626734885371401760100025992318635002556156068237393526784"},
+  {"0x1.c34c70a777a4dp+926", 279, "1.00000000000000005797329227496039376326586256854570003660522038565138810871918243694654926956848701671034100601884673643359244818290018424438474005524037381854809282549632468371548670461972003147699225647526402820936493779014936084382083526600749927951882334537452986506723249357e+279"},
+  {"0x1.1a0fc668aac6fp+930", 280, "9999999999999998312538756460757341310094469988278417855282391117573785590229095277790152515038100038016294300856434658995751266289947873088679994697143921417382666342399831226135658142385861165970188884104804799869139102108086341186118549553740473625584843283014570307735223533568"},
+  {"0x1.1a0fc668aac70p+930", 280, "1.000000000000000032782245982862098248570705283021493564263333577440942603197374335927934378672411793053817497581824150818701634676910695695993991101293042521124778804245620065815273272355149596490328548912510300629092601392444835652130948564826004622078785676810855105701264700211e+280"},
+  {"0x1.6093b802d578bp+933", 281, "99999999999999987155954971343300695452169865566657214127525800489409136785780248940879907693753036165206704358487960288340042823857796898629319779603012221761556906824111051125390730586189881257568082051088644411534964844713587442531567367726443881446254459800333664575907082272768"},
+  {"0x1.6093b802d578cp+933", 281, "1.0000000000000000327822459828620982485707052830214935642633335774409426031973743359279343786724117930538174975818241508187016346769106956959939911012930425211247788042456200658152732723551495964903285489125103006290926013924448356521309485648260046220787856768108551057012647002112e+281"},
+  {"0x1.b8b8a6038ad6ep+936", 282, "999999999999999903804088967318825213331499981137556425872873119403461614925716858712626137284506647932417134384268512470460669526244514328233356457082706278317411015442012422166180499160548969358610366191211215418098239036197666670678728654776751975985792813764840337747509598224384"},
+  {"0x1.b8b8a6038ad6fp+936", 282, "1.0000000000000000327822459828620982485707052830214935642633335774409426031973743359279343786724117930538174975818241508187016346769106956959939911012930425211247788042456200658152732723551495964903285489125103006290926013924448356521309485648260046220787856768108551057012647002112e+282"},
+  {"0x1.137367c236c65p+940", 283, "9999999999999999553953517735361344274271821018911312812290573026184540102343798495987494338396687059809772796632907678097570555865109868753376103147668407754403581309634554796258176084383892202112976392797308495024959839786965342632596166187964530344229899589832462449290116390191104"},
+  {"0x1.137367c236c66p+940", 283, "1.000000000000000161760402998405371283809910584905430702653794035478423591469031813143242620060316938175217860779379789166942599827576877063754625745503378763932146593049227709464366045549750223622046731633809385840086963748692004633583168474875257268171778539856869873655019802198016e+283"},
+  {"0x1.585041b2c477ep+943", 284, "99999999999999991412234152856228705615063640528827139694410995604646009398744945688985079659553905954212916344007296353831994673829780883765420722861953317774200043854630103365810792101611701952914782080891514223497778802469744018919490624758069218767323224280852151918381000638332928"},
+  {"0x1.585041b2c477fp+943", 284, "1.0000000000000000792143825084576765412568191916997109340838993423344357589751710277254453455720576452975216283329441806240683821311505209883878195732087635685354312082149188175289466707052058222577470946921779713050505718406938164854537477324437355746722631075074204221646165369264538e+284"},
+  {"0x1.ae64521f7595ep+946", 285, "999999999999999980159157920520442850193109519852847211800025710561650359982538085224088616186146493844286149397221450372619320895438893697947652166455225334059372746413748147206443420891752540620587530362220273863006901551095990707698442841525909542472844588688081080376132618600579072"},
+  {"0x1.ae64521f7595fp+946", 285, "1.00000000000000011223279070443675443827805574898199884151185721959203089197271534189256425536736136244860012131151842404121806920972106341853454204212660964669411736214864237430311442064302358280346694946883053711906512860389309174470551602941634425207206928044720020276077784303507866e+285"},
+  {"0x1.0cfeb353a97dap+950", 286, "9999999999999998216707985798208689444911740448978652561458278997251937215943253772219178491686886515191093831000650819703008229183002900332433843156495641588976792075318750746904382211902272900011322274342879579557370290877394694632899550160573878909537749585771381335145583492791795712"},
+  {"0x1.0cfeb353a97dbp+950", 286, "1.000000000000000032988611034086967485427088011504507863684758314173802572778608987891478871858632441286011738162940239840058820221151761586182408116723779059113270592707705838045111820792260957493739298004864379165430192372214831122501272116682083426312534465391728729329990708374378906e+286"},
+  {"0x1.503e602893dd1p+953", 287, "99999999999999990619792356152730836086553963154052229916140006550463726206803882148974225824466616742587032512521514511820402183944087865441899383607925011898391576160220738003230766103104075699817505566251852643961429440152961412697448185630726610509727876130297437184073129291725930496"},
+  {"0x1.503e602893dd2p+953", 287, "1.0000000000000000752521735249401871936142708048258363851925443970635243430154657100253910763966211992393922091755152714140104196817220558967702128769386220391563888697428719907160465407126676909922607121189796634073688250291099034543435355368070225333842863667546468484930771801934187725e+287"},
+  {"0x1.a44df832b8d45p+956", 288, "999999999999999872387073568844732594315793396883459481955171199192859845878553443782612494614275161063165948315155119859042742270984643205948750027907375734949421139974074457895559885094715370199357924371226299046063388276013556261500671120207314819439877240212639876510262115462027411456"},
+  {"0x1.a44df832b8d46p+956", 288, "1.00000000000000000763047353957503566051477833551171075078008666443996951063649495461113154913583918651398345555539522089568786054480958499982972526059487327108739962648660614644255098884001691739462644953639520862026701277807778772339591406460711996206948332457397785783213882528295498547e+288"},
+  {"0x1.06b0bb1fb384bp+960", 289, "9999999999999998453383935746986719810759964091578092281901881061434379129269651416169086837099623559730024468671070996517137186162196548471725549813698762277218254426715681201861616643456550607603042193381925171312226633756007099691216225313273537909139560233403722802458867734978418966528"},
+  {"0x1.06b0bb1fb384cp+960", 289, "1.000000000000000061727833527867156886994372310963011258310052850538813376539671558942539170944464796694310458451491261310345907854339561717382115353669872285542591021091618821861347430338137536272733859602462772449948462578903480308154011242367042019121325758318513050360889509211326015078e+289"},
+  {"0x1.485ce9e7a065ep+963", 290, "99999999999999988861628156533236896225967158951884963421416105502251300564950642508203478115686284411726404918398393198344015646384363622121446705582987543928597855835557826052119881754415155586279014739104656819496782321626126403692810027353529143655542997033600043426888732064053872033792"},
+  {"0x1.485ce9e7a065fp+963", 290, "1.0000000000000000617278335278671568869943723109630112583100528505388133765396715589425391709444647966943104584514912613103459078543395617173821153536698722855425910210916188218613474303381375362727338596024627724499484625789034803081540112423670420191213257583185130503608895092113260150784e+290"},
+  {"0x1.9a742461887f6p+966", 291, "999999999999999957860902350346284132153551878096514283852517773229033154005572478626236537071903625148082612890986863714202457020042006419681526374965874177788623543449994485057258262661745948026767632275613049896960078961318150545418464661067991669581788285529005480705688196068853638234112"},
+  {"0x1.9a742461887f7p+966", 291, "1.0000000000000000963501439203741144719413124552518435831292312096420734507177045857146400489019851872097197403049927271757270581324387468166156450132378716547939135136388269341293771528969347323547226020447460133009445904514319235623991934361333921356345049159150155735792899469254834740265e+291"},
+  {"0x1.008896bcf54f9p+970", 292, "9999999999999997916738124663128877244082391855101191247204616495333847979510139501201523228758057506741180599941798275603729356851659179433605840090394772053822755792233955461707155943795194068332216685526534938121786651731816229250415901309895111103185283290657933692573660950408978352832512"},
+  {"0x1.008896bcf54fap+970", 292, "1.000000000000000013256598978357416268068656108958646003563203147794249272690425321461597941803936249972737463856589209098812297465000702578455173830274673168590739531525527464686105818755821461757949620183266235258553883557363659752210756171094151856002874937683409517855128896411505572551066e+292"},
+  {"0x1.40aabc6c32a38p+973", 293, "99999999999999992462348437353960485060448933957923525202610654848990348279466077292501969423268405025328970231162545648343655275306678872441733790178059478330735395060467469727994972900530063978805843953102113868000379620369084502134308975505229555772913629423636305841602377586326247764393984"},
+  {"0x1.40aabc6c32a39p+973", 293, "1.0000000000000001018897135831752276855328228783380567551002997470985950625861898699981761893751884496921852254015529617141880421769346164324930097587687515538741251124463802320922619085063422837278408008355113318371039709110364744830784225871360081542766135811304559772942340169597486674581914e+293"},
+  {"0x1.90d56b873f4c6p+976", 294, "999999999999999924623484373539604850604489339579235252026106548489903482794660772925019694232684050253289702311625456483436552753066788724417337901780594783307353950604674697279949729005300639788058439531021138680003796203690845021343089755052295557729136294236363058416023775863262477643939840"},
+  {"0x1.90d56b873f4c7p+976", 294, "1.00000000000000006643646774124810311854715617058629245448546110737685674662788405058354489034668756980440612078356746066803774429216105089087787538737112019976077088007803912512979947260613395493988432857461329320568393596956734859073135602071926563496711812375163739351859196874045142949534106e+294"},
+  {"0x1.f50ac6690f1f8p+979", 295, "9999999999999999813486777206230041577815560719820581330098483720446847883279500839884297726782854580737362697004022581572770293687044935910015528960168049498887207223940204684198896264456339658487887951484580004902758521100414464490983962613190835886243290260424727924570510530141380583845003264"},
+  {"0x1.f50ac6690f1f9p+979", 295, "1.000000000000000094799064414789802772135689536787703894977332019154247399394528706115249929569488273714629404477955861504957982599979903324169982884489225283051454265972712010699769421326300617970249506383331724110819963922742649304609009273852659650414714489654692260539105607315889219865621299e+295"},
+  {"0x1.3926bc01a973bp+983", 296, "99999999999999998134867772062300415778155607198205813300984837204468478832795008398842977267828545807373626970040225815727702936870449359100155289601680494988872072239402046841988962644563396584878879514845800049027585211004144644909839626131908358862432902604247279245705105301413805838450032640"},
+  {"0x1.3926bc01a973cp+983", 296, "1.0000000000000001628692964312898819407481696156710913521578222074199849660344758793913420237042099630991652853444880235135665545387451491640710408775726774829490943921199269360676972982547006092431259331242559582831464310103633710179153770813728052874889457678220239413883383398969399167542938829e+296"},
+  {"0x1.87706b0213d09p+986", 297, "999999999999999872436306494222877488001587945768638201521064070819504681704034606746682422062730755058478860313950798943503314266680100247159860107083281430052496520558476587831205023360193979812186512362979225814553504769848291707808207769286850569305558980974742103098278680884456943362624192512"},
+  {"0x1.87706b0213d0ap+986", 297, "1.0000000000000000176528014627563797143748787807198647768394431391197448238692552430690122228834703590788220728292194112285349344027126247056154504923279794565007954563392017619494511608074472945276562227436175920488499678901058313628617924253298279283972523743983830222433085103906984300584590377e+297"},
+  {"0x1.e94c85c298c4cp+989", 298, "9999999999999999595662034753429788238255624467393741467120915117996487670031669885400803025551745174706847878231119663145222863482996149222332143382301002459214758820269116923021527058285459686414683385913622455551313826420028155008403585629126369847605750170289266545852965785882018353801250996224"},
+  {"0x1.e94c85c298c4dp+989", 298, "1.00000000000000007573939945016978060492419511470035540696679476643984088073534349759794414321176620068695935783532685614254758245712563448899768664642585866708011503065149183159674961578634862041384410689587293854256855313820884722488322628774701887203392973176783938990132044219319502473679297577e+298"},
+  {"0x1.31cfd3999f7afp+993", 299, "99999999999999986662764669548153739894665631237058913850832890808749507601742578129378923002990117089766513181334005445210204946123879926882163649167349350899456456312724758086647517786230384722356772394775369116518164624503799012160606438304513147494189124523779646633247748770420728389479079870464"},
+  {"0x1.31cfd3999f7b0p+993", 299, "1.0000000000000000525047602552044202487044685811081591549158541155118024579889081957863713750804478640437044438328838781769425232353604305756447921847867069828483872009265758037378302337947880900593689532349707999450811190389676408800746527427801424945792587888200568428381156694721963868654594005402e+299"},
+  {"0x1.7e43c8800759bp+996", 300, "999999999999999903803069407426113968898218766118103141789833949572356552411722264192305659040010509526872994217248819197070144216063125530186267630296136203765329090687113225440746189048800695790727969805197112921161540803823920273299782054992133678869364753954248541633605124057805104488924519071744"},
+  {"0x1.7e43c8800759cp+996", 300, "1.00000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936895323497079994508111903896764088007465274278014249457925878882005684283811566947219638686545940054016e+300"},
+  {"0x1.ddd4baa009302p+999", 301, "9999999999999999335434075769817752248594687291161143444150379827602457335271594505111188022480979804302392841403758309930446200199225865392779725411942503595819407127350057411001629979979981746444561664911518503259454564508526643946547561925497354420113435609274102018745072331406833609642314953654272"},
+  {"0x1.ddd4baa009303p+999", 301, "1.00000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936895323497079994508111903896764088007465274278014249457925878882005684283811566947219638686545940054016e+301"},
+  {"0x1.2aa4f4a405be1p+1003", 302, "99999999999999988595886650569271721532146878831929642021471152965962304374245995240101777311515802698485322026337261211948545873374744892473124468375726771027536211745837771604509610367928220847849105179362427047829119141560667380048679757245757262098417746977035154548906385860807815060374033329553408"},
+  {"0x1.2aa4f4a405be2p+1003", 302, "1.0000000000000000762970307908489492534734685515065681170160173420621138028812579448414218896469178407663974757713854876137221038784479993829181561135051983075016764985648898162653636809541460731423515105837345898689082515565906361771586320528262239050928418343985861710308373567384989920457049815751066e+302"},
+  {"0x1.754e31cd072d9p+1006", 303, "999999999999999847891233648661470807691068835681842080854450367179124891914700353912936949808806064228544369161770037020638129704807338833093862397807681590830099241237075296001042588224309435545718960035602206600167779387409881325152430676383842364162444596844704620380709158981993982315347403639619584"},
+  {"0x1.754e31cd072dap+1006", 303, "1.00000000000000000016176507678645643821266864623165943829549501710111749922573874786526024303421391525377977356818033741602744582056777919964339154160602606861115074612228497617725665004420052727680732706769046211266142750019705122648989826067876339144937608854729232081412795748633065546891912226327757e+303"},
+  {"0x1.d2a1be4048f90p+1009", 304, "9999999999999999392535525055364621860040287220117324953190771571323204563013233902843309257440507748436856118056162172578717193742636030530235798840866882774987301441682011041067710253162440905843719802548551599076639682550821832659549112269607949805346034918662572406407604380845959862074904348138143744"},
+  {"0x1.d2a1be4048f91p+1009", 304, "1.000000000000000061069977648036450690421308570451586381271912877069914542150154105446189560324377055663873935330744457574183172266871955346263203199125363859723571348076368848247742274772156963969242673880525764317658886745311919187024885294396731802364148685228327400987495476888065324730347809712740762e+304"},
+  {"0x1.23a516e82d9bap+1013", 305, "99999999999999993925355250553646218600402872201173249531907715713232045630132339028433092574405077484368561180561621725787171937426360305302357988408668827749873014416820110410677102531624409058437198025485515990766396825508218326595491122696079498053460349186625724064076043808459598620749043481381437440"},
+  {"0x1.23a516e82d9bbp+1013", 305, "1.0000000000000001341598327335364437930716764795154987128436143090324709936594525345433047410725728241559869294458214017639700440024369667222069771881485692090584760704212694947323250244457046880001650900559281269636558378394497607396668697348582938954618758012455694971955365001701469278440622346520965939e+305"},
+  {"0x1.6c8e5ca239028p+1016", 306, "999999999999999861291040414336469543176969619010226008309262296372260241358071732580741399612641955118765084749534143455432389522994257585350220962461935904874831773666973747856549425664459851618054736334425973085267220421335152276470127823801795414563694568114532338018850013250375609552861714878501486592"},
+  {"0x1.6c8e5ca239029p+1016", 306, "1.00000000000000001721606459673645482883108782501323898232889201789238067124457504798792045187545959456860613886169829106031104922553294852069693880571144065012262851466942846035699262496802832955068922417528434673006071608882921425543969463011979454650551241561798214326267086291881636286211915474912726221e+306"},
+  {"0x1.c7b1f3cac7433p+1019", 307, "9999999999999999860310597602564577717002641838126363875249660735883565852672743849064846414228960666786379280392654615393353172850252103336275952370615397010730691664689375178569039851073146339641623266071126720011020169553304018596457812688561947201171488461172921822139066929851282122002676667750021070848"},
+  {"0x1.c7b1f3cac7434p+1019", 307, "1.000000000000000110771079106176446000223558748615046766740669850804452929176477037232227883233150178238510771328996779623238245047056163081904969511661143497271306559270901287857258544550169416310269916879799370916936813489325651442821434713910594025670603124120052026408963372719880814847673618671502727578e+307"},
+  {"0x1.1ccf385ebc89fp+1023", 308, "99999999999999981139503267596847425176765179308926185662298078548582170379439067165044410288854031049481594743364161622187121841818187648603927125262209438639553681654618823985640760188731793867961170022535129351893330180773705244319986644578003569234231285691342840034082734135647456849389933411990123839488"},
+  {"0x1.1ccf385ebc8a0p+1023", 308, "1.0000000000000000109790636294404554174049230967731184633681068290315758540491149153716332897849468889906124966972117251561159028374314008832830700919814604603127166450293302718569748969958855904333838446616500117842689762621294517762809119578670745812278397017178441510529180289320787327297488571543022311834e+308"},
+  {"0x1.a36e2eb1c432cp-14", 309, "9.99999999999999912396464463171241732197813689708709716796875e-5"},
+  {"0x1.a36e2eb1c432dp-14", 309, "0.000100000000000000004792173602385929598312941379845142364501953125"},
+  {"0x1.0624dd2f1a9fbp-10", 309, "0.00099999999999999980397624721462079833145253360271453857421875"},
+  {"0x1.0624dd2f1a9fcp-10", 309, "0.001000000000000000020816681711721685132943093776702880859375"},
+  {"0x1.47ae147ae147ap-7", 309, "0.0099999999999999984734433411404097569175064563751220703125"},
+  {"0x1.47ae147ae147bp-7", 309, "0.01000000000000000020816681711721685132943093776702880859375"},
+  {"0x1.9999999999999p-4", 309, "0.09999999999999999167332731531132594682276248931884765625"},
+  {"0x1.999999999999ap-4", 309, "0.1000000000000000055511151231257827021181583404541015625"},
+  {"0x1.fffffffffffffp-1", 309, "0.99999999999999988897769753748434595763683319091796875"},
+  {"0x1.0000000000000p+0", 309, "1"},
+  {"0x1.3ffffffffffffp+3", 309, "9.9999999999999982236431605997495353221893310546875"},
+  {"0x1.4000000000000p+3", 309, "10"},
+  {"0x1.8ffffffffffffp+6", 309, "99.9999999999999857891452847979962825775146484375"},
+  {"0x1.9000000000000p+6", 309, "100"},
+  {"0x1.f3fffffffffffp+9", 309, "999.9999999999998863131622783839702606201171875"},
+  {"0x1.f400000000000p+9", 309, "1000"},
+  {"0x1.387ffffffffffp+13", 309, "9999.999999999998181010596454143524169921875"},
+  {"0x1.3880000000000p+13", 309, "10000"},
+  {"0x1.869ffffffffffp+16", 309, "99999.999999999985448084771633148193359375"},
+  {"0x1.86a0000000000p+16", 309, "100000"},
+  {"0x1.e847fffffffffp+19", 309, "999999.999999999883584678173065185546875"},
+  {"0x1.e848000000000p+19", 309, "1000000"},
+  {"0x1.312cfffffffffp+23", 309, "9999999.99999999813735485076904296875"},
+  {"0x1.312d000000000p+23", 309, "10000000"},
+  {"0x1.7d783ffffffffp+26", 309, "99999999.99999998509883880615234375"},
+  {"0x1.7d78400000000p+26", 309, "100000000"},
+  {"0x1.dcd64ffffffffp+29", 309, "999999999.99999988079071044921875"},
+  {"0x1.dcd6500000000p+29", 309, "1000000000"},
+  {"0x1.2a05f1fffffffp+33", 309, "9999999999.9999980926513671875"},
+  {"0x1.2a05f20000000p+33", 309, "10000000000"},
+  {"0x1.74876e7ffffffp+36", 309, "99999999999.9999847412109375"},
+  {"0x1.74876e8000000p+36", 309, "100000000000"},
+  {"0x1.d1a94a1ffffffp+39", 309, "999999999999.9998779296875"},
+  {"0x1.d1a94a2000000p+39", 309, "1000000000000"},
+  {"0x1.2309ce53fffffp+43", 309, "9999999999999.998046875"},
+  {"0x1.2309ce5400000p+43", 309, "10000000000000"},
+  {"0x1.6bcc41e8fffffp+46", 309, "99999999999999.984375"},
+  {"0x1.6bcc41e900000p+46", 309, "100000000000000"},
+  {"0x1.c6bf52633ffffp+49", 309, "999999999999999.875"},
+  {"0x1.c6bf526340000p+49", 309, "1000000000000000"},
+  {"0x1.1c37937e07fffp+53", 309, "9999999999999998"},
+  {"0x1.1c37937e08000p+53", 309, "10000000000000000"},
+  {"0x1.6345785d89fffp+56", 309, "99999999999999984"},
+  {"0x1.6345785d8a000p+56", 309, "100000000000000000"},
+  {"0x1.bc16d674ec7ffp+59", 309, "999999999999999872"},
+  {"0x1.bc16d674ec800p+59", 309, "1000000000000000000"},
+  {"0x1.158e460913cffp+63", 309, "9999999999999997952"},
+  {"0x1.158e460913d00p+63", 309, "10000000000000000000"},
+  {"0x1.5af1d78b58c3fp+66", 309, "99999999999999983616"},
+  {"0x1.5af1d78b58c40p+66", 309, "100000000000000000000"},
+  {"0x1.b1ae4d6e2ef4fp+69", 309, "999999999999999868928"},
+  {"0x1.b1ae4d6e2ef50p+69", 309, "1000000000000000000000"},
+  {"0x1.0f0cf064dd591p+73", 309, "9999999999999997902848"},
+  {"0x1.0f0cf064dd592p+73", 309, "10000000000000000000000"},
+  {"0x1.52d02c7e14af6p+76", 309, "99999999999999991611392"},
+  {"0x1.52d02c7e14af7p+76", 309, "100000000000000008388608"},
+  {"0x1.a784379d99db4p+79", 309, "999999999999999983222784"},
+  {"0x1.a784379d99db5p+79", 309, "1000000000000000117440512"},
+  {"0x1.08b2a2c280290p+83", 309, "9999999999999998758486016"},
+  {"0x1.08b2a2c280291p+83", 309, "10000000000000000905969664"},
+  {"0x1.4adf4b7320334p+86", 309, "99999999999999987584860160"},
+  {"0x1.4adf4b7320335p+86", 309, "100000000000000004764729344"},
+  {"0x1.9d971e4fe8401p+89", 309, "999999999999999875848601600"},
+  {"0x1.9d971e4fe8402p+89", 309, "1000000000000000013287555072"},
+  {"0x1.027e72f1f1281p+93", 309, "9999999999999999583119736832"},
+  {"0x1.027e72f1f1282p+93", 309, "10000000000000001782142992384"},
+  {"0x1.431e0fae6d721p+96", 309, "99999999999999991433150857216"},
+  {"0x1.431e0fae6d722p+96", 309, "100000000000000009025336901632"},
+  {"0x1.93e5939a08ce9p+99", 309, "999999999999999879147136483328"},
+  {"0x1.93e5939a08ceap+99", 309, "1000000000000000019884624838656"},
+  {"0x1.f8def8808b024p+102", 309, "9999999999999999635896294965248"},
+  {"0x1.f8def8808b025p+102", 309, "10000000000000000761796201807872"},
+  {"0x1.3b8b5b5056e16p+106", 309, "99999999999999987351763694911488"},
+  {"0x1.3b8b5b5056e17p+106", 309, "100000000000000005366162204393472"},
+  {"0x1.8a6e32246c99cp+109", 309, "999999999999999945575230987042816"},
+  {"0x1.8a6e32246c99dp+109", 309, "1000000000000000089690419062898688"},
+  {"0x1.ed09bead87c03p+112", 309, "9999999999999999455752309870428160"},
+  {"0x1.ed09bead87c04p+112", 309, "10000000000000000608673814477275136"},
+  {"0x1.3426172c74d82p+116", 309, "99999999999999996863366107917975552"},
+  {"0x1.3426172c74d83p+116", 309, "100000000000000015310110181627527168"},
+  {"0x1.812f9cf7920e2p+119", 309, "999999999999999894846684784341549056"},
+  {"0x1.812f9cf7920e3p+119", 309, "1000000000000000042420637374017961984"},
+  {"0x1.e17b84357691bp+122", 309, "9999999999999999538762658202121142272"},
+  {"0x1.e17b84357691cp+122", 309, "10000000000000000719354278919532445696"},
+  {"0x1.2ced32a16a1b1p+126", 309, "99999999999999997748809823456034029568"},
+  {"0x1.2ced32a16a1b2p+126", 309, "100000000000000016638275754934614884352"},
+  {"0x1.78287f49c4a1dp+129", 309, "999999999999999939709166371603178586112"},
+  {"0x1.78287f49c4a1ep+129", 309, "1000000000000000090824893823431825424384"},
+  {"0x1.d6329f1c35ca4p+132", 309, "9999999999999999094860208812374492184576"},
+  {"0x1.d6329f1c35ca5p+132", 309, "10000000000000000303786028427003666890752"},
+  {"0x1.25dfa371a19e6p+136", 309, "99999999999999981277195531206711524196352"},
+  {"0x1.25dfa371a19e7p+136", 309, "100000000000000000620008645040778319495168"},
+  {"0x1.6f578c4e0a060p+139", 309, "999999999999999890143207767403382423158784"},
+  {"0x1.6f578c4e0a061p+139", 309, "1000000000000000044885712678075916785549312"},
+  {"0x1.cb2d6f618c878p+142", 309, "9999999999999998901432077674033824231587840"},
+  {"0x1.cb2d6f618c879p+142", 309, "10000000000000000139372116959414099130712064"},
+  {"0x1.1efc659cf7d4bp+146", 309, "99999999999999989014320776740338242315878400"},
+  {"0x1.1efc659cf7d4cp+146", 309, "100000000000000008821361405306422640701865984"},
+  {"0x1.66bb7f0435c9ep+149", 309, "999999999999999929757289024535551219930759168"},
+  {"0x1.66bb7f0435c9fp+149", 309, "1000000000000000088213614053064226407018659840"},
+  {"0x1.c06a5ec5433c6p+152", 309, "9999999999999999931398190359470212947659194368"},
+  {"0x1.c06a5ec5433c7p+152", 309, "10000000000000001199048790587699614444362399744"},
+  {"0x1.18427b3b4a05bp+156", 309, "99999999999999984102174700855949311516153479168"},
+  {"0x1.18427b3b4a05cp+156", 309, "100000000000000004384584304507619735463404765184"},
+  {"0x1.5e531a0a1c872p+159", 309, "999999999999999881586566215862833963056037363712"},
+  {"0x1.5e531a0a1c873p+159", 309, "1000000000000000043845843045076197354634047651840"},
+  {"0x1.b5e7e08ca3a8fp+162", 309, "9999999999999999464902769475481793196872414789632"},
+  {"0x1.b5e7e08ca3a90p+162", 309, "10000000000000000762976984109188700329496497094656"},
+  {"0x1.11b0ec57e6499p+166", 309, "99999999999999986860582406952576489172979654066176"},
+  {"0x1.11b0ec57e649ap+166", 309, "100000000000000007629769841091887003294964970946560"},
+  {"0x1.561d276ddfdc0p+169", 309, "999999999999999993220948674361627976461708441944064"},
+  {"0x1.561d276ddfdc1p+169", 309, "1000000000000000159374448147476112089437590976987136"},
+  {"0x1.aba4714957d30p+172", 309, "9999999999999999932209486743616279764617084419440640"},
+  {"0x1.aba4714957d31p+172", 309, "10000000000000001261437482528532152668424144699785216"},
+  {"0x1.0b46c6cdd6e3ep+176", 309, "99999999999999999322094867436162797646170844194406400"},
+  {"0x1.0b46c6cdd6e3fp+176", 309, "100000000000000020589742799994816764107083808679919616"},
+  {"0x1.4e1878814c9cdp+179", 309, "999999999999999908150356944127012110618056584002011136"},
+  {"0x1.4e1878814c9cep+179", 309, "1000000000000000078291540404596243842305360299886116864"},
+  {"0x1.a19e96a19fc40p+182", 309, "9999999999999998741221202520331657642805958408251899904"},
+  {"0x1.a19e96a19fc41p+182", 309, "10000000000000000102350670204085511496304388135324745728"},
+  {"0x1.05031e2503da8p+186", 309, "99999999999999987412212025203316576428059584082518999040"},
+  {"0x1.05031e2503da9p+186", 309, "100000000000000009190283508143378238084034459715684532224"},
+  {"0x1.4643e5ae44d12p+189", 309, "999999999999999874122120252033165764280595840825189990400"},
+  {"0x1.4643e5ae44d13p+189", 309, "1000000000000000048346692115553659057528394845890514255872"},
+  {"0x1.97d4df19d6057p+192", 309, "9999999999999999438119489974413630815797154428513196965888"},
+  {"0x1.97d4df19d6058p+192", 309, "10000000000000000831916064882577577161779546469035791089664"},
+  {"0x1.fdca16e04b86dp+195", 309, "99999999999999997168788049560464200849936328366177157906432"},
+  {"0x1.fdca16e04b86ep+195", 309, "100000000000000008319160648825775771617795464690357910896640"},
+  {"0x1.3e9e4e4c2f344p+199", 309, "999999999999999949387135297074018866963645011013410073083904"},
+  {"0x1.3e9e4e4c2f345p+199", 309, "1000000000000000127793096885319003999249391192200302120927232"},
+  {"0x1.8e45e1df3b015p+202", 309, "9999999999999999493871352970740188669636450110134100730839040"},
+  {"0x1.8e45e1df3b016p+202", 309, "10000000000000000921119045676700069727922419559629237113585664"},
+  {"0x1.f1d75a5709c1ap+205", 309, "99999999999999992084218144295482124579792562202350734542897152"},
+  {"0x1.f1d75a5709c1bp+205", 309, "100000000000000003502199685943161173046080317798311825604870144"},
+  {"0x1.3726987666190p+209", 309, "999999999999999875170255276364105051932774599639662981181079552"},
+  {"0x1.3726987666191p+209", 309, "1000000000000000057857959942726969827393378689175040438172647424"},
+  {"0x1.84f03e93ff9f4p+212", 309, "9999999999999998751702552763641050519327745996396629811810795520"},
+  {"0x1.84f03e93ff9f5p+212", 309, "10000000000000000213204190094543968723012578712679649467743338496"},
+  {"0x1.e62c4e38ff872p+215", 309, "99999999999999999209038626283633850822756121694230455365568299008"},
+  {"0x1.e62c4e38ff873p+215", 309, "100000000000000010901051724930857196452234783424494612613028642816"},
+  {"0x1.2fdbb0e39fb47p+219", 309, "999999999999999945322333868247445125709646570021247924665841614848"},
+  {"0x1.2fdbb0e39fb48p+219", 309, "1000000000000000132394543446603018655781305157705474440625207115776"},
+  {"0x1.7bd29d1c87a19p+222", 309, "9999999999999999827367757839185598317239782875580932278577147150336"},
+  {"0x1.7bd29d1c87a1ap+222", 309, "10000000000000001323945434466030186557813051577054744406252071157760"},
+  {"0x1.dac74463a989fp+225", 309, "99999999999999995280522225138166806691251291352861698530421623488512"},
+  {"0x1.dac74463a98a0p+225", 309, "100000000000000007253143638152923512615837440964652195551821015547904"},
+  {"0x1.28bc8abe49f63p+229", 309, "999999999999999880969493773293127831364996015857874003175819882528768"},
+  {"0x1.28bc8abe49f64p+229", 309, "1000000000000000072531436381529235126158374409646521955518210155479040"},
+  {"0x1.72ebad6ddc73cp+232", 309, "9999999999999999192818822949403492903236716946156035936442979371188224"},
+  {"0x1.72ebad6ddc73dp+232", 309, "10000000000000000725314363815292351261583744096465219555182101554790400"},
+  {"0x1.cfa698c95390bp+235", 309, "99999999999999991928188229494034929032367169461560359364429793711882240"},
+  {"0x1.cfa698c95390cp+235", 309, "100000000000000004188152556421145795899143386664033828314342771180699648"},
+  {"0x1.21c81f7dd43a7p+239", 309, "999999999999999943801810948794571024057224129020550531544123892056457216"},
+  {"0x1.21c81f7dd43a8p+239", 309, "1000000000000000139961240179628344893925643604260126034742731531557535744"},
+  {"0x1.6a3a275d49491p+242", 309, "9999999999999999830336967949613257980309080240684656321838454199566729216"},
+  {"0x1.6a3a275d49492p+242", 309, "10000000000000001399612401796283448939256436042601260347427315315575357440"},
+  {"0x1.c4c8b1349b9b5p+245", 309, "99999999999999995164818811802792197885196090803013355167206819763650035712"},
+  {"0x1.c4c8b1349b9b6p+245", 309, "100000000000000007719022282576153725556774937218346187371917708691719061504"},
+  {"0x1.1afd6ec0e1411p+249", 309, "999999999999999926539781176481198923508803215199467887262646419780362305536"},
+  {"0x1.1afd6ec0e1412p+249", 309, "1000000000000000127407036708854983366254064757844793202538020642629466718208"},
+  {"0x1.61bcca7119915p+252", 309, "9999999999999998863663300700064420349597509066704028242075715752105414230016"},
+  {"0x1.61bcca7119916p+252", 309, "10000000000000000470601344959054695891559601407866630764278709534898249531392"},
+  {"0x1.ba2bfd0d5ff5bp+255", 309, "99999999999999998278261272554585856747747644714015897553975120217811154108416"},
+  {"0x1.ba2bfd0d5ff5cp+255", 309, "100000000000000011133765626626508061083444383443316717731599070480153836519424"},
+  {"0x1.145b7e285bf98p+259", 309, "999999999999999802805551768538947706777722104929947493053015898505313987330048"},
+  {"0x1.145b7e285bf99p+259", 309, "1000000000000000008493621433689702976148869924598760615894999102702796905906176"},
+  {"0x1.59725db272f7fp+262", 309, "9999999999999999673560075006595519222746403606649979913266024618633003221909504"},
+  {"0x1.59725db272f80p+262", 309, "10000000000000001319064632327801561377715586164000484896001890252212866570518528"},
+  {"0x1.afcef51f0fb5ep+265", 309, "99999999999999986862573406138718939297648940722396769236245052384850852127440896"},
+  {"0x1.afcef51f0fb5fp+265", 309, "100000000000000000026609864708367276537402401181200809098131977453489758916313088"},
+  {"0x1.0de1593369d1bp+269", 309, "999999999999999921281879895665782741935503249059183851809998224123064148429897728"},
+  {"0x1.0de1593369d1cp+269", 309, "1000000000000000131906463232780156137771558616400048489600189025221286657051852800"},
+  {"0x1.5159af8044462p+272", 309, "9999999999999999634067965630886574211027143225273567793680363843427086501542887424"},
+  {"0x1.5159af8044463p+272", 309, "10000000000000001319064632327801561377715586164000484896001890252212866570518528000"},
+  {"0x1.a5b01b605557ap+275", 309, "99999999999999989600692989521205793443517660497828009527517532799127744739526311936"},
+  {"0x1.a5b01b605557bp+275", 309, "100000000000000003080666323096525690777025204007643346346089744069413985291331436544"},
+  {"0x1.078e111c3556cp+279", 309, "999999999999999842087036560910778345101146430939018748000886482910132485188042620928"},
+  {"0x1.078e111c3556dp+279", 309, "1000000000000000057766609898115896702437267127096064137098041863234712334016924614656"},
+  {"0x1.4971956342ac7p+282", 309, "9999999999999998420870365609107783451011464309390187480008864829101324851880426209280"},
+  {"0x1.4971956342ac8p+282", 309, "10000000000000000146306952306748730309700429878646550592786107871697963642511482159104"},
+  {"0x1.9bcdfabc13579p+285", 309, "99999999999999987659576829486359728227492574232414601025643134376206526100066373992448"},
+  {"0x1.9bcdfabc1357ap+285", 309, "100000000000000001463069523067487303097004298786465505927861078716979636425114821591040"},
+  {"0x1.0160bcb58c16cp+289", 309, "999999999999999959416724456350362731491996089648451439669739009806703922950954425516032"},
+  {"0x1.0160bcb58c16dp+289", 309, "1000000000000000180272607553648403929404183682513265918105226119259073688151729587093504"},
+  {"0x1.41b8ebe2ef1c7p+292", 309, "9999999999999999594167244563503627314919960896484514396697390098067039229509544255160320"},
+  {"0x1.41b8ebe2ef1c8p+292", 309, "10000000000000001361014309341887956898217461639403030224181286973685997351115745547780096"},
+  {"0x1.922726dbaae39p+295", 309, "99999999999999999475366575191804932315794610450682175621941694731908308538307845136842752"},
+  {"0x1.922726dbaae3ap+295", 309, "100000000000000013610143093418879568982174616394030302241812869736859973511157455477800960"},
+  {"0x1.f6b0f092959c7p+298", 309, "999999999999999966484112715463900049825186092620125502979674597309179755437379230686511104"},
+  {"0x1.f6b0f092959c8p+298", 309, "1000000000000000079562324861280497143156226140166910515938643997348793075220176113414176768"},
+  {"0x1.3a2e965b9d81cp+302", 309, "9999999999999998986371854279739417938265620640920544952042929572854117635677011010499117056"},
+  {"0x1.3a2e965b9d81dp+302", 309, "10000000000000000795623248612804971431562261401669105159386439973487930752201761134141767680"},
+  {"0x1.88ba3bf284e23p+305", 309, "99999999999999989863718542797394179382656206409205449520429295728541176356770110104991170560"},
+  {"0x1.88ba3bf284e24p+305", 309, "100000000000000004337729697461918607329029332495193931179177378933611681288968111094132375552"},
+  {"0x1.eae8caef261acp+308", 309, "999999999999999927585207737302990649719308316264031458521789123695552773432097103028194115584"},
+  {"0x1.eae8caef261adp+308", 309, "1000000000000000043377296974619186073290293324951939311791773789336116812889681110941323755520"},
+  {"0x1.32d17ed577d0bp+312", 309, "9999999999999998349515363474500343108625203093137051759058013911831015418660298966976904036352"},
+  {"0x1.32d17ed577d0cp+312", 309, "10000000000000000202188791271559469885760963232143577411377768562080040049981643093586978275328"},
+  {"0x1.7f85de8ad5c4ep+315", 309, "99999999999999987200500490339121684640523551209383568895219648418808203449245677922989188841472"},
+  {"0x1.7f85de8ad5c4fp+315", 309, "100000000000000002021887912715594698857609632321435774113777685620800400499816430935869782753280"},
+  {"0x1.df67562d8b362p+318", 309, "999999999999999931290554592897108903273579836542044509826428632996050822694739791281414264061952"},
+  {"0x1.df67562d8b363p+318", 309, "1000000000000000049861653971908893017010268485438462151574892930611988399099305815384459015356416"},
+  {"0x1.2ba095dc7701dp+322", 309, "9999999999999998838621148412923952577789043769834774531270429139496757921329133816401963635441664"},
+  {"0x1.2ba095dc7701ep+322", 309, "10000000000000000735758738477112498397576062152177456799245857901351759143802190202050679656153088"},
+  {"0x1.7688bb5394c25p+325", 309, "99999999999999999769037024514370800696612547992403838920556863966097586548129676477911932478685184"},
+  {"0x1.7688bb5394c26p+325", 309, "100000000000000014946137745027879167254908695051145297064360294060937596327914127563101660644376576"},
+  {"0x1.d42aea2879f2ep+328", 309, "999999999999999967336168804116691273849533185806555472917961779471295845921727862608739868455469056"},
+  {"0x1.d42aea2879f2fp+328", 309, "1000000000000000088752974568224758206315902362276487138068389220230015924160003471290257693781000192"},
+  {"0x1.249ad2594c37cp+332", 309, "9999999999999998216360018871870109548898901740426374747374488505608317520357971321909184780648316928"},
+  {"0x1.249ad2594c37dp+332", 309, "10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104"},
+  {"0x1.6dc186ef9f45cp+335", 309, "99999999999999997704951326524533662844684271992415000612999597473199345218078991130326129448151154688"},
+  {"0x1.6dc186ef9f45dp+335", 309, "100000000000000013246302464330366230200379526580566253752254309890315515232578269041560411089819140096"},
+  {"0x1.c931e8ab87173p+338", 309, "999999999999999977049513265245336628446842719924150006129995974731993452180789911303261294481511546880"},
+  {"0x1.c931e8ab87174p+338", 309, "1000000000000000101380322367691997167292404756629360031244033674068922812296784134593135547614855430144"},
+  {"0x1.1dbf316b346e7p+342", 309, "9999999999999998029863805218200118740630558685368559709703431956602923480183979986974373400948301103104"},
+  {"0x1.1dbf316b346e8p+342", 309, "10000000000000000019156750857346687362159551272651920111528035145993793242039887559612361451081803235328"},
+  {"0x1.652efdc6018a1p+345", 309, "99999999999999984277223943460294324649363572028252317900683525944810974325551615015019710109750015295488"},
+  {"0x1.652efdc6018a2p+345", 309, "100000000000000000191567508573466873621595512726519201115280351459937932420398875596123614510818032353280"},
+  {"0x1.be7abd3781ecap+348", 309, "999999999999999938258300825281978540327027364472124478294416212538871491824599713636820527503908255301632"},
+  {"0x1.be7abd3781ecbp+348", 309, "1000000000000000065573049346187358932104882890058259544011190816659887156583377798285651762712452391763968"},
+  {"0x1.170cb642b133ep+352", 309, "9999999999999998873324014169198263836158851542376704520077063708904652259210884797772880334204906007166976"},
+  {"0x1.170cb642b133fp+352", 309, "10000000000000000910359990503684350104604539951754865571545457374840902895351334152154180097541612190564352"},
+  {"0x1.5ccfe3d35d80ep+355", 309, "99999999999999996881384047029926983435371269061279689406644211752791525136670645395254002395395884805259264"},
+  {"0x1.5ccfe3d35d80fp+355", 309, "100000000000000013177671857705815673582936776336304977818391361080281530225794240230304400502089534272438272"},
+  {"0x1.b403dcc834e11p+358", 309, "999999999999999903628689227595715073763450661512695740419453520217955231010212074612338431527184250183876608"},
+  {"0x1.b403dcc834e12p+358", 309, "1000000000000000033998991713002824594943974719712898047713430714837875271723200833292741616380733445921308672"},
+  {"0x1.108269fd210cbp+362", 309, "9999999999999999818508707188399807864717650964328171247958398369899072554380053298205803424393137676263358464"},
+  {"0x1.108269fd210ccp+362", 309, "10000000000000001904433546954913560203606035895531408164662033483817793205787873437092254382049924808062271488"},
+  {"0x1.54a3047c694fdp+365", 309, "99999999999999985669538033284915564613846200056062290979362173015478401635353612148739328497990653971840106496"},
+  {"0x1.54a3047c694fep+365", 309, "100000000000000002356936751417025583324953279505688186312991253926828166846616173259830936159244951026231410688"},
+  {"0x1.a9cbc59b83a3dp+368", 309, "999999999999999956819772641641815758405104477258378281795396215622882607621111488153942930947432322044748890112"},
+  {"0x1.a9cbc59b83a3ep+368", 309, "1000000000000000090318962386698695908093961112855385444464428862913680729311211977042675792237466698479879323648"},
+  {"0x1.0a1f5b8132466p+372", 309, "9999999999999999301199346926304397284673331501389768492615896861647229832830913903761963586894254467577228034048"},
+  {"0x1.0a1f5b8132467p+372", 309, "10000000000000001437186382847214479679695037670941883095320419218299999779872521725981689367534804490539314970624"},
+  {"0x1.4ca732617ed7fp+375", 309, "99999999999999984468045325579403643266646490335689226515340879189861218540142707748740732746380344583923932594176"},
+  {"0x1.4ca732617ed80p+375", 309, "100000000000000001555941612946684302426820139692106143336977058043083378116475570326498538991504744767620628086784"},
+  {"0x1.9fd0fef9de8dfp+378", 309, "999999999999999878856245830528597750986812202069726098796681149605056504554092802642922939954052246206632716926976"},
+  {"0x1.9fd0fef9de8e0p+378", 309, "1000000000000000015559416129466843024268201396921061433369770580430833781164755703264985389915047447676206280867840"},
+  {"0x1.03e29f5c2b18bp+382", 309, "9999999999999997968343436511656505870179786851589248980528274911095901385876950622696854699774551253248885785624576"},
+  {"0x1.03e29f5c2b18cp+382", 309, "10000000000000000155594161294668430242682013969210614333697705804308337811647557032649853899150474476762062808678400"},
+  {"0x1.44db473335deep+385", 309, "99999999999999984057935814682588907446802322751135220511621610897383886710310719046874545396497358979515211902353408"},
+  {"0x1.44db473335defp+385", 309, "100000000000000001555941612946684302426820139692106143336977058043083378116475570326498538991504744767620628086784000"},
+  {"0x1.961219000356ap+388", 309, "999999999999999910571381339882270654388094495275235896417637897556636832727766595587241428345003132947573783761256448"},
+  {"0x1.961219000356bp+388", 309, "1000000000000000050555427725995033814228237030803003279020481474722232763977085405824233377105062219252417113236701184"},
+  {"0x1.fb969f40042c5p+391", 309, "9999999999999999665649998943273759183241515094863428494587753284228752052274941196820382078490267674695111155514343424"},
+  {"0x1.fb969f40042c6p+391", 309, "10000000000000000785522370032175864461962655379085567555410501901553519502269491678716317668570740365133857791317901312"},
+  {"0x1.3d3e2388029bbp+395", 309, "99999999999999994416755247254933381274972870380190006824232035607637985622760311004411949604741731366073618283536318464"},
+  {"0x1.3d3e2388029bcp+395", 309, "100000000000000012334713184677367065734511114927744231797396013484834264822673118714746919046029294413093564456393244672"},
+  {"0x1.8c8dac6a0342ap+398", 309, "999999999999999980003468347394201181668805192897008518188648311830772414627428725464789434929992439754776075181077037056"},
+  {"0x1.8c8dac6a0342bp+398", 309, "1000000000000000123347131846773670657345111149277442317973960134848342648226731187147469190460292944130935644563932446720"},
+  {"0x1.efb1178484134p+401", 309, "9999999999999999226660029476424133913982828103448349982745235826237443211877077407917175327178722380043122474279348731904"},
+  {"0x1.efb1178484135p+401", 309, "10000000000000000373409337471459889719393275754491820381027730410378005080671497101378613371421126415052399029342192009216"},
+  {"0x1.35ceaeb2d28c0p+405", 309, "99999999999999983092605830803955292696544699826135736641192401589249937168415416531480248917847991520357012302290741100544"},
+  {"0x1.35ceaeb2d28c1p+405", 309, "100000000000000001440594758724527385583111862242831263013712314935498927069126131626863257625726456080505437183296233537536"},
+  {"0x1.83425a5f872f1p+408", 309, "999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376"},
+  {"0x1.83425a5f872f2p+408", 309, "1000000000000000124493881154768706413150521596928485788372242629432483210095525606840930628504535348165944921118995289997312"},
+  {"0x1.e412f0f768fadp+411", 309, "9999999999999999483531874467312143214394768377282087351960514613084929070487027419252537449089020883885200422613425626021888"},
+  {"0x1.e412f0f768faep+411", 309, "10000000000000000657803165854228757159135066771950601039801789067244864424132513185357050006393242615734699614997777141989376"},
+  {"0x1.2e8bd69aa19ccp+415", 309, "99999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005841365553228283904"},
+  {"0x1.2e8bd69aa19cdp+415", 309, "100000000000000011275116824089954027370311861298180065149382988489088385655907074917988550293149313084744992919515177483763712"},
+  {"0x1.7a2ecc414a03fp+418", 309, "999999999999999924867761618992882042544670869834838461439225972225294199975793026603163493762817653751530058413655532282839040"},
+  {"0x1.7a2ecc414a040p+418", 309, "1000000000000000075174486916518208627471429064352408213482909102357765925242415204664541101097758035428265955038852526326677504"},
+  {"0x1.d8ba7f519c84fp+421", 309, "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772377386949310916067328"},
+  {"0x1.d8ba7f519c850p+421", 309, "10000000000000000751744869165182086274714290643524082134829091023577659252424152046645411010977580354282659550388525263266775040"},
+  {"0x1.27748f9301d31p+425", 309, "99999999999999988278187853568579059876517857536991893086699469578820211690113881674597776370903434688204400735860037395056427008"},
+  {"0x1.27748f9301d32p+425", 309, "100000000000000007517448691651820862747142906435240821348290910235776592524241520466454110109775803542826595503885252632667750400"},
+  {"0x1.7151b377c247ep+428", 309, "999999999999999998217443564185241415988928868759412500436543339729940401905904649497115766142268560009777175966751665376232210432"},
+  {"0x1.7151b377c247fp+428", 309, "1000000000000000152131530268851175838953929259945403926529274864985591448578925759831966436053247510846754734110953387277122797568"},
+  {"0x1.cda62055b2d9dp+431", 309, "9999999999999999366518088823188676468029287122850159299994507296276799832366962053631754981778769796749861527090709766158759755776"},
+  {"0x1.cda62055b2d9ep+431", 309, "10000000000000000597830782460516151851749290252338090708736359498322008205751130936310560341066601403445681992244323541365884452864"},
+  {"0x1.2087d4358fc82p+435", 309, "99999999999999991202555500957231813912852864969525730182461368558677581576901282770959939099212034754106974340599870111173348163584"},
+  {"0x1.2087d4358fc83p+435", 309, "100000000000000010903558599154471420052372915041332632722331003791400915551047984893820824847817340461240101783057690514487343316992"},
+  {"0x1.68a9c942f3ba3p+438", 309, "999999999999999990829567402361276563686608849982484911984092226517669151665599636201042933986541570369602253175829982724989462249472"},
+  {"0x1.68a9c942f3ba4p+438", 309, "1000000000000000148437592187939193412802769250556940132303049308379455823458773253183930019975384016026667272715492545951501423476736"},
+  {"0x1.c2d43b93b0a8bp+441", 309, "9999999999999998962647525310145264542169126096378117797927179774005971485896954660113106823932361029753632414520324447890822855131136"},
+  {"0x1.c2d43b93b0a8cp+441", 309, "10000000000000000223511723594768599335098409300973759560478836428900264860242343595976203511843100595010152570837624953702918544949248"},
+  {"0x1.19c4a53c4e697p+445", 309, "99999999999999992148203649670699315007549827372972461504375111049848301607660324472857261615145089428049364457837845490532419930947584"},
+  {"0x1.19c4a53c4e698p+445", 309, "100000000000000012322030822224672671694418358646502729705201617528156995597186547446666808621716922472153686958914653583525950968037376"},
+  {"0x1.6035ce8b6203dp+448", 309, "999999999999999961829690841814939863449235336276785151445404123455100404055655690676191710164594560368702289580532071091311261383655424"},
+  {"0x1.6035ce8b6203ep+448", 309, "1000000000000000123220308222246726716944183586465027297052016175281569955971865474466668086217169224721536869589146535835259509680373760"},
+  {"0x1.b843422e3a84cp+451", 309, "9999999999999999295515673657285824927502456862391367223240817130898064936724137339180964349540796274981353735788091781425216117243117568"},
+  {"0x1.b843422e3a84dp+451", 309, "10000000000000000586640612700740119755462042863897304388093713545509821352053815609504775357961393589804030375857007499376802103616864256"},
+  {"0x1.132a095ce492fp+455", 309, "99999999999999982626157224225223890651347880611866174913584999992086598044603947229219155428043184231232124237329592070639473281441202176"},
+  {"0x1.132a095ce4930p+455", 309, "100000000000000003284156248920492607898701256635961169551231342625874700689878799554400131562772741268394950478432243557864849063421149184"},
+  {"0x1.57f48bb41db7bp+458", 309, "999999999999999867577570291642776341008185558166851738411142685188442185736589176942553506549890956386646894855501223680845484378371915776"},
+  {"0x1.57f48bb41db7cp+458", 309, "1000000000000000032841562489204926078987012566359611695512313426258747006898787995544001315627727412683949504784322435578648490634211491840"},
+  {"0x1.adf1aea12525ap+461", 309, "9999999999999999006303687311552062886039509598054037298313768334025031499690289406628430683654582476461074168412654660604060856295398309888"},
+  {"0x1.adf1aea12525bp+461", 309, "10000000000000000328415624892049260789870125663596116955123134262587470068987879955440013156277274126839495047843224355786484906342114918400"},
+  {"0x1.0cb70d24b7378p+465", 309, "99999999999999984774589122793531837245072631718372054355900219626000560719712531871037976946055058163097058166404267825310912362767116664832"},
+  {"0x1.0cb70d24b7379p+465", 309, "100000000000000005928380124081487003706362488767045328864850074482999577828473980652023296508018124569151792237293382948229697163514582401024"},
+  {"0x1.4fe4d06de5056p+468", 309, "999999999999999847745891227935318372450726317183720543559002196260005607197125318710379769460550581630970581664042678253109123627671166648320"},
+  {"0x1.4fe4d06de5057p+468", 309, "1000000000000000016976219238238959704141045173573106739630601035115997744067216908958262325956255112879408454231155599236459402033650892537856"},
+  {"0x1.a3de04895e46cp+471", 309, "9999999999999999154380224320567749051268538597394750219876417318024024619451619548095327920588323941303457306908878466464492349900630570041344"},
+  {"0x1.a3de04895e46dp+471", 309, "10000000000000000508222848402996879704791089448509839788449208028871961714412352270078388372553960191290960287445781834331294577148468377157632"},
+  {"0x1.066ac2d5daec3p+475", 309, "99999999999999980713061250546244445284504979165026785650181847493456749434830333705088795590158149413134549224793557721710505681023603243483136"},
+  {"0x1.066ac2d5daec4p+475", 309, "100000000000000002374543235865110535740865792782868218747346498867023742954202057256817762821608329412934596913384011607579341316989008157343744"},
+  {"0x1.4805738b51a74p+478", 309, "999999999999999850453576476100176633757771418885950722696147777681701481387046784154345890364481854130945587625116484988842728082166842262552576"},
+  {"0x1.4805738b51a75p+478", 309, "1000000000000000023745432358651105357408657927828682187473464988670237429542020572568177628216083294129345969133840116075793413169890081573437440"},
+  {"0x1.9a06d06e26112p+481", 309, "9999999999999999890870611821409196126784806260401358945180015464725302399110258148854112806457630061296658928320953898584032761523454337112604672"},
+  {"0x1.9a06d06e26113p+481", 309, "10000000000000001277205458881816625915991898331943210663398553152633589984350048456164766709270441581283861980390742947279638242225240251599683584"},
+  {"0x1.00444244d7cabp+485", 309, "99999999999999993363366729972462242111019694317846182578926003895619873650143420259298512453325054533017777074930382791057905692427399713177731072"},
+  {"0x1.00444244d7cacp+485", 309, "100000000000000015544724282938981118738333167462515810070422606902152475013980065176268974898330038852813025908047007570187593383655974344970993664"},
+  {"0x1.405552d60dbd6p+488", 309, "999999999999999977996382405657660174364823889467801080772253244969263939229107492426926049423260513969768268415537077468838432306731146395363835904"},
+  {"0x1.405552d60dbd7p+488", 309, "1000000000000000155447242829389811187383331674625158100704226069021524750139800651762689748983300388528130259080470075701875933836559743449709936640"},
+  {"0x1.906aa78b912cbp+491", 309, "9999999999999999070160382361647997691574207754048582727994641153483596148648302286926205695992445641464234721495638781756234316947997075736253956096"},
+  {"0x1.906aa78b912ccp+491", 309, "10000000000000000489767265751505205795722270035307438887450423745901682635933847561612315292472764637931130646815102767620534329186625852171022761984"},
+  {"0x1.f485516e7577ep+494", 309, "99999999999999993540817590396194393124038202103003539598857976719672134461054113418634276152885094407576139065595315789290943193957228310232077172736"},
+  {"0x1.f485516e7577fp+494", 309, "100000000000000004897672657515052057957222700353074388874504237459016826359338475616123152924727646379311306468151027676205343291866258521710227619840"},
+  {"0x1.38d352e5096afp+498", 309, "999999999999999980835596172437374590573120014030318793091164810154100112203678582976298268616221151962702060266176005440567032331208403948233373515776"},
+  {"0x1.38d352e5096b0p+498", 309, "1000000000000000162545277246339097227904071986031452381501504981983615182576228378136120296965701983510464738707067395631197433897752887331883780669440"},
+  {"0x1.8708279e4bc5ap+501", 309, "9999999999999998718097875280963410081745488308296386400449607070563910699801487058804050516065326530340444532016411713261887913912817139180431292235776"},
+  {"0x1.8708279e4bc5bp+501", 309, "10000000000000000171775323872177191180393104084305455107732328445200031262781885420082626742861173182722545959543542834786931126445173006249634549465088"},
+  {"0x1.e8ca3185deb71p+504", 309, "99999999999999992995688547174489225212045346187000138833626956204183589249936464033154810067836651912932851030272641618719051989257594860081125951275008"},
+  {"0x1.e8ca3185deb72p+504", 309, "100000000000000004625108135904199474001226272395072688491888727201272553753779650923383419882203425131989662450489690590919397689516441796634752009109504"},
+  {"0x1.317e5ef3ab327p+508", 309, "999999999999999999733403004123153744855539019118436686285840188024369679522423761672919759564567158443669378824028710020392594094129030220133015859757056"},
+  {"0x1.317e5ef3ab328p+508", 309, "1000000000000000185804116423798517725482433838447597480818028523977793111583914751916577516594435529948578361547501493575598125298270581204991032785108992"},
+  {"0x1.7dddf6b095ff0p+511", 309, "9999999999999998880909749523179353564794021275209402095665271864523156202855291675267251053466461355407239891899450398872692753716440996292182057045458944"},
+  {"0x1.7dddf6b095ff1p+511", 309, "10000000000000000369475456880582265409809179829842688451922778552150543659347219597216513109705408327446511753687232667314337003349573404171046192448274432"},
+  {"0x1.dd55745cbb7ecp+514", 309, "99999999999999988809097495231793535647940212752094020956652718645231562028552916752672510534664613554072398918994503988726927537164409962921820570454589440"},
+  {"0x1.dd55745cbb7edp+514", 309, "100000000000000000717623154091016830408061481189160311806712772146250661680488340128266606984576189330386573813296762136260081534229469225952733653677113344"},
+  {"0x1.2a5568b9f52f4p+518", 309, "999999999999999983359180223191721714560372275017470536367007614460468417501012554531477876945938741751237388344363105067534507348164573733465510370326085632"},
+  {"0x1.2a5568b9f52f5p+518", 309, "1000000000000000173895590764939294430722312570010531189967968470476774011931979328540983420144523954172264186653199235428064971301205521941960119701886468096"},
+  {"0x1.74eac2e8727b1p+521", 309, "9999999999999999833591802231917217145603722750174705363670076144604684175010125545314778769459387417512373883443631050675345073481645737334655103703260856320"},
+  {"0x1.74eac2e8727b2p+521", 309, "10000000000000001357883086565897798874899245110119190592477762992735128930457859737390823115048069116880588269914320093559588785105973323002611978355743916032"},
+  {"0x1.d22573a28f19dp+524", 309, "99999999999999995287335453651211007997446182781858083179085387749785952239205787068995699003416510776387310061494932420984963311567802202010637287727642443776"},
+  {"0x1.d22573a28f19ep+524", 309, "100000000000000007481665728323055661831810361661413965009546882534829510282787660605604053768125964371333025153260444764058913004562422887354292284947506921472"},
+  {"0x1.2357684599702p+528", 309, "999999999999999928484693987168420772305733470059469068129930887927772406304894123616740280504746200573981670431418299523701733729688780649419062882836695482368"},
+  {"0x1.2357684599703p+528", 309, "1000000000000000123593978381917935233655560332132363177417314804488469335002204100202473956740097458093113111899666497012884928817602711614917542838354527125504"},
+  {"0x1.6c2d4256ffcc2p+531", 309, "9999999999999998504409802292686149877658027252303114244149773213034936348259701329824468100106056975663290938441190205280284556945232082632196709006295628251136"},
+  {"0x1.6c2d4256ffcc3p+531", 309, "10000000000000000065284077450682265568456642148886267118448844545520511777838181142510337509988867035816342470187175785193750117648543530356184548650438281396224"},
+  {"0x1.c73892ecbfbf3p+534", 309, "99999999999999991287595123558845961539774732109363753938694017460291665200910932548988158640591809997245115511395844372456707812265566617217918448639526895091712"},
+  {"0x1.c73892ecbfbf4p+534", 309, "100000000000000003774589324822814887066163651282028976933086588120176268637538771050475113919654290478469527765363729011764432297892058199009821165792668120252416"},
+  {"0x1.1c835bd3f7d78p+538", 309, "999999999999999937849939638116397466450525159438967985375725315922685858882365002492855496964043060934899979621894213003182527093908649335762989920701551401238528"},
+  {"0x1.1c835bd3f7d79p+538", 309, "1000000000000000137641846858339900274872747866201611553286006446480839513868410418516646781429042748634490575685380367232106118863932514644433433395151811003809792"},
+  {"0x1.63a432c8f5cd6p+541", 309, "9999999999999999378499396381163974664505251594389679853757253159226858588823650024928554969640430609348999796218942130031825270939086493357629899207015514012385280"},
+  {"0x1.63a432c8f5cd7p+541", 309, "10000000000000000976834654142951997131883033248490828397039502203692087828712013353118885245360428110945724564726831363863214005099277415826993447002617590832955392"},
+  {"0x1.bc8d3f7b3340bp+544", 309, "99999999999999987391652932764487656775541389327492204364443535414407668928683046936524228593524316087103098888157864364992697772750101243698844800887746832841572352"},
+  {"0x1.bc8d3f7b3340cp+544", 309, "100000000000000000178334994858791836514563642560301392710701527770129502847789953562046870799284296099876897036220978235643807646031628623453753183252563447406133248"},
+  {"0x1.15d847ad00087p+548", 309, "999999999999999899489893451833484927233458399740540420336951338855520357125044282616287570346763120896578585177704871391229197474064067196498264773607101557544845312"},
+  {"0x1.15d847ad00088p+548", 309, "1000000000000000104076806445342351803057814451465487433877079216547069699830754788624649845638922801100959355546714693321646955446568505272576798891444167390577819648"},
+  {"0x1.5b4e5998400a9p+551", 309, "9999999999999999404072760505352583023983296100855298230449769143938302256661863838179600254051950569374547392515068357773127490685649548117139715971745147241514401792"},
+  {"0x1.5b4e5998400aap+551", 309, "10000000000000001040768064453423518030578144514654874338770792165470696998307547886246498456389228011009593555467146933216469554465685052725767988914441673905778196480"},
+  {"0x1.b221effe500d3p+554", 309, "99999999999999990767336997157383960226643264180953830087855645396318233083327270285662206135844950810475381599246526426844590779296424471954140613832058419086616428544"},
+  {"0x1.b221effe500d4p+554", 309, "100000000000000003860899428741951440279402051491350438954423829568577391016492742670197391754543170343555750902863155030391327289536708508823166797373630632400726786048"},
+  {"0x1.0f5535fef2084p+558", 309, "999999999999999933860494834742974562371950216430331518611692822307700646699603647625692432595845947170914554599698521475539380813444812793279458505403728617494385000448"},
+  {"0x1.0f5535fef2085p+558", 309, "1000000000000000143357493740096054243216090813396677260476783769063847173630251205778255402495017459700200463457564579132287164977289357383183877442068884030520150720512"},
+  {"0x1.532a837eae8a5p+561", 309, "9999999999999999338604948347429745623719502164303315186116928223077006466996036476256924325958459471709145545996985214755393808134448127932794585054037286174943850004480"},
+  {"0x1.532a837eae8a6p+561", 309, "10000000000000001014580939590254383070472626940034081121037655797126178682441216941477428085151831571943432816859913676009376081445204484652029936547358529479149975764992"},
+  {"0x1.a7f5245e5a2cep+564", 309, "99999999999999990034097500988648181343688772091571619991327827082671720239070003832128235741197850516622880918243995225045973534722968565889475147553730375141026248523776"},
+  {"0x1.a7f5245e5a2cfp+564", 309, "100000000000000003441905430931245280917713770297417747470693647675065097962631447553892265814744827318497179085147422915077831721209019419643357959500300321574675254607872"},
+  {"0x1.08f936baf85c1p+568", 309, "999999999999999953972206729656870211732987713739100709830741553196290713284945813208338477706166412373726001850053663010587168093173889073910282723323583537144858509574144"},
+  {"0x1.08f936baf85c2p+568", 309, "1000000000000000168497133608738423804917387685032638749500594682674584756861928912756562958882918041203714772520508506051096899076950702733972407714468702680083242606919680"},
+  {"0x1.4b378469b6731p+571", 309, "9999999999999999110672213538405594930961077194803931018967709273006319045695491932986935814708160866077282477159626944024852218964185263418978577250945597085571816901050368"},
+  {"0x1.4b378469b6732p+571", 309, "10000000000000000826871628571058023676436276965152235336326534308832671394311356729372731664122173896717192642523265688348930066834399772699475577180106550229078889679814656"},
+  {"0x1.9e056584240fdp+574", 309, "99999999999999987674323305318751091818660372407342701554959442658410485759723189737097766448253582599493004440868991951600366493901423615628791772651134064568704023452975104"},
+  {"0x1.9e056584240fep+574", 309, "100000000000000001403918625579970521782461970570129136093830042945021304548650108108184133243565686844612285763778101906192989276863139689872767772084421689716760605683089408"},
+  {"0x1.02c35f729689ep+578", 309, "999999999999999849284042412665072058259000527747854146471853226010883220019378060628804930891911617504691481762871699606818419373090804007799965727644765395390927070069522432"},
+  {"0x1.02c35f729689fp+578", 309, "1000000000000000068957567536844582937679826098352437099093782830596656320642208754566186799616905285426599982929417458880300383900478261195703581718577367397759832385751351296"},
+  {"0x1.4374374f3c2c6p+581", 309, "9999999999999999371534524623368764100273307559896873275206250678451924602685103382037576783819090846734548822294900033162112051840457868829614121240178061963384891963422539776"},
+  {"0x1.4374374f3c2c7p+581", 309, "10000000000000001128922725616804851135639912124733536896181687515138109407667748933536631733619040190109816831627266107349967768059557526332843049167638877982336134488877170688"},
+  {"0x1.945145230b377p+584", 309, "99999999999999986685792442259943292861266657339622078268160759437774506806920451614379548038991111093844416185619536034869697653528180058283225500691937355558043949532406874112"},
+  {"0x1.945145230b378p+584", 309, "100000000000000000744898050207431989144199493858315387235964254131263985246781616026371987637390705840846560260278464628372543383280977318309056924111623883709653889736043921408"},
+  {"0x1.f965966bce055p+587", 309, "999999999999999894976135638494410321178532246433607400617214583764724024948926844967780359586710300432448450005513217535702667994787395102883917853758746611883659375731342835712"},
+  {"0x1.f965966bce056p+587", 309, "1000000000000000007448980502074319891441994938583153872359642541312639852467816160263719876373907058408465602602784646283725433832809773183090569241116238837096538897360439214080"},
+  {"0x1.3bdf7e0360c35p+591", 309, "9999999999999998724815666657784284071258397080036981062687289922551408594451489819085924562292709488372450194860589317860981148271829194868425875762872481668410834714055235600384"},
+  {"0x1.3bdf7e0360c36p+591", 309, "10000000000000000524381184475062837195473800154429724610566137243318061834753718863820956830887857615988724636416932177829345401680187244151732297960592357271816907060120777654272"},
+  {"0x1.8ad75d8438f43p+594", 309, "99999999999999998045549773481514159457876389246726271914145983150114005386328272459269439234497983649422148597943950338419997003168440244384097290815044070304544781216945608327168"},
+  {"0x1.8ad75d8438f44p+594", 309, "100000000000000012442073916019742584451599613841868220297176761716247231308746104817149697383259168670352344130394693218166911030435304638650548668396803075131793359985469944758272"},
+  {"0x1.ed8d34e547313p+597", 309, "999999999999999894076352879585771044616424544896411028843275160104340698328775730445412843452412726368640312784735046105718485868083216078242264642659886674081956339558310064685056"},
+  {"0x1.ed8d34e547314p+597", 309, "1000000000000000009248546019891598444566210341657546615907521388633406505708118389308454908642502206536081877044340989143693798086218131232373875663313958712699944969706504756133888"},
+  {"0x1.3478410f4c7ecp+601", 309, "9999999999999999171107915076469365246063817042486381462561244058101538598046442622180212564904306224021286256366562347133135483117101991090685868467907010818055540655879490029748224"},
+  {"0x1.3478410f4c7edp+601", 309, "10000000000000001013863005321362603645260389790664550855589183714566591516115925163988885607945737906700351284520257435740740478607260633556791644798372163435943358738250605092929536"},
+  {"0x1.819651531f9e7p+604", 309, "99999999999999991711079150764693652460638170424863814625612440581015385980464426221802125649043062240212862563665623471331354831171019910906858684679070108180555406558794900297482240"},
+  {"0x1.819651531f9e8p+604", 309, "100000000000000006453119872723839559654210752410289169769835957832735809325020286556271509993374515701645382788895184180192194795092289050635704895322791329123657951217763820802932736"},
+  {"0x1.e1fbe5a7e7861p+607", 309, "999999999999999946594872951565228338993526868219488856544571440313594706493755982886960025179093529324993666087115356131035228239552737388526279268078143523691759154905886843985723392"},
+  {"0x1.e1fbe5a7e7862p+607", 309, "1000000000000000064531198727238395596542107524102891697698359578327358093250202865562715099933745157016453827888951841801921947950922890506357048953227913291236579512177638208029327360"},
+  {"0x1.2d3d6f88f0b3cp+611", 309, "9999999999999998286585471758920610814449462123360860153907833022998313197373091002112049504244419016335335042852788704601485085281825842706955095829283737561469387976341354799421194240"},
+  {"0x1.2d3d6f88f0b3dp+611", 309, "10000000000000000173566684169691286935226752617495305612368443231218527385476241124924130700318845059398697631682172475335672600663748292592247410791680053842186513692689376624118857728"},
+  {"0x1.788ccb6b2ce0cp+614", 309, "99999999999999997961704416875371517110712945186684165206763211895744845478556111003617144611039598507860251139162957211888350975873638026151889477992007905860430885494197722591793250304"},
+  {"0x1.788ccb6b2ce0dp+614", 309, "100000000000000013057554116161536926076931269139759728874448093561506558983381311986113794179635006852367151849798027377761851098929017625234227997691178436106167891224981897189374558208"},
+  {"0x1.d6affe45f818fp+617", 309, "999999999999999979617044168753715171107129451866841652067632118957448454785561110036171446110395985078602511391629572118883509758736380261518894779920079058604308854941977225917932503040"},
+  {"0x1.d6affe45f8190p+617", 309, "1000000000000000100383841763043038442836876043491446161409111172283542162824162717896144642659159251834657717076710133445871510743179417054177602937513443300570204900788250622698582966272"},
+  {"0x1.262dfeebbb0f9p+621", 309, "9999999999999999071569656121801212080692814968920789464627446869617922299624001453201875281811380250249693879805812353226907091680705581859236698853640605134247712274342131878495422251008"},
+  {"0x1.262dfeebbb0fap+621", 309, "10000000000000001003838417630430384428368760434914461614091111722835421628241627178961446426591592518346577170767101334458715107431794170541776029375134433005702049007882506226985829662720"},
+  {"0x1.6fb97ea6a9d37p+624", 309, "99999999999999986851159038200753776111576258757220550347347138989744224339004763080499610528553377966303172216135545569805454885304878641227288327493418395599568449276340570087973407686656"},
+  {"0x1.6fb97ea6a9d38p+624", 309, "100000000000000002309309130269787154892983822485169927543056457815484218967945768886576179686795076111078238543825857419659919011313587350687602971665369018571203143144663564875896666980352"},
+  {"0x1.cba7de5054485p+627", 309, "999999999999999899427890566145604518678577715028104257864890027548922232647929642417149243602017175952581854816736079397763477105066203831193512563278085201938953880500051690455580595453952"},
+  {"0x1.cba7de5054486p+627", 309, "1000000000000000023093091302697871548929838224851699275430564578154842189679457688865761796867950761110782385438258574196599190113135873506876029716653690185712031431446635648758966669803520"},
+  {"0x1.1f48eaf234ad3p+631", 309, "9999999999999998746948504188351511126283256130633852543517551174277382412416240331274267329488304589209417486924315804379963345034522698960570091326029642051843383703107348987949033805840384"},
+  {"0x1.1f48eaf234ad4p+631", 309, "10000000000000000725591715973187783610303424287811372824568343983972101724920689074452068181743241951740625976868675721161334753163637413771490365780039321792212624518252692320803210995433472"},
+  {"0x1.671b25aec1d88p+634", 309, "99999999999999991426771465453187656230872897620693565997277097362163262749171300799098274999392920617156591849131877877362376266603456419227541462168315779999172318661364176545198692437590016"},
+  {"0x1.671b25aec1d89p+634", 309, "100000000000000007255917159731877836103034242878113728245683439839721017249206890744520681817432419517406259768686757211613347531636374137714903657800393217922126245182526923208032109954334720"},
+  {"0x1.c0e1ef1a724eap+637", 309, "999999999999999914267714654531876562308728976206935659972770973621632627491713007990982749993929206171565918491318778773623762666034564192275414621683157799991723186613641765451986924375900160"},
+  {"0x1.c0e1ef1a724ebp+637", 309, "1000000000000000040900880208761398001286019738266296957960021713442094663491997727554362004538245197373563261847757813447631532786297905940174312186739777303375354598782943738754654264509857792"},
+  {"0x1.188d357087712p+641", 309, "9999999999999998636144484328400679867178126713831911407778706776934478130915991201656310481762028096907669811487431649040206546179292274931158555956605099986382706217459209761309199883223171072"},
+  {"0x1.188d357087713p+641", 309, "10000000000000000662275133196073022890814778906781692175574718614061870706920546714670378554471083956139627305190456203824330868103505742897540916997511012040520808812168041334151877325366493184"},
+  {"0x1.5eb082cca94d7p+644", 309, "99999999999999994465967438754696170766327875910118237148971115117854351613178134068619377108456504406004528089686414709538562749489776621177115003729674648080379472553427423904462708600804999168"},
+  {"0x1.5eb082cca94d8p+644", 309, "100000000000000010675012629696074914955421093453716483291339209814873492221214578172731921690128951279860188039310611147811557324883484364908173892056921944513484293311098076487204128137951576064"},
+  {"0x1.b65ca37fd3a0dp+647", 309, "999999999999999977077764769429719196041465194188378863774447340572581797347854228894418860247909937807756600796112539971931616645685181699233267813951241073670004367049615544210109925082343145472"},
+  {"0x1.b65ca37fd3a0ep+647", 309, "1000000000000000106750126296960749149554210934537164832913392098148734922212145781727319216901289512798601880393106111478115573248834843649081738920569219445134842933110980764872041281379515760640"},
+  {"0x1.11f9e62fe4448p+651", 309, "9999999999999999511432924639235132053389160461186216699466583890573511723749959183278387889172340228095875448767138256706948253250552493092635735926276453993770366538373425000777236538229086224384"},
+  {"0x1.11f9e62fe4449p+651", 309, "10000000000000001586190709079731611309593092306766792205689700011791961721578624028604793595626413427949399922319035400805891558900947084290211273632164107937207783595355268531368138238983848067072"},
+  {"0x1.56785fbbdd55ap+654", 309, "99999999999999995114329246392351320533891604611862166994665838905735117237499591832783878891723402280958754487671382567069482532505524930926357359262764539937703665383734250007772365382290862243840"},
+  {"0x1.56785fbbdd55bp+654", 309, "100000000000000011712391521916323154583523059376506771044450767875482717220128910595395124543355987879786950276086559719861028977708681660506961660909865771485203001839588998252499578988328956985344"},
+  {"0x1.ac1677aad4ab0p+657", 309, "999999999999999884751043361827625869140390227060043253747518673178360772444478643277393806310703680414274761723053117059528639544242622390941156386039240473187039308013923507098814799398756243472384"},
+  {"0x1.ac1677aad4ab1p+657", 309, "1000000000000000017535541566019400541537441865177200086145798104936341572305513193378283771523764365204900328030374534281861011105867876227585990799216050325567033999660761493056632508247061001404416"},
+  {"0x1.0b8e0acac4eaep+661", 309, "9999999999999998847510433618276258691403902270600432537475186731783607724444786432773938063107036804142747617230531170595286395442426223909411563860392404731870393080139235070988147993987562434723840"},
+  {"0x1.0b8e0acac4eafp+661", 309, "10000000000000000972062404885344653449756728480474941855847657639911300522221339234388177506516007760792756678147673846152604340428430285295728914471221362369950308146488642846313231335560438561636352"},
+  {"0x1.4e718d7d7625ap+664", 309, "99999999999999996973312221251036165947450327545502362648241750950346848435554075534196338404706251868027512415973882408182135734368278484639385041047239877871023591066789981811181813306167128854888448"},
+  {"0x1.4e718d7d7625bp+664", 309, "100000000000000013969727991387583324014272937224498437195221518215368390817766497947110253951978019521227584903311023812640679294256310975729923845933871538975662911597585244013782480038750137870188544"},
+  {"0x1.a20df0dcd3af0p+667", 309, "999999999999999901747459131964173027207212836739039328294498440443382314826691065690307721857975448067474834210390258463987183104130654882031695190925872134291678628544718769301415466131339252487684096"},
+  {"0x1.a20df0dcd3af1p+667", 309, "1000000000000000037718785293056550291741793714171007924670336578563554653884390444993619046236149589293075414109087389699655531583234914810756005630018925423128793192791080866922220799992003324610084864"},
+  {"0x1.0548b68a044d6p+671", 309, "9999999999999999017474591319641730272072128367390393282944984404433823148266910656903077218579754480674748342103902584639871831041306548820316951909258721342916786285447187693014154661313392524876840960"},
+  {"0x1.0548b68a044d7p+671", 309, "10000000000000001193015809897119766504625422406301890824958394614356580573190100725756058408630540740284357620483056684410565406706974707679905918934747573964310619313388981254947040003084017678835253248"},
+  {"0x1.469ae42c8560cp+674", 309, "99999999999999998876910787506329447650934459829549922997503484884029261182361866844442696946000689845185920534555642245481492613075738123641525387194542623914743194966239051177873087980216425864602058752"},
+  {"0x1.469ae42c8560dp+674", 309, "100000000000000016281240536126153737511360812140841903333610766563411320581747387395266546466406979922062794761588875043647041218401083394518237123398453444885893859189773399673336170714381427096269357056"},
+  {"0x1.98419d37a6b8fp+677", 309, "999999999999999988769107875063294476509344598295499229975034848840292611823618668444426969460006898451859205345556422454814926130757381236415253871945426239147431949662390511778730879802164258646020587520"},
+  {"0x1.98419d37a6b90p+677", 309, "1000000000000000128003745864021888795392755416785835072663893102275349087018702832851017765623257219066874199161822284840139314973360143403428947761576712806916637263450665299742435541675484268499358973952"},
+  {"0x1.fe52048590672p+680", 309, "9999999999999999052283250816881378851792981072012977243617198967792587267065681698004724917620567060828502090557969050236202928251957239362070375381666542984859087613894256390005080826781722527340175556608"},
+  {"0x1.fe52048590673p+680", 309, "10000000000000000166160354728550133402860267619935663985128064995273039068626355013257451286926569625748622041088095949318798038992779336698179926498716835527012730124200454693714718121768282606166882648064"},
+  {"0x1.3ef342d37a407p+684", 309, "99999999999999986067324092522138770313660664528439025470128525568004065464414123719036343698981660348604541103459182906031648839556284004276265549348464259679976306097717770685212259087870984958094927200256"},
+  {"0x1.3ef342d37a408p+684", 309, "100000000000000003889357755108838843130737249295202013334302382007691294289384896763079965607877701387326460311941213291353170611409437561654018367221268940354434586262616943544566455807655946219322240663552"},
+  {"0x1.8eb0138858d09p+687", 309, "999999999999999896317308250394787848770759814817916230429632968559415112294082783278450680807608685563489249451555889830959531939269147157518161129230251958148679621306976052570830984318279772103403898929152"},
+  {"0x1.8eb0138858d0ap+687", 309, "1000000000000000038893577551088388431307372492952020133343023820076912942893848967630799656078777013873264603119412132913531706114094375616540183672212689403544345862626169435445664558076559462193222406635520"},
+  {"0x1.f25c186a6f04cp+690", 309, "9999999999999999818630698308109481982927274216983785721776674794699138106539424938898600659703096825493544616522696356805028364441642842329313746550197144253860793660984920822957311285732475861572950035529728"},
+  {"0x1.f25c186a6f04dp+690", 309, "10000000000000000959240852713658286643220175642056616945083801606839120751337554413717392461872443451971747445865546301465605757840244670001489926894056643817026123591538467885955979875798713382291498097180672"},
+  {"0x1.37798f428562fp+694", 309, "99999999999999989061425747836704382546929530769255207431309733449871519907009213590435672179676195243109823530484164010765664497227613801915728022751095446033285297165420831725583764136794858449981115862089728"},
+  {"0x1.37798f4285630p+694", 309, "100000000000000007311188218325485257111615953570420507004223762444111242223779285187536341014385741266761068799969763125334902791605243044670546908252847439043930576054277584733562461577854658781477884848504832"},
+  {"0x1.8557f31326bbbp+697", 309, "999999999999999927113782419344605574598668153294882673458925392487194643703632279098558059466181044478400725843812838336795121561031396504666917998514458446354143529431921823271795036250068185162804696593727488"},
+  {"0x1.8557f31326bbcp+697", 309, "1000000000000000073111882183254852571116159535704205070042237624441112422237792851875363410143857412667610687999697631253349027916052430446705469082528474390439305760542775847335624615778546587814778848485048320"},
+  {"0x1.e6adefd7f06aap+700", 309, "9999999999999999563134023721266549739021664297767471527755878388779781994104643936539191296017163181162427182749897969201059028320356032930746282153172616351711759756540926280845609521557638656931995269719916544"},
+  {"0x1.e6adefd7f06abp+700", 309, "10000000000000000731118821832548525711161595357042050700422376244411124222377928518753634101438574126676106879996976312533490279160524304467054690825284743904393057605427758473356246157785465878147788484850483200"},
+  {"0x1.302cb5e6f642ap+704", 309, "99999999999999990959401044767537593501656918740576398586892792465272451027953301036534141738485988029569553038510666318680865279842887243162229186843277653306392406169861934038413548670665077684456779836676898816"},
+  {"0x1.302cb5e6f642bp+704", 309, "100000000000000009647157814548049209055895815688969665349556758155373926680325854351965226625228563157788428194463919811999765293285579587743163725597071694149293171752051249118583734850310313223909471278765965312"},
+  {"0x1.7c37e360b3d35p+707", 309, "999999999999999984345037526797422397233524775199337052919583787413130412889023223627065756931830180808571031008919677160084252852199641809946030023447952696435527124027376600704816231425231719002378564135125254144"},
+  {"0x1.7c37e360b3d36p+707", 309, "1000000000000000133847091685041515321667435950786483187020895512933942218108003650150514436025770781834322032256545705106635452959741180566593506333478305023178733248684891121346177720862393603318000095671837786112"},
+  {"0x1.db45dc38e0c82p+710", 309, "9999999999999999544446266951486038123467425400819078260993214423089680518452271383223760211130420606034208307593944715707740128306913340586165347614418822310868858990958736965765439335377993421392542578277827477504"},
+  {"0x1.db45dc38e0c83p+710", 309, "10000000000000000740462700217438781518938714805516247333803708227256174960204114795411349643881945414240216317574952939280149729167245650639345158094661640924814507988218853130896331250875288495917514830571527733248"},
+  {"0x1.290ba9a38c7d1p+714", 309, "99999999999999990660396936451049407652789096389402106318690169014230827417515340183487244380298106827518051036015414262787762879627804165648934234223216948652905993920546904997130825691790753915825536773603473752064"},
+  {"0x1.290ba9a38c7d2p+714", 309, "100000000000000009796659868706293301980329726864556811483658069880894738485544834778488675304322503758814179195711545839946316493393121126499811201907102046476036377876708763639225096339747475108225092810302677843968"},
+  {"0x1.734e940c6f9c5p+717", 309, "999999999999999868331443500000006287872809702943711652856965888408980452039094412644869581954932274412588254040761879473560521568747407734787588406864399290882799171293145332687119715621994096773456255662636329336832"},
+  {"0x1.734e940c6f9c6p+717", 309, "1000000000000000021421546958041957442493134746744949294176709095342291740583330369404881029347127449862957279318330932090828950478869943421594604148335480073467842242942440201823873880805647866312652703956229962072064"},
+  {"0x1.d022390f8b837p+720", 309, "9999999999999999601855055748251769806450047292244542376488118125689672251656359867008764503902493796828096692073033110439215789148209291468717978517470477604338250142827222541691722147321863584969741246387925089779712"},
+  {"0x1.d022390f8b838p+720", 309, "10000000000000000826575883412587379043412647642654443507046063781156162560010247521088856083040055200431048894293585531377363220429189576963174104449239123865018594716021581494785755468791093741283312832736674151661568"},
+  {"0x1.221563a9b7322p+724", 309, "99999999999999988670225591496504042642724870819986016981533507324097780666440272745607095564199569546663253707407016578763273303796211201720443029584092898479300433989106071698353021544403254911815982945786756526505984"},
+  {"0x1.221563a9b7323p+724", 309, "100000000000000008265758834125873790434126476426544435070460637811561625600102475210888560830400552004310488942935855313773632204291895769631741044492391238650185947160215814947857554687910937412833128327366741516615680"},
+  {"0x1.6a9abc9424febp+727", 309, "999999999999999965084388885482519417592855130626093842171043595190833186399051537317196816706799625297221478016185520727674168639944850288849622355474122345476546392575499689981548348018063279122228410984187505225498624"},
+  {"0x1.6a9abc9424fecp+727", 309, "1000000000000000121848654826517477399924067975478561186882460639090543945868349157039448538836407484958399359900416230607757039843910326832140006474740509066843630497944377635977584613166124739130365574036827385146376192"},
+  {"0x1.c5416bb92e3e6p+730", 309, "9999999999999999964372420736895110140590976995965873111133270039707753382929110612616471611327211972294570543930316627036907428807379455975076991793273996897499632136492752791807556010476755711238558435947154812096741376"},
+  {"0x1.c5416bb92e3e7p+730", 309, "10000000000000001218486548265174773999240679754785611868824606390905439458683491570394485388364074849583993599004162306077570398439103268321400064747405090668436304979443776359775846131661247391303655740368273851463761920"},
+  {"0x1.1b48e353bce6fp+734", 309, "99999999999999984594354677029595135102113336853821866019036664182705300920238534632828550788829765195472628778417018121881118652493108811594893042483166843723756247249515245102456078650553656951604416706418119648563167232"},
+  {"0x1.1b48e353bce70p+734", 309, "100000000000000004660180717482069756840508580994937686142098045801868278132308629957276771221419571232103397659598548986531726166600689809136062209749264344058743012736731622189948720589505523832645973577156024278435495936"},
+  {"0x1.621b1c28ac20bp+737", 309, "999999999999999886075198851200900594497923856820450300436489405065378963626525536977181948753477264027987825546533242948112401553146250111031268759363863437907536003469585205199546070383440303278127280805657005745376329728"},
+  {"0x1.621b1c28ac20cp+737", 309, "1000000000000000046601807174820697568405085809949376861420980458018682781323086299572767712214195712321033976595985489865317261666006898091360622097492643440587430127367316221899487205895055238326459735771560242784354959360"},
+  {"0x1.baa1e332d728ep+740", 309, "9999999999999999181805205159248599892793562474462356126333876156560397271658376894962991014456209536865970557564236923315533735757183797070971394269896194384435148282491314085395342974857632902877937717988376531531720556544"},
+  {"0x1.baa1e332d728fp+740", 309, "10000000000000000466018071748206975684050858099493768614209804580186827813230862995727677122141957123210339765959854898653172616660068980913606220974926434405874301273673162218994872058950552383264597357715602427843549593600"},
+  {"0x1.14a52dffc6799p+744", 309, "99999999999999996954903517948319502092964807244749211214842475260109694882873713352688654575305085714037182409224841134505892881183378706080253249519082903930108094789640533388351546084948006950326015738792668900564521713664"},
+  {"0x1.14a52dffc679ap+744", 309, "100000000000000017502309383371653514753081537245251811020857330038132583548033490964923632298277047095547089743554728739908114975629541647562410476799566744273134542648550103525944011430434718636512569974428283241553786306560"},
+  {"0x1.59ce797fb817fp+747", 309, "999999999999999928454223448636526995609414612446486912536395043045051171498417578302416590307106934377352009423588636134254484622941461177838218040629861358615028052178586193608330530158506646130887048916655460323666687950848"},
+  {"0x1.59ce797fb8180p+747", 309, "1000000000000000092833470372023199096890348452450507710984513881269234280819695799200296412090882625429431268098227736977472261378510764709695475858873732081359239635049862754709070252922400339620379482801740375051580804694016"},
+  {"0x1.b04217dfa61dfp+750", 309, "9999999999999999613300728333138614158656013804472910722260188106898877933626732224819925546638620725877678611585164563028980399740553218842096696042786355031638703687528415058284784747112853848287855356936724432692495112994816"},
+  {"0x1.b04217dfa61e0p+750", 309, "10000000000000000928334703720231990968903484524505077109845138812692342808196957992002964120908826254294312680982277369774722613785107647096954758588737320813592396350498627547090702529224003396203794828017403750515808046940160"},
+  {"0x1.0e294eebc7d2bp+754", 309, "99999999999999988242803431008825880725075313724536108897092176834227990088845967645101024020764974088276981699468968789815350713138205618891818585152157755624664880897462875650012340778461641195382916742883168419985073526276096"},
+  {"0x1.0e294eebc7d2cp+754", 309, "100000000000000009283347037202319909689034845245050771098451388126923428081969579920029641209088262542943126809822773697747226137851076470969547585887373208135923963504986275470907025292240033962037948280174037505158080469401600"},
+  {"0x1.51b3a2a6b9c76p+757", 309, "999999999999999924509121522475246865178672200286390413373640190927670776874706901000867474584296317792102107215397297714017257980807797893073643852992008461269166974189675556141912776812173197487139230503413422370196749149011968"},
+  {"0x1.51b3a2a6b9c77p+757", 309, "1000000000000000092833470372023199096890348452450507710984513881269234280819695799200296412090882625429431268098227736977472261378510764709695475858873732081359239635049862754709070252922400339620379482801740375051580804694016000"},
+  {"0x1.a6208b5068394p+760", 309, "9999999999999999918388610622944277578633427011520373324179896670642961784527024602806390495869308408470337715685294734193992593398889846197223766553446979093051960385337504355687757672562640543404353314227442034427503713670135808"},
+  {"0x1.a6208b5068395p+760", 309, "10000000000000001264983401419327895432326837028833311705066886193375469816086935788401821995921998869568971002747938248301632620580513580730198422600500768053772541672219001944225017481444457680470275332614057655878576158030168064"},
+  {"0x1.07d457124123cp+764", 309, "99999999999999988411127779858373832956786989976700226194703050524569553592790956543300452958271560395914310860351799229078805716535908585708440417158039479244754953558323062848579498254571868337516156995181495372666457581821100032"},
+  {"0x1.07d457124123dp+764", 309, "100000000000000009956644432600511718615881550253707240288894882888289682097749535512827356959114607773492443453354095454801046151441888338236034913910900102616284254148427024265175655196680942530570909289367345315883616691581616128"},
+  {"0x1.49c96cd6d16cbp+767", 309, "999999999999999884111277798583738329567869899767002261947030505245695535927909565433004529582715603959143108603517992290788057165359085857084404171580394792447549535583230628485794982545718683375161569951814953726664575818211000320"},
+  {"0x1.49c96cd6d16ccp+767", 309, "1000000000000000056475411020520841414840626381983058374700565164155456563967578197189219761589459982979768169347536362096565980644606923877305160145603279779419783940304062319818564238082591276919599588305301753272401848696295129088"},
+  {"0x1.9c3bc80c85c7ep+770", 309, "9999999999999999185841044429711589466224211962102134844977374370276477415358432917842475759840644797632681207523216662519436418612086534611285553663849717898419964165273969667523488336530932020840491736225123136358120303938278260736"},
+  {"0x1.9c3bc80c85c7fp+770", 309, "10000000000000000564754110205208414148406263819830583747005651641554565639675781971892197615894599829797681693475363620965659806446069238773051601456032797794197839403040623198185642380825912769195995883053017532724018486962951290880"},
+  {"0x1.01a55d07d39cfp+774", 309, "99999999999999997374062707399103193390970327051935144057886852787877127050853725394623645022622268104986814019040754458979257737456796162759919727807229498567311142603806310797883499542489243201826933949562808949044795771481474727936"},
+  {"0x1.01a55d07d39d0p+774", 309, "100000000000000019436671759807052388305883156775590326490339289128326538639931310259419194719485548619626821794275105794118831942800519429348176492482158776899757146408072767288477964251208935175515000298809119290899166699876243210240"},
+  {"0x1.420eb449c8842p+777", 309, "999999999999999841364972759543336764420226292177420345984153909836074800974071744757463152045042997962028093539001436578955132142505622028069656690022719315678435403212464369035268207172574280176140941400150227439321732144446136385536"},
+  {"0x1.420eb449c8843p+777", 309, "1000000000000000017865845178806930323739528929966661805443773400559670093686692423675827549619949242079148155740876247260071725785255408160775710807422153542338003433646596020960023924842331815965645472194120710174156699571604284243968"},
+  {"0x1.9292615c3aa53p+780", 309, "9999999999999999119653217272487741881479473472931169297680017061255129180591200163248089110750054956088761184197513608514017695996055364811520783369824930063422626153861170298051704942404772944919427537177384205332557191153093955289088"},
+  {"0x1.9292615c3aa54p+780", 309, "10000000000000000531660196626596490356033894575245100973356972987043891522292165594595004291349304909025721681812512093962950445138053653873169216309020403876699170397334223513449750683762833231235463783529148067211236930570359138156544"},
+  {"0x1.f736f9b3494e8p+783", 309, "99999999999999994020546131433094915763903576933939556328154082464128816489313932495174721468699049466761532837205133056038042458244550226238504699576640248260779350025557809411313140906763850021826347864477369777082931390365469918625792"},
+  {"0x1.f736f9b3494e9p+783", 309, "100000000000000005316601966265964903560338945752451009733569729870438915222921655945950042913493049090257216818125120939629504451380536538731692163090204038766991703973342235134497506837628332312354637835291480672112369305703591381565440"},
+  {"0x1.3a825c100dd11p+787", 309, "999999999999999940205461314330949157639035769339395563281540824641288164893139324951747214686990494667615328372051330560380424582445502262385046995766402482607793500255578094113131409067638500218263478644773697770829313903654699186257920"},
+  {"0x1.3a825c100dd12p+787", 309, "1000000000000000120942354671656868962382001670435578817768191183142249744630862900164152357803694488643546272066771136697843816472621283262276046411983423130707191163420128905684081263961470216866716118177799472091300320549064642593292288"},
+  {"0x1.8922f31411455p+790", 309, "9999999999999999040580826428657651966904425891201589123842107529410958489455946099092661860636496958724291396331073693328877462044103460624068471125229983529879139676226679317989414380888721568885729507381685429067351125745727105048510464"},
+  {"0x1.8922f31411456p+790", 309, "10000000000000000486475973287265010404848153099971055159735310397418651127357734700791903005570128910531738945888832142428584597165509708623196466454966148714674320981543085810557013220039375302073350623645891623631119178909006652304785408"},
+  {"0x1.eb6bafd91596bp+793", 309, "99999999999999999081179145438220670296706622164632687453780292502155740721970192601122065475966761298087599260657287627887017431169472094235452683230716826407562484594165232135299736843791138087983021771402091458056119576436948334022754304"},
+  {"0x1.eb6bafd91596cp+793", 309, "100000000000000010648340320307079537800256439834788415740925915446217281825184501414715994635435816912547179657119355220684674512140722078228476645868606147885923935036696484075840527556996367953483990701515741014566264001743184712072953856"},
+  {"0x1.33234de7ad7e2p+797", 309, "999999999999999828871535006218182557917368774264146678517764203804695831774701602620905646527100834378441867056103929979702975178097221166452191355376717763378564539746214794185426298453038162762816652692429820789419173810082174047524749312"},
+  {"0x1.33234de7ad7e3p+797", 309, "1000000000000000013946113804119924437974165856986638331112094170909680489426130543638408513078605724209795153399497011464465488473637220910340574757582946907032347746826714825234078949864321840610832155574248213693581484614981956096327942144"},
+  {"0x1.7fec216198ddbp+800", 309, "9999999999999999029013665253788793099400876073531433395554961906466896948352731790279067931477027903109831815934611625736079804963132210640075447162592094208400778225784148066048873590175516339020228538451571779510840981320420868670460264448"},
+  {"0x1.7fec216198ddcp+800", 309, "10000000000000000509610295637002728139855252735311366616309601643306774209564163318419090863889067021760658106681756277614179911327452208591182514380241927357631043882428148314438094801465785761804352561506118922744139467759619125060885807104"},
+  {"0x1.dfe729b9ff152p+803", 309, "99999999999999993251329913304315801074917514058874200397058898538348724005950180959070725179594357268399970740840405561116998262359962102302968606061220608382468313571129481157267178324335702235770533430624812081575006786082605199485453729792"},
+  {"0x1.dfe729b9ff153p+803", 309, "100000000000000005096102956370027281398552527353113666163096016433067742095641633184190908638890670217606581066817562776141799113274522085911825143802419273576310438824281483144380948014657857618043525615061189227441394677596191250608858071040"},
+  {"0x1.2bf07a143f6d3p+807", 309, "999999999999999885134206960780312089454635087411784140906440513804611167700736000690226517958758320887173266104495426751070779219941381088594259909647411423049314634698686803624216704482068400828613365568502612232284516294771707790360919932928"},
+  {"0x1.2bf07a143f6d4p+807", 309, "1000000000000000074650575649831695774632795300119615593163034400120115457135799236292149453307499328074479031320129942191467592834574340826335964513506590066150788638749118835418037019527222886944981240519484646566146722558989084608335389392896"},
+  {"0x1.76ec98994f488p+810", 309, "9999999999999999230374806985905888264902671299533504313577592910677120255877486478106111050285065223246344191476223298391501419428679730361426008304192471516696094355087732099829807674910992980518869405586990190990569575476151831539558138249216"},
+  {"0x1.76ec98994f489p+810", 309, "10000000000000000746505756498316957746327953001196155931630344001201154571357992362921494533074993280744790313201299421914675928345743408263359645135065900661507886387491188354180370195272228869449812405194846465661467225589890846083353893928960"},
+  {"0x1.d4a7bebfa31aap+813", 309, "99999999999999992303748069859058882649026712995335043135775929106771202558774864781061110502850652232463441914762232983915014194286797303614260083041924715166960943550877320998298076749109929805188694055869901909905695754761518315395581382492160"},
+  {"0x1.d4a7bebfa31abp+813", 309, "100000000000000004432795665958347438500428966608636256080197937830963477082618911859584178365170076692451010888562841972100410265623306726829729177688912148325455279810104971033102576911999816916636238052732752107272876955671430431745947427930112"},
+  {"0x1.24e8d737c5f0ap+817", 309, "999999999999999874521290314193434603084658115500145579580071256170942927492372459496518833579228824484684143252419893886408557657521935343280724451831297419035632090471862609843762766839539749606096764571247618309588232743975534688554349643169792"},
+  {"0x1.24e8d737c5f0bp+817", 309, "1000000000000000068586051851782051496707094173312964986690823395758019319873877212752887919376339615844485246833229637697374894798906086114728229966183096349571541470619505010400634769445777943389257468521053221467463131958534128550160206370177024"},
+  {"0x1.6e230d05b76cdp+820", 309, "9999999999999999521471949292288813605336325386252733424243721120057734844449743607990664678980731410286045846847437914107950925140755956518597266575720169912499958425309195700665115678820350271193610461511698595727381924297989722331966923339726848"},
+  {"0x1.6e230d05b76cep+820", 309, "10000000000000001073990041592997748754315813848755288681129738236754345983501781634041617365357617741164454675493915864595681622271829162690177310690534561356787233466490334905120091699670255821458896093110143420990381118014458473224813777155784704"},
+  {"0x1.c9abd04725480p+823", 309, "99999999999999992109683308321470265755404276937522223728665176967184126166393360027804741417053541441103640811181423240104047857145413152842812577527572916236425034170729678597741204746503691611405533351920096306747820855546959721533975525765152768"},
+  {"0x1.c9abd04725481p+823", 309, "100000000000000004529828046727141746947240184637542665783753313900757015278809664236212362908068632088130911440353246844005893434193998802215452930446088047790723234500178792233381012913302936013527818404707654908851814405278709728676750356293615616"},
+  {"0x1.1e0b622c774d0p+827", 309, "999999999999999921096833083214702657554042769375222237286651769671841261663933600278047414170535414411036408111814232401040478571454131528428125775275729162364250341707296785977412047465036916114055333519200963067478208555469597215339755257651527680"},
+  {"0x1.1e0b622c774d1p+827", 309, "1000000000000000119819148897705446356623417292575549310168061960609007487462594467612569358026776864763472738178563410063470007804231501918390371421971971267233021546978482604147648978133824826548011894363801900701142105351177597329624152546106933248"},
+  {"0x1.658e3ab795204p+830", 309, "9999999999999999210968330832147026575540427693752222372866517696718412616639336002780474141705354144110364081118142324010404785714541315284281257752757291623642503417072967859774120474650369161140553335192009630674782085554695972153397552576515276800"},
+  {"0x1.658e3ab795205p+830", 309, "10000000000000000800746857348072976168095423879354838955917799224215742423028622941456649692555285746929854721652135745309841019576760278403979222926327228462592673059242454405136015920000672444612205821948817131744093259920359973067672730884158521344"},
+  {"0x1.bef1c9657a685p+833", 309, "99999999999999992109683308321470265755404276937522223728665176967184126166393360027804741417053541441103640811181423240104047857145413152842812577527572916236425034170729678597741204746503691611405533351920096306747820855546959721533975525765152768000"},
+  {"0x1.bef1c9657a686p+833", 309, "100000000000000004827911520448877862495844246422343156393075429187162764617507655537214145823852994263659565935453370610499537728043164857800396298916132410948026391308085570960636368309306117879178753245974556315302310250472271728848176952226298724352"},
+  {"0x1.17571ddf6c813p+837", 309, "999999999999999895660376658959887464073162830405580371957831265231883984761705009259228605356936508765924557863270337660249498829658628118512958332498610172941047627432585001251621720339432063578508893731092043050369229765618973200711352404729235767296"},
+  {"0x1.17571ddf6c814p+837", 309, "1000000000000000099152028052998409011920202342162715294588395300751542199979533737409779075865727753926819359851621495586577336764022655397834297874715562088326669341630279279057944337344270883862880412035963403187241060084423965317738575228107571068928"},
+  {"0x1.5d2ce55747a18p+840", 309, "9999999999999999363587069377675917736425707327570073564839440723358156278052707548893386994586947577981035182609405692455150664165314335743772262409420005560181719702721238568128862437403998276353831973920663150777435958293799716241167969694049028276224"},
+  {"0x1.5d2ce55747a19p+840", 309, "10000000000000000991520280529984090119202023421627152945883953007515421999795337374097790758657277539268193598516214955865773367640226553978342978747155620883266693416302792790579443373442708838628804120359634031872410600844239653177385752281075710689280"},
+  {"0x1.b4781ead1989ep+843", 309, "99999999999999993635870693776759177364257073275700735648394407233581562780527075488933869945869475779810351826094056924551506641653143357437722624094200055601817197027212385681288624374039982763538319739206631507774359582937997162411679696940490282762240"},
+  {"0x1.b4781ead1989fp+843", 309, "100000000000000006659336382995224556426467602028157370696750505506839688554468114090569100058432115470107619153348531031836488269452441103314288354796084978186496986735864819460893271862349667261738096910718398556534156723341516657901421957636703742066688"},
+  {"0x1.10cb132c2ff63p+847", 309, "999999999999999988452569694641453289891412847766833896677368465428848130901034909295879619908945316559292587569958465674654992927728624557883489163749540246356891129106733591931304833693638565628182306078113383272782784390994049606075766012189756664840192"},
+  {"0x1.10cb132c2ff64p+847", 309, "1000000000000000196828020722136899354886781307806140057451066037800978143284091526922043301709947551604048864806030051391214698972517388491908540854979699007711767764445172532404979193506593517599378740822301656052939538637450361533911642183329172013711360"},
+  {"0x1.54fdd7f73bf3bp+850", 309, "9999999999999998634272990781441856508941917717432502002131499220055701234712009387201814108283439755324388212283155142447191693008553661974684581490114449895439651479036702276471002178058655944454644452316004196046887318431202624493742403095061074555174912"},
+  {"0x1.54fdd7f73bf3cp+850", 309, "10000000000000000301276599001405425028904865397746951288321079799032741333776462328211123562691457635682438430171727828179669341366863773446884995019955719986278664561744213800260397056562295560224215930269510378288141352402853119916429412464176397346144256"},
+  {"0x1.aa3d4df50af0ap+853", 309, "99999999999999989676737124254345702129345072534953918593694153358511092545248999754036759991650433313959982558608696795936872226802156842691246641960827039136074540955782045812288811537593838676085587479067054324951381252255327235782798049688841391133687808"},
+  {"0x1.aa3d4df50af0bp+853", 309, "100000000000000003012765990014054250289048653977469512883210797990327413337764623282111235626914576356824384301717278281796693413668637734468849950199557199862786645617442138002603970565622955602242159302695103782881413524028531199164294124641763973461442560"},
+  {"0x1.0a6650b926d66p+857", 309, "999999999999999843423255779504622828654636399579476808778874955057845642282427503428069697375447760968142218613652642015929437520555644859802053186653349748453896990911180089361627479263821919056229587496158345417793683435460456504301996197076723582025859072"},
+  {"0x1.0a6650b926d67p+857", 309, "1000000000000000056799717631659959599209893702659726317411141269166906774962677479877261307539674049653972646503389945789686576510419339128243706118473032320081290665497741564406670023712287789874734736674207136744674199783831719918405933396323484899269935104"},
+  {"0x1.4cffe4e7708c0p+860", 309, "9999999999999999287738405203667575368767393208115766122317814807014700953545274940077463414411382764424743897695475635254322931165011225671787143593812227771048544607458046793796444970432082673836316471673778619485458899748089618699435710767754281089234894848"},
+  {"0x1.4cffe4e7708c1p+860", 309, "10000000000000000994750100020910269533209451632757762191375945319887190014987274751670996295725193073911387320813374065444380043083920779819320367048369688344067694004150538594156785326019809640384357665098168950100503030535059726012267208361728371627187503104"},
+  {"0x1.a03fde214caf0p+863", 309, "99999999999999992877384052036675753687673932081157661223178148070147009535452749400774634144113827644247438976954756352543229311650112256717871435938122277710485446074580467937964449704320826738363164716737786194854588997480896186994357107677542810892348948480"},
+  {"0x1.a03fde214caf1p+863", 309, "100000000000000006533477610574617307003210399478293629775643192173126922026988747893522897194624310120140586361897943794063686207001388689898137223574581962294638641248120402340847172549022642470747494264132908839774942043776657045497009088429335535195969814528"},
+  {"0x1.0427ead4cfed6p+867", 309, "999999999999999928773840520366757536876739320811576612231781480701470095354527494007746341441138276442474389769547563525432293116501122567178714359381222777104854460745804679379644497043208267383631647167377861948545889974808961869943571076775428108923489484800"},
+  {"0x1.0427ead4cfed7p+867", 309, "1000000000000000147271337456973822389925322799165752109071222186349148695219103469891718550249305996056764747928638562589759603442121545498062966961564577730451305583522443629825768062558437319101780919925699824267271538715541135605986002768804111697781423341568"},
+  {"0x1.4531e58a03e8bp+870", 309, "9999999999999998413748417457239315956573059294699064134960051984423986554086971036541574579178711885967582465059111638997013689862529533948250133185078807957662740116351490992011950708371166466963719380640490770210556304785160923755265983999639546733803159420928"},
+  {"0x1.4531e58a03e8cp+870", 309, "10000000000000000161728392950095834780961727121532468109675577629605415353003578843613352249644053642881905330331839631511632172467492917395324154002545647584434349098564602595580939232492998880708913562707066468760361494711018313643605437535869015444666630275072"},
+  {"0x1.967e5eec84e2ep+873", 309, "99999999999999987633444125558106197214507928600657449299031571134602723138702925979559301132717802373504470381136572374999373863835222106376649373485721758830170619127941133127257484131955329497127582170538059099205173427703324017329338747068854404759758535917568"},
+  {"0x1.967e5eec84e2fp+873", 309, "100000000000000001617283929500958347809617271215324681096755776296054153530035788436133522496440536428819053303318396315116321724674929173953241540025456475844343490985646025955809392324929988807089135627070664687603614947110183136436054375358690154446666302750720"},
+  {"0x1.fc1df6a7a61bap+876", 309, "999999999999999932269800471352470574525516656465243420181212531991832952952360709621889896782068959956303035500093019510461530081711049334072862401016156456358397678710230902586782474091451932211122035531511013345645500354660676649720249983847887046345216426508288"},
+  {"0x1.fc1df6a7a61bbp+876", 309, "1000000000000000044140518902895287779286391397382581274563006173283444396083023609274483667691850832398819698877547611031397112968428705874685599733334034192471780653571870045215197739635249206690814463183771858052833032509915549602573975010166573043840478561173504"},
+  {"0x1.3d92ba28c7d14p+880", 309, "9999999999999998875215130987353436926211667600983082784284950754751883757000955497608523884181562109792963701491111829020872969270239867178277674680890053619130444887655752455354163678739330224192450644706066754627704874925587274685787599733204126473471115726422016"},
+  {"0x1.3d92ba28c7d15p+880", 309, "10000000000000000665146625892038512202385663455660488454393649015417666847091561892050024218738072068873230315530385293355842295457722371828081471997976097396944572485441978737408807927440086615867529487142240269942705389409665241931447200154303102433395309881065472"},
+  {"0x1.8cf768b2f9c59p+883", 309, "99999999999999988752151309873534369262116676009830827842849507547518837570009554976085238841815621097929637014911118290208729692702398671782776746808900536191304448876557524553541636787393302241924506447060667546277048749255872746857875997332041264734711157264220160"},
+  {"0x1.8cf768b2f9c5ap+883", 309, "100000000000000003071603269111014971471508642847250073203719093632845102290734406131617241518267700770571769927225306004888484302202258708981207125345588886413817469658847334809978790776999353375325137186550055668797052865128496484823152800700833072414104710501367808"},
+  {"0x1.f03542dfb8370p+886", 309, "999999999999999973438224854160227305877518561122823750593712591987145964024444656694044404476868689015149167622996309190165824584023146941018349739309135463248122613459314107074039291811569329219648848907543004197890512187794469896370420793533163493423472892065087488"},
+  {"0x1.f03542dfb8371p+886", 309, "1000000000000000087993840528060072123552654295822177713480669280669756081790243465938300425888485326396286230921509810907603861460022027238605792767602642265028226779717632589125536523728417738286853894823458109178050545114775459800092635220483497954858621317962268672"},
+  {"0x1.362149cbd3226p+890", 309, "9999999999999999734382248541602273058775185611228237505937125919871459640244446566940444044768686890151491676229963091901658245840231469410183497393091354632481226134593141070740392918115693292196488489075430041978905121877944698963704207935331634934234728920650874880"},
+  {"0x1.362149cbd3227p+890", 309, "10000000000000001567272099323999790141577357366417900912128432938793221524497227514848540387354553088249684689006179119380666835856213554171582585845787463460962892794726236783564348628785267837271769223730071721661465648709640537423259638766536986317197103735005773824"},
+  {"0x1.83a99c3ec7eafp+893", 309, "99999999999999990012263082286432662256543169091523721434606031123027548865433341877772055077343404109122144711194766809100548098338386355056238620120129111010885594705399027856108106338478634741663761952135733701058809111452663635798820356028494943810497789949089153024"},
+  {"0x1.83a99c3ec7eb0p+893", 309, "100000000000000004675381888545612798918960543133041028684136487274401643939455589461036825818030333693907688813404495028932616818466243033147431327741697981638738927986463793558699752023835231102266007829372867138519293326106230343475263802678137754874196788463928344576"},
+  {"0x1.e494034e79e5bp+896", 309, "999999999999999929448868435382686895890266438998271828845121223533023678802377913944250092254807900260792535316367124530669618423639576906744771616444428851364562613616119809966264354755499540137842111275831603885509059543833769773341090453584235060232375896520569913344"},
+  {"0x1.e494034e79e5cp+896", 309, "1000000000000000046753818885456127989189605431330410286841364872744016439394555894610368258180303336939076888134044950289326168184662430331474313277416979816387389279864637935586997520238352311022660078293728671385192933261062303434752638026781377548741967884639283445760"},
+  {"0x1.2edc82110c2f9p+900", 309, "9999999999999999529098585253973751145501342374646995204443699533752222309208135100774737254399069875964494058799026896824009283758441475916906799486389390443691279468658234350904109878520700943148057046794110173854458342872794765056233999682236635579342942941443126198272"},
+  {"0x1.2edc82110c2fap+900", 309, "10000000000000001405977792455148808638290766251961210532383597921128106478682982791432627909206996862817043703881872108962514079934807130712579466061950205884056506128634524360835840526246345277305144519080463253849400322348451303638818760853390915395496414751342542716928"},
+  {"0x1.7a93a2954f3b7p+903", 309, "99999999999999991537227438137387396469434575991841521388557198562770454753131655626431591234374844785939841297824578543963083245231683449577722661712772273556182341366629763489177637489755720763166395523368395578554699469776634573397170474480057796161122485794632428945408"},
+  {"0x1.7a93a2954f3b8p+903", 309, "100000000000000006552261095746787856411749967010355244012076385661777528108930437151694716472838260680760238458487340241071121614642608687943103994317258797079104154646440083568631482671560875436423095301659220218514235305581886882057848563849292034690350260273827761094656"},
+  {"0x1.d9388b3aa30a5p+906", 309, "999999999999999945402341696592674884578976541955442659132610359825718694242914119314842162820675279649039207299571308833846909191138684972507989282336695782607667040225918275050684065261167516978177354790265605065466066369376850351293060923539046438669680406904714953752576"},
+  {"0x1.d9388b3aa30a6p+906", 309, "1000000000000000065522610957467878564117499670103552440120763856617775281089304371516947164728382606807602384584873402410711216146426086879431039943172587970791041546464400835686314826715608754364230953016592202185142353055818868820578485638492920346903502602738277610946560"},
+  {"0x1.27c35704a5e67p+910", 309, "9999999999999999213782878444176341486712719163258207029349796604673073768736360688744211624391338142173265718425108901184740478000812045911233791501695173449709921389782217629235579129702792695009666351450002856415308090320884466574359759805482716570229159677380024223137792"},
+  {"0x1.27c35704a5e68p+910", 309, "10000000000000001135707186618179600359329089213627963525160252553345979158278604723977891654914655376710276554989942398414569389285410476422002602075069448460643913489597938599405671312973852493186523923071228410330128677303956762082926555244744699101970314810717026738241536"},
+  {"0x1.71b42cc5cf601p+913", 309, "99999999999999995981677400789769932612359931733321583285118877944076548466448094957909476304960015890806678857380756006307062602577317320133875536163700284518967198097453618232695975663570046546450378657742479671982722077174989256760731188933351130765773907040474247261585408"},
+  {"0x1.71b42cc5cf602p+913", 309, "100000000000000011357071866181796003593290892136279635251602525533459791582786047239778916549146553767102765549899423984145693892854104764220026020750694484606439134895979385994056713129738524931865239230712284103301286773039567620829265552447446991019703148107170267382415360"},
+  {"0x1.ce2137f743381p+916", 309, "999999999999999929065985077113647184161737396527299728918221484261998998431805045015355882561227083155474615188770224107393363445219598313166454392463014445014728107377484646804238281703363508693674065431485187857190091380020735839470243162305319587149880588271350432374194176"},
+  {"0x1.ce2137f743382p+916", 309, "1000000000000000052069140800249855752009185079750964144650090664977064943362508663270311404514719386165843308728919567930102413767433897865855658269158968045714503601765690788895124181432711335776992950015243623307738608946937362752018518070418086469181314516804918593340833792"},
+  {"0x1.20d4c2fa8a030p+920", 309, "9999999999999998060628293539774386163142897133036353131863523035469330535011014267604003606077347801451059216486208802846843131230052987604772505157670608443149526129892785047133523819740156816103551808477267524066415738131041089269219682541925527051184466597377822714075545600"},
+  {"0x1.20d4c2fa8a031p+920", 309, "10000000000000000028678785109953723248702060064614983783573429926910385653902272159683291957333224649616958313128598304010187936385481780447799767184805866054345934040104083320587698215409722049436653961817402491275192019201707119869992081071729797163687409453914913289541779456"},
+  {"0x1.6909f3b92c83dp+923", 309, "99999999999999996350686867959178558315902274782992576532314485486221746301240205812674342870820492799837784938001204037775189753543960218791943147793788145321066524580618236658968633362758090027700335311493754978334367629875739137498376013657689431411868208826074951744485326848"},
+  {"0x1.6909f3b92c83ep+923", 309, "100000000000000012095090800520613255000375578235621621745993740617750187252370268949308649680867507585164977711140320047081948194787390561536161244010870206210637787862308622846602028528114611894365152538214834716004577878441067382304555201896123592311891751678371676348215197696"},
+  {"0x1.c34c70a777a4cp+926", 309, "999999999999999932018060814468916189790076140924667674895786344599160581110141931853474815088110898427723463833733808359138380652952741502430995285503717331431522719242801594214419543296867856543673718661495390308003255801626734885371401760100025992318635002556156068237393526784"},
+  {"0x1.c34c70a777a4dp+926", 309, "1000000000000000057973292274960393763265862568545700036605220385651388108719182436946549269568487016710341006018846736433592448182900184244384740055240373818548092825496324683715486704619720031476992256475264028209364937790149360843820835266007499279518823345374529865067232493568"},
+  {"0x1.1a0fc668aac6fp+930", 309, "9999999999999998312538756460757341310094469988278417855282391117573785590229095277790152515038100038016294300856434658995751266289947873088679994697143921417382666342399831226135658142385861165970188884104804799869139102108086341186118549553740473625584843283014570307735223533568"},
+  {"0x1.1a0fc668aac70p+930", 309, "10000000000000000327822459828620982485707052830214935642633335774409426031973743359279343786724117930538174975818241508187016346769106956959939911012930425211247788042456200658152732723551495964903285489125103006290926013924448356521309485648260046220787856768108551057012647002112"},
+  {"0x1.6093b802d578bp+933", 309, "99999999999999987155954971343300695452169865566657214127525800489409136785780248940879907693753036165206704358487960288340042823857796898629319779603012221761556906824111051125390730586189881257568082051088644411534964844713587442531567367726443881446254459800333664575907082272768"},
+  {"0x1.6093b802d578cp+933", 309, "100000000000000003278224598286209824857070528302149356426333357744094260319737433592793437867241179305381749758182415081870163467691069569599399110129304252112477880424562006581527327235514959649032854891251030062909260139244483565213094856482600462207878567681085510570126470021120"},
+  {"0x1.b8b8a6038ad6ep+936", 309, "999999999999999903804088967318825213331499981137556425872873119403461614925716858712626137284506647932417134384268512470460669526244514328233356457082706278317411015442012422166180499160548969358610366191211215418098239036197666670678728654776751975985792813764840337747509598224384"},
+  {"0x1.b8b8a6038ad6fp+936", 309, "1000000000000000032782245982862098248570705283021493564263333577440942603197374335927934378672411793053817497581824150818701634676910695695993991101293042521124778804245620065815273272355149596490328548912510300629092601392444835652130948564826004622078785676810855105701264700211200"},
+  {"0x1.137367c236c65p+940", 309, "9999999999999999553953517735361344274271821018911312812290573026184540102343798495987494338396687059809772796632907678097570555865109868753376103147668407754403581309634554796258176084383892202112976392797308495024959839786965342632596166187964530344229899589832462449290116390191104"},
+  {"0x1.137367c236c66p+940", 309, "10000000000000001617604029984053712838099105849054307026537940354784235914690318131432426200603169381752178607793797891669425998275768770637546257455033787639321465930492277094643660455497502236220467316338093858400869637486920046335831684748752572681717785398568698736550198021980160"},
+  {"0x1.585041b2c477ep+943", 309, "99999999999999991412234152856228705615063640528827139694410995604646009398744945688985079659553905954212916344007296353831994673829780883765420722861953317774200043854630103365810792101611701952914782080891514223497778802469744018919490624758069218767323224280852151918381000638332928"},
+  {"0x1.585041b2c477fp+943", 309, "100000000000000007921438250845767654125681919169971093408389934233443575897517102772544534557205764529752162833294418062406838213115052098838781957320876356853543120821491881752894667070520582225774709469217797130505057184069381648545374773244373557467226310750742042216461653692645376"},
+  {"0x1.ae64521f7595ep+946", 309, "999999999999999980159157920520442850193109519852847211800025710561650359982538085224088616186146493844286149397221450372619320895438893697947652166455225334059372746413748147206443420891752540620587530362220273863006901551095990707698442841525909542472844588688081080376132618600579072"},
+  {"0x1.ae64521f7595fp+946", 309, "1000000000000000112232790704436754438278055748981998841511857219592030891972715341892564255367361362448600121311518424041218069209721063418534542042126609646694117362148642374303114420643023582803466949468830537119065128603893091744705516029416344252072069280447200202760777843035078656"},
+  {"0x1.0cfeb353a97dap+950", 309, "9999999999999998216707985798208689444911740448978652561458278997251937215943253772219178491686886515191093831000650819703008229183002900332433843156495641588976792075318750746904382211902272900011322274342879579557370290877394694632899550160573878909537749585771381335145583492791795712"},
+  {"0x1.0cfeb353a97dbp+950", 309, "10000000000000000329886110340869674854270880115045078636847583141738025727786089878914788718586324412860117381629402398400588202211517615861824081167237790591132705927077058380451118207922609574937392980048643791654301923722148311225012721166820834263125344653917287293299907083743789056"},
+  {"0x1.503e602893dd1p+953", 309, "99999999999999990619792356152730836086553963154052229916140006550463726206803882148974225824466616742587032512521514511820402183944087865441899383607925011898391576160220738003230766103104075699817505566251852643961429440152961412697448185630726610509727876130297437184073129291725930496"},
+  {"0x1.503e602893dd2p+953", 309, "100000000000000007525217352494018719361427080482583638519254439706352434301546571002539107639662119923939220917551527141401041968172205589677021287693862203915638886974287199071604654071266769099226071211897966340736882502910990345434353553680702253338428636675464684849307718019341877248"},
+  {"0x1.a44df832b8d45p+956", 309, "999999999999999872387073568844732594315793396883459481955171199192859845878553443782612494614275161063165948315155119859042742270984643205948750027907375734949421139974074457895559885094715370199357924371226299046063388276013556261500671120207314819439877240212639876510262115462027411456"},
+  {"0x1.a44df832b8d46p+956", 309, "1000000000000000007630473539575035660514778335511710750780086664439969510636494954611131549135839186513983455555395220895687860544809584999829725260594873271087399626486606146442550988840016917394626449536395208620267012778077787723395914064607119962069483324573977857832138825282954985472"},
+  {"0x1.06b0bb1fb384bp+960", 309, "9999999999999998453383935746986719810759964091578092281901881061434379129269651416169086837099623559730024468671070996517137186162196548471725549813698762277218254426715681201861616643456550607603042193381925171312226633756007099691216225313273537909139560233403722802458867734978418966528"},
+  {"0x1.06b0bb1fb384cp+960", 309, "10000000000000000617278335278671568869943723109630112583100528505388133765396715589425391709444647966943104584514912613103459078543395617173821153536698722855425910210916188218613474303381375362727338596024627724499484625789034803081540112423670420191213257583185130503608895092113260150784"},
+  {"0x1.485ce9e7a065ep+963", 309, "99999999999999988861628156533236896225967158951884963421416105502251300564950642508203478115686284411726404918398393198344015646384363622121446705582987543928597855835557826052119881754415155586279014739104656819496782321626126403692810027353529143655542997033600043426888732064053872033792"},
+  {"0x1.485ce9e7a065fp+963", 309, "100000000000000006172783352786715688699437231096301125831005285053881337653967155894253917094446479669431045845149126131034590785433956171738211535366987228554259102109161882186134743033813753627273385960246277244994846257890348030815401124236704201912132575831851305036088950921132601507840"},
+  {"0x1.9a742461887f6p+966", 309, "999999999999999957860902350346284132153551878096514283852517773229033154005572478626236537071903625148082612890986863714202457020042006419681526374965874177788623543449994485057258262661745948026767632275613049896960078961318150545418464661067991669581788285529005480705688196068853638234112"},
+  {"0x1.9a742461887f7p+966", 309, "1000000000000000096350143920374114471941312455251843583129231209642073450717704585714640048901985187209719740304992727175727058132438746816615645013237871654793913513638826934129377152896934732354722602044746013300944590451431923562399193436133392135634504915915015573579289946925483474026496"},
+  {"0x1.008896bcf54f9p+970", 309, "9999999999999997916738124663128877244082391855101191247204616495333847979510139501201523228758057506741180599941798275603729356851659179433605840090394772053822755792233955461707155943795194068332216685526534938121786651731816229250415901309895111103185283290657933692573660950408978352832512"},
+  {"0x1.008896bcf54fap+970", 309, "10000000000000000132565989783574162680686561089586460035632031477942492726904253214615979418039362499727374638565892090988122974650007025784551738302746731685907395315255274646861058187558214617579496201832662352585538835573636597522107561710941518560028749376834095178551288964115055725510656"},
+  {"0x1.40aabc6c32a38p+973", 309, "99999999999999992462348437353960485060448933957923525202610654848990348279466077292501969423268405025328970231162545648343655275306678872441733790178059478330735395060467469727994972900530063978805843953102113868000379620369084502134308975505229555772913629423636305841602377586326247764393984"},
+  {"0x1.40aabc6c32a39p+973", 309, "100000000000000010188971358317522768553282287833805675510029974709859506258618986999817618937518844969218522540155296171418804217693461643249300975876875155387412511244638023209226190850634228372784080083551133183710397091103647448307842258713600815427661358113045597729423401695974866745819136"},
+  {"0x1.90d56b873f4c6p+976", 309, "999999999999999924623484373539604850604489339579235252026106548489903482794660772925019694232684050253289702311625456483436552753066788724417337901780594783307353950604674697279949729005300639788058439531021138680003796203690845021343089755052295557729136294236363058416023775863262477643939840"},
+  {"0x1.90d56b873f4c7p+976", 309, "1000000000000000066436467741248103118547156170586292454485461107376856746627884050583544890346687569804406120783567460668037744292161050890877875387371120199760770880078039125129799472606133954939884328574613293205683935969567348590731356020719265634967118123751637393518591968740451429495341056"},
+  {"0x1.f50ac6690f1f8p+979", 309, "9999999999999999813486777206230041577815560719820581330098483720446847883279500839884297726782854580737362697004022581572770293687044935910015528960168049498887207223940204684198896264456339658487887951484580004902758521100414464490983962613190835886243290260424727924570510530141380583845003264"},
+  {"0x1.f50ac6690f1f9p+979", 309, "10000000000000000947990644147898027721356895367877038949773320191542473993945287061152499295694882737146294044779558615049579825999799033241699828844892252830514542659727120106997694213263006179702495063833317241108199639227426493046090092738526596504147144896546922605391056073158892198656212992"},
+  {"0x1.3926bc01a973bp+983", 309, "99999999999999998134867772062300415778155607198205813300984837204468478832795008398842977267828545807373626970040225815727702936870449359100155289601680494988872072239402046841988962644563396584878879514845800049027585211004144644909839626131908358862432902604247279245705105301413805838450032640"},
+  {"0x1.3926bc01a973cp+983", 309, "100000000000000016286929643128988194074816961567109135215782220741998496603447587939134202370420996309916528534448802351356655453874514916407104087757267748294909439211992693606769729825470060924312593312425595828314643101036337101791537708137280528748894576782202394138833833989693991675429388288"},
+  {"0x1.87706b0213d09p+986", 309, "999999999999999872436306494222877488001587945768638201521064070819504681704034606746682422062730755058478860313950798943503314266680100247159860107083281430052496520558476587831205023360193979812186512362979225814553504769848291707808207769286850569305558980974742103098278680884456943362624192512"},
+  {"0x1.87706b0213d0ap+986", 309, "1000000000000000017652801462756379714374878780719864776839443139119744823869255243069012222883470359078822072829219411228534934402712624705615450492327979456500795456339201761949451160807447294527656222743617592048849967890105831362861792425329827928397252374398383022243308510390698430058459037696"},
+  {"0x1.e94c85c298c4cp+989", 309, "9999999999999999595662034753429788238255624467393741467120915117996487670031669885400803025551745174706847878231119663145222863482996149222332143382301002459214758820269116923021527058285459686414683385913622455551313826420028155008403585629126369847605750170289266545852965785882018353801250996224"},
+  {"0x1.e94c85c298c4dp+989", 309, "10000000000000000757393994501697806049241951147003554069667947664398408807353434975979441432117662006869593578353268561425475824571256344889976866464258586670801150306514918315967496157863486204138441068958729385425685531382088472248832262877470188720339297317678393899013204421931950247367929757696"},
+  {"0x1.31cfd3999f7afp+993", 309, "99999999999999986662764669548153739894665631237058913850832890808749507601742578129378923002990117089766513181334005445210204946123879926882163649167349350899456456312724758086647517786230384722356772394775369116518164624503799012160606438304513147494189124523779646633247748770420728389479079870464"},
+  {"0x1.31cfd3999f7b0p+993", 309, "100000000000000005250476025520442024870446858110815915491585411551180245798890819578637137508044786404370444383288387817694252323536043057564479218478670698284838720092657580373783023379478809005936895323497079994508111903896764088007465274278014249457925878882005684283811566947219638686545940054016"},
+  {"0x1.7e43c8800759bp+996", 309, "999999999999999903803069407426113968898218766118103141789833949572356552411722264192305659040010509526872994217248819197070144216063125530186267630296136203765329090687113225440746189048800695790727969805197112921161540803823920273299782054992133678869364753954248541633605124057805104488924519071744"},
+  {"0x1.7e43c8800759cp+996", 309, "1000000000000000052504760255204420248704468581108159154915854115511802457988908195786371375080447864043704443832883878176942523235360430575644792184786706982848387200926575803737830233794788090059368953234970799945081119038967640880074652742780142494579258788820056842838115669472196386865459400540160"},
+  {"0x1.ddd4baa009302p+999", 309, "9999999999999999335434075769817752248594687291161143444150379827602457335271594505111188022480979804302392841403758309930446200199225865392779725411942503595819407127350057411001629979979981746444561664911518503259454564508526643946547561925497354420113435609274102018745072331406833609642314953654272"},
+  {"0x1.ddd4baa009303p+999", 309, "10000000000000000525047602552044202487044685811081591549158541155118024579889081957863713750804478640437044438328838781769425232353604305756447921847867069828483872009265758037378302337947880900593689532349707999450811190389676408800746527427801424945792587888200568428381156694721963868654594005401600"},
+  {"0x1.2aa4f4a405be1p+1003", 309, "99999999999999988595886650569271721532146878831929642021471152965962304374245995240101777311515802698485322026337261211948545873374744892473124468375726771027536211745837771604509610367928220847849105179362427047829119141560667380048679757245757262098417746977035154548906385860807815060374033329553408"},
+  {"0x1.2aa4f4a405be2p+1003", 309, "100000000000000007629703079084894925347346855150656811701601734206211380288125794484142188964691784076639747577138548761372210387844799938291815611350519830750167649856488981626536368095414607314235151058373458986890825155659063617715863205282622390509284183439858617103083735673849899204570498157510656"},
+  {"0x1.754e31cd072d9p+1006", 309, "999999999999999847891233648661470807691068835681842080854450367179124891914700353912936949808806064228544369161770037020638129704807338833093862397807681590830099241237075296001042588224309435545718960035602206600167779387409881325152430676383842364162444596844704620380709158981993982315347403639619584"},
+  {"0x1.754e31cd072dap+1006", 309, "1000000000000000000161765076786456438212668646231659438295495017101117499225738747865260243034213915253779773568180337416027445820567779199643391541606026068611150746122284976177256650044200527276807327067690462112661427500197051226489898260678763391449376088547292320814127957486330655468919122263277568"},
+  {"0x1.d2a1be4048f90p+1009", 309, "9999999999999999392535525055364621860040287220117324953190771571323204563013233902843309257440507748436856118056162172578717193742636030530235798840866882774987301441682011041067710253162440905843719802548551599076639682550821832659549112269607949805346034918662572406407604380845959862074904348138143744"},
+  {"0x1.d2a1be4048f91p+1009", 309, "10000000000000000610699776480364506904213085704515863812719128770699145421501541054461895603243770556638739353307444575741831722668719553462632031991253638597235713480763688482477422747721569639692426738805257643176588867453119191870248852943967318023641486852283274009874954768880653247303478097127407616"},
+  {"0x1.23a516e82d9bap+1013", 309, "99999999999999993925355250553646218600402872201173249531907715713232045630132339028433092574405077484368561180561621725787171937426360305302357988408668827749873014416820110410677102531624409058437198025485515990766396825508218326595491122696079498053460349186625724064076043808459598620749043481381437440"},
+  {"0x1.23a516e82d9bbp+1013", 309, "100000000000000013415983273353644379307167647951549871284361430903247099365945253454330474107257282415598692944582140176397004400243696672220697718814856920905847607042126949473232502444570468800016509005592812696365583783944976073966686973485829389546187580124556949719553650017014692784406223465209659392"},
+  {"0x1.6c8e5ca239028p+1016", 309, "999999999999999861291040414336469543176969619010226008309262296372260241358071732580741399612641955118765084749534143455432389522994257585350220962461935904874831773666973747856549425664459851618054736334425973085267220421335152276470127823801795414563694568114532338018850013250375609552861714878501486592"},
+  {"0x1.6c8e5ca239029p+1016", 309, "1000000000000000017216064596736454828831087825013238982328892017892380671244575047987920451875459594568606138861698291060311049225532948520696938805711440650122628514669428460356992624968028329550689224175284346730060716088829214255439694630119794546505512415617982143262670862918816362862119154749127262208"},
+  {"0x1.c7b1f3cac7433p+1019", 309, "9999999999999999860310597602564577717002641838126363875249660735883565852672743849064846414228960666786379280392654615393353172850252103336275952370615397010730691664689375178569039851073146339641623266071126720011020169553304018596457812688561947201171488461172921822139066929851282122002676667750021070848"},
+  {"0x1.c7b1f3cac7434p+1019", 309, "10000000000000001107710791061764460002235587486150467667406698508044529291764770372322278832331501782385107713289967796232382450470561630819049695116611434972713065592709012878572585445501694163102699168797993709169368134893256514428214347139105940256706031241200520264089633727198808148476736186715027275776"},
+  {"0x1.1ccf385ebc89fp+1023", 309, "99999999999999981139503267596847425176765179308926185662298078548582170379439067165044410288854031049481594743364161622187121841818187648603927125262209438639553681654618823985640760188731793867961170022535129351893330180773705244319986644578003569234231285691342840034082734135647456849389933411990123839488"},
+  {"0x1.1ccf385ebc8a0p+1023", 309, "100000000000000001097906362944045541740492309677311846336810682903157585404911491537163328978494688899061249669721172515611590283743140088328307009198146046031271664502933027185697489699588559043338384466165001178426897626212945177628091195786707458122783970171784415105291802893207873272974885715430223118336"},
+  {"0x1.fffffffffffffp+1023", 309, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368"},
+] of _
diff --git a/spec/std/sprintf_spec.cr b/spec/std/sprintf_spec.cr
index f37384d3a70c..d2da4369827b 100644
--- a/spec/std/sprintf_spec.cr
+++ b/spec/std/sprintf_spec.cr
@@ -583,11 +583,212 @@ describe "::sprintf" do
     end
 
     context "general format" do
-      pending_win32 "works" do
-        assert_sprintf "%g", 123, "123"
-        assert_sprintf "%G", 12345678.45, "1.23457E+07"
-        assert_sprintf "%100.50g", 123.45, "                                                  123.4500000000000028421709430404007434844970703125"
-        assert_sprintf "%#.12g", 12345.0, "12345.0000000"
+      it "works" do
+        assert_sprintf "%g", 123.45, "123.45"
+        assert_sprintf "%G", 123.45, "123.45"
+
+        assert_sprintf "%g", 1.2345e-5, "1.2345e-5"
+        assert_sprintf "%G", 1.2345e-5, "1.2345E-5"
+
+        assert_sprintf "%g", 1.2345e+25, "1.2345e+25"
+        assert_sprintf "%G", 1.2345e+25, "1.2345E+25"
+
+        assert_sprintf "%g", Float64::MAX, "1.79769e+308"
+        assert_sprintf "%g", Float64::MIN_POSITIVE, "2.22507e-308"
+        assert_sprintf "%g", Float64::MIN_SUBNORMAL, "4.94066e-324"
+        assert_sprintf "%g", 0.0, "0"
+        assert_sprintf "%g", -0.0, "-0"
+        assert_sprintf "%g", -Float64::MIN_SUBNORMAL, "-4.94066e-324"
+        assert_sprintf "%g", -Float64::MIN_POSITIVE, "-2.22507e-308"
+        assert_sprintf "%g", Float64::MIN, "-1.79769e+308"
+      end
+
+      context "width specifier" do
+        it "sets the minimum length of the string" do
+          assert_sprintf "%10g", 123.45, "    123.45"
+          assert_sprintf "%10g", -123.45, "   -123.45"
+          assert_sprintf "%+10g", 123.45, "   +123.45"
+
+          assert_sprintf "%7g", 123.45, " 123.45"
+          assert_sprintf "%7g", -123.45, "-123.45"
+          assert_sprintf "%+7g", 123.45, "+123.45"
+
+          assert_sprintf "%6g", 123.45, "123.45"
+          assert_sprintf "%6g", -123.45, "-123.45"
+          assert_sprintf "%+6g", 123.45, "+123.45"
+
+          assert_sprintf "%2g", 123.45, "123.45"
+          assert_sprintf "%2g", -123.45, "-123.45"
+          assert_sprintf "%+2g", 123.45, "+123.45"
+        end
+
+        it "left-justifies on negative width" do
+          assert_sprintf "%*g", [-10, 123.45], "123.45    "
+        end
+      end
+
+      context "precision specifier" do
+        it "sets the precision of the value" do
+          assert_sprintf "%.0g", 123.45, "1e+2"
+          assert_sprintf "%.1g", 123.45, "1e+2"
+          assert_sprintf "%.2g", 123.45, "1.2e+2"
+          assert_sprintf "%.3g", 123.45, "123"
+          assert_sprintf "%.4g", 123.45, "123.5"
+          assert_sprintf "%.5g", 123.45, "123.45"
+          assert_sprintf "%.6g", 123.45, "123.45"
+          assert_sprintf "%.7g", 123.45, "123.45"
+          assert_sprintf "%.8g", 123.45, "123.45"
+
+          assert_sprintf "%.1000g", 123.45, "123.4500000000000028421709430404007434844970703125"
+
+          assert_sprintf "%.0g", 1.23e-45, "1e-45"
+          assert_sprintf "%.1g", 1.23e-45, "1e-45"
+          assert_sprintf "%.2g", 1.23e-45, "1.2e-45"
+          assert_sprintf "%.3g", 1.23e-45, "1.23e-45"
+          assert_sprintf "%.4g", 1.23e-45, "1.23e-45"
+          assert_sprintf "%.5g", 1.23e-45, "1.23e-45"
+          assert_sprintf "%.6g", 1.23e-45, "1.23e-45"
+
+          assert_sprintf "%.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125e-5"
+        end
+
+        it "can be used with width" do
+          assert_sprintf "%10.1g", 123.45, "      1e+2"
+          assert_sprintf "%10.2g", 123.45, "    1.2e+2"
+          assert_sprintf "%10.3g", 123.45, "       123"
+          assert_sprintf "%10.4g", 123.45, "     123.5"
+          assert_sprintf "%10.5g", 123.45, "    123.45"
+          assert_sprintf "%10.1g", -123.45, "     -1e+2"
+          assert_sprintf "%10.2g", -123.45, "   -1.2e+2"
+          assert_sprintf "%10.3g", -123.45, "      -123"
+          assert_sprintf "%10.4g", -123.45, "    -123.5"
+          assert_sprintf "%10.5g", -123.45, "   -123.45"
+          assert_sprintf "%10.5g", 0, "         0"
+
+          assert_sprintf "%-10.1g", 123.45, "1e+2      "
+          assert_sprintf "%-10.2g", 123.45, "1.2e+2    "
+          assert_sprintf "%-10.3g", 123.45, "123       "
+          assert_sprintf "%-10.4g", 123.45, "123.5     "
+          assert_sprintf "%-10.5g", 123.45, "123.45    "
+          assert_sprintf "%-10.1g", -123.45, "-1e+2     "
+          assert_sprintf "%-10.2g", -123.45, "-1.2e+2   "
+          assert_sprintf "%-10.3g", -123.45, "-123      "
+          assert_sprintf "%-10.4g", -123.45, "-123.5    "
+          assert_sprintf "%-10.5g", -123.45, "-123.45   "
+          assert_sprintf "%-10.5g", 0, "0         "
+
+          assert_sprintf "%3.1g", 123.45, "1e+2"
+          assert_sprintf "%3.2g", 123.45, "1.2e+2"
+          assert_sprintf "%3.3g", 123.45, "123"
+          assert_sprintf "%3.4g", 123.45, "123.5"
+          assert_sprintf "%3.5g", 123.45, "123.45"
+          assert_sprintf "%3.1g", -123.45, "-1e+2"
+          assert_sprintf "%3.2g", -123.45, "-1.2e+2"
+          assert_sprintf "%3.3g", -123.45, "-123"
+          assert_sprintf "%3.4g", -123.45, "-123.5"
+          assert_sprintf "%3.5g", -123.45, "-123.45"
+
+          assert_sprintf "%1000.800g", 123.45, "#{" " * 950}123.4500000000000028421709430404007434844970703125"
+        end
+
+        it "is ignored if precision argument is negative" do
+          assert_sprintf "%.*g", [-2, 123.45], "123.45"
+        end
+      end
+
+      context "sharp flag" do
+        it "prints decimal point and trailing zeros" do
+          assert_sprintf "%#.0g", 12345, "1.e+4"
+          assert_sprintf "%#.6g", 12345, "12345.0"
+          assert_sprintf "%#.10g", 12345, "12345.00000"
+          assert_sprintf "%#.100g", 12345, "12345.#{"0" * 95}"
+          assert_sprintf "%#.1000g", 12345, "12345.#{"0" * 995}"
+
+          assert_sprintf "%#.0g", 1e-5, "1.e-5"
+          assert_sprintf "%#.6g", 1e-5, "1.00000e-5"
+          assert_sprintf "%#.10g", 1e-5, "1.000000000e-5"
+          assert_sprintf "%#.100g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 35}e-5"
+          assert_sprintf "%#.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 935}e-5"
+
+          assert_sprintf "%#15.0g", 12345, "          1.e+4"
+          assert_sprintf "%#15.6g", 12345, "        12345.0"
+          assert_sprintf "%#15.10g", 12345, "    12345.00000"
+        end
+      end
+
+      context "plus flag" do
+        it "writes a plus sign for positive values" do
+          assert_sprintf "%+g", 123.45, "+123.45"
+          assert_sprintf "%+g", -123.45, "-123.45"
+          assert_sprintf "%+g", 0.0, "+0"
+        end
+
+        it "writes plus sign after left space-padding" do
+          assert_sprintf "%+10g", 123.45, "   +123.45"
+          assert_sprintf "%+10g", -123.45, "   -123.45"
+          assert_sprintf "%+10g", 0.0, "        +0"
+        end
+
+        it "writes plus sign before left zero-padding" do
+          assert_sprintf "%+010g", 123.45, "+000123.45"
+          assert_sprintf "%+010g", -123.45, "-000123.45"
+          assert_sprintf "%+010g", 0.0, "+000000000"
+        end
+      end
+
+      context "space flag" do
+        it "writes a space for positive values" do
+          assert_sprintf "% g", 123.45, " 123.45"
+          assert_sprintf "% g", -123.45, "-123.45"
+          assert_sprintf "% g", 0.0, " 0"
+        end
+
+        it "writes space before left space-padding" do
+          assert_sprintf "% 10g", 123.45, "    123.45"
+          assert_sprintf "% 10g", -123.45, "   -123.45"
+          assert_sprintf "% 10g", 0.0, "         0"
+
+          assert_sprintf "% 010g", 123.45, " 000123.45"
+          assert_sprintf "% 010g", -123.45, "-000123.45"
+          assert_sprintf "% 010g", 0.0, " 000000000"
+        end
+
+        it "is ignored if plus flag is also specified" do
+          assert_sprintf "% +g", 123.45, "+123.45"
+          assert_sprintf "%+ g", -123.45, "-123.45"
+        end
+      end
+
+      context "zero flag" do
+        it "left-pads the result with zeros" do
+          assert_sprintf "%010g", 123.45, "0000123.45"
+          assert_sprintf "%010g", -123.45, "-000123.45"
+          assert_sprintf "%010g", 0.0, "0000000000"
+        end
+
+        it "is ignored if string is left-justified" do
+          assert_sprintf "%-010g", 123.45, "123.45    "
+          assert_sprintf "%-010g", -123.45, "-123.45   "
+          assert_sprintf "%-010g", 0.0, "0         "
+        end
+
+        it "can be used with precision" do
+          assert_sprintf "%010.2g", 123.45, "00001.2e+2"
+          assert_sprintf "%010.2g", -123.45, "-0001.2e+2"
+          assert_sprintf "%010.2g", 0.0, "0000000000"
+        end
+      end
+
+      context "minus flag" do
+        it "left-justifies the string" do
+          assert_sprintf "%-10g", 123.45, "123.45    "
+          assert_sprintf "%-10g", -123.45, "-123.45   "
+          assert_sprintf "%-10g", 0.0, "0         "
+
+          assert_sprintf "%- 10g", 123.45, " 123.45   "
+          assert_sprintf "%- 10g", -123.45, "-123.45   "
+          assert_sprintf "%- 10g", 0.0, " 0        "
+        end
       end
     end
 
diff --git a/src/float/printer/ryu_printf.cr b/src/float/printer/ryu_printf.cr
index d44a2fa8739b..005e575c3806 100644
--- a/src/float/printer/ryu_printf.cr
+++ b/src/float/printer/ryu_printf.cr
@@ -613,6 +613,76 @@ module Float::Printer::RyuPrintf
     index
   end
 
+  private MAX_FIXED_PRECISION =  66_u32
+  private MAX_SCI_PRECISION   = 766_u32
+
+  # Source port of Microsoft STL's `std::to_chars` based on:
+  #
+  # * https://github.com/ulfjack/ryu/pull/185/files
+  # * https://github.com/microsoft/STL/blob/a8888806c6960f1687590ffd4244794c753aa819/stl/inc/charconv#L2324
+  # * https://github.com/llvm/llvm-project/blob/701f64790520790f75b1f948a752472d421ddaa3/libcxx/src/include/to_chars_floating_point.h#L836
+  def self.d2gen_buffered_n(d : Float64, precision : UInt32, result : UInt8*, alternative : Bool = false)
+    if d == 0
+      result[0] = '0'.ord.to_u8!
+      return {1, 0}
+    end
+
+    precision = precision.clamp(1_u32, 1000000_u32)
+    if precision <= MAX_SPECIAL_P
+      table_begin = SPECIAL_X.to_unsafe + (precision &- 1) * (precision &+ 10) // 2
+      table_length = precision.to_i32! &+ 5
+    else
+      table_begin = ORDINARY_X.to_unsafe
+      table_length = {precision, MAX_ORDINARY_P}.min.to_i32! &+ 5
+    end
+
+    bits = d.unsafe_as(UInt64)
+    index = 0
+    while index < table_length
+      break if bits <= table_begin[index]
+      index &+= 1
+    end
+
+    sci_exp_x = index &- 5
+    use_fixed_notation = precision > sci_exp_x && sci_exp_x >= -4
+
+    significand_last = exponent_first = exponent_last = Pointer(UInt8).null
+
+    # Write into the local buffer.
+    if use_fixed_notation
+      effective_precision = precision &- 1 &- sci_exp_x
+      max_precision = MAX_FIXED_PRECISION
+      len = d2fixed_buffered_n(d, {effective_precision, max_precision}.min, result)
+      significand_last = result + len
+    else
+      effective_precision = precision &- 1
+      max_precision = MAX_SCI_PRECISION
+      len = d2exp_buffered_n(d, {effective_precision, max_precision}.min, result)
+      exponent_first = result + Slice.new(result, len).fast_index('e'.ord.to_u8!, 0).not_nil!
+      significand_last = exponent_first
+      exponent_last = result + len
+    end
+
+    # If we printed a decimal point followed by digits, perform zero-trimming.
+    if effective_precision > 0 && !alternative
+      while significand_last[-1] === '0' # will stop at '.' or a nonzero digit
+        significand_last -= 1
+      end
+
+      if significand_last[-1] === '.'
+        significand_last -= 1
+      end
+    end
+
+    # Copy the exponent to the output range.
+    unless use_fixed_notation
+      exponent_first.move_to(significand_last, exponent_last - exponent_first)
+    end
+
+    extra_zeros = effective_precision > max_precision ? effective_precision &- max_precision : 0_u32
+    {(significand_last - result + (exponent_last - exponent_first)).to_i32!, extra_zeros.to_i32!}
+  end
+
   def self.d2fixed(d : Float64, precision : Int)
     String.new(2000) do |buffer|
       len = d2fixed_buffered_n(d, precision.to_u32, buffer)
@@ -626,4 +696,11 @@ module Float::Printer::RyuPrintf
       {len, len}
     end
   end
+
+  def self.d2gen(d : Float64, precision : Int)
+    String.new(773) do |buffer|
+      len, _ = d2gen_buffered_n(d, precision.to_u32, buffer)
+      {len, len}
+    end
+  end
 end
diff --git a/src/float/printer/ryu_printf_table.cr b/src/float/printer/ryu_printf_table.cr
index dc733c492991..6e16b939f16c 100644
--- a/src/float/printer/ryu_printf_table.cr
+++ b/src/float/printer/ryu_printf_table.cr
@@ -16,6 +16,533 @@ module Float::Printer::RyuPrintf
     array << values
   end
 
+  # Special constants for `%g` formatting; for details refer to
+  # https://github.com/ulfjack/ryu/pull/185/files or
+  # https://github.com/microsoft/STL/blob/a8888806c6960f1687590ffd4244794c753aa819/stl/inc/xcharconv_tables.h
+
+  private MAX_SPECIAL_P = 15_u32
+
+  private SPECIAL_X = begin
+    data = Array(UInt64).new(195)
+    put(data, 0x3F18E757928E0C9Du64)
+    put(data, 0x3F4F212D77318FC5u64)
+    put(data, 0x3F8374BC6A7EF9DBu64)
+    put(data, 0x3FB851EB851EB851u64)
+    put(data, 0x3FEE666666666666u64)
+    put(data, 0x4022FFFFFFFFFFFFu64)
+    put(data, 0x3F1A1554FBDAD751u64)
+    put(data, 0x3F504D551D68C692u64)
+    put(data, 0x3F8460AA64C2F837u64)
+    put(data, 0x3FB978D4FDF3B645u64)
+    put(data, 0x3FEFD70A3D70A3D7u64)
+    put(data, 0x4023E66666666666u64)
+    put(data, 0x4058DFFFFFFFFFFFu64)
+    put(data, 0x3F1A3387ECC8EB96u64)
+    put(data, 0x3F506034F3FD933Eu64)
+    put(data, 0x3F84784230FCF80Du64)
+    put(data, 0x3FB99652BD3C3611u64)
+    put(data, 0x3FEFFBE76C8B4395u64)
+    put(data, 0x4023FD70A3D70A3Du64)
+    put(data, 0x4058FCCCCCCCCCCCu64)
+    put(data, 0x408F3BFFFFFFFFFFu64)
+    put(data, 0x3F1A368D04E0BA6Au64)
+    put(data, 0x3F506218230C7482u64)
+    put(data, 0x3F847A9E2BCF91A3u64)
+    put(data, 0x3FB99945B6C3760Bu64)
+    put(data, 0x3FEFFF972474538Eu64)
+    put(data, 0x4023FFBE76C8B439u64)
+    put(data, 0x4058FFAE147AE147u64)
+    put(data, 0x408F3F9999999999u64)
+    put(data, 0x40C387BFFFFFFFFFu64)
+    put(data, 0x3F1A36DA54164F19u64)
+    put(data, 0x3F506248748DF16Fu64)
+    put(data, 0x3F847ADA91B16DCBu64)
+    put(data, 0x3FB99991361DC93Eu64)
+    put(data, 0x3FEFFFF583A53B8Eu64)
+    put(data, 0x4023FFF972474538u64)
+    put(data, 0x4058FFF7CED91687u64)
+    put(data, 0x408F3FF5C28F5C28u64)
+    put(data, 0x40C387F999999999u64)
+    put(data, 0x40F869F7FFFFFFFFu64)
+    put(data, 0x3F1A36E20F35445Du64)
+    put(data, 0x3F50624D49814ABAu64)
+    put(data, 0x3F847AE09BE19D69u64)
+    put(data, 0x3FB99998C2DA04C3u64)
+    put(data, 0x3FEFFFFEF39085F4u64)
+    put(data, 0x4023FFFF583A53B8u64)
+    put(data, 0x4058FFFF2E48E8A7u64)
+    put(data, 0x408F3FFEF9DB22D0u64)
+    put(data, 0x40C387FF5C28F5C2u64)
+    put(data, 0x40F869FF33333333u64)
+    put(data, 0x412E847EFFFFFFFFu64)
+    put(data, 0x3F1A36E2D51EC34Bu64)
+    put(data, 0x3F50624DC5333A0Eu64)
+    put(data, 0x3F847AE136800892u64)
+    put(data, 0x3FB9999984200AB7u64)
+    put(data, 0x3FEFFFFFE5280D65u64)
+    put(data, 0x4023FFFFEF39085Fu64)
+    put(data, 0x4058FFFFEB074A77u64)
+    put(data, 0x408F3FFFE5C91D14u64)
+    put(data, 0x40C387FFEF9DB22Du64)
+    put(data, 0x40F869FFEB851EB8u64)
+    put(data, 0x412E847FE6666666u64)
+    put(data, 0x416312CFEFFFFFFFu64)
+    put(data, 0x3F1A36E2E8E94FFCu64)
+    put(data, 0x3F50624DD191D1FDu64)
+    put(data, 0x3F847AE145F6467Du64)
+    put(data, 0x3FB999999773D81Cu64)
+    put(data, 0x3FEFFFFFFD50CE23u64)
+    put(data, 0x4023FFFFFE5280D6u64)
+    put(data, 0x4058FFFFFDE7210Bu64)
+    put(data, 0x408F3FFFFD60E94Eu64)
+    put(data, 0x40C387FFFE5C91D1u64)
+    put(data, 0x40F869FFFDF3B645u64)
+    put(data, 0x412E847FFD70A3D7u64)
+    put(data, 0x416312CFFE666666u64)
+    put(data, 0x4197D783FDFFFFFFu64)
+    put(data, 0x3F1A36E2EAE3F7A7u64)
+    put(data, 0x3F50624DD2CE7AC8u64)
+    put(data, 0x3F847AE14782197Bu64)
+    put(data, 0x3FB9999999629FD9u64)
+    put(data, 0x3FEFFFFFFFBB47D0u64)
+    put(data, 0x4023FFFFFFD50CE2u64)
+    put(data, 0x4058FFFFFFCA501Au64)
+    put(data, 0x408F3FFFFFBCE421u64)
+    put(data, 0x40C387FFFFD60E94u64)
+    put(data, 0x40F869FFFFCB923Au64)
+    put(data, 0x412E847FFFBE76C8u64)
+    put(data, 0x416312CFFFD70A3Du64)
+    put(data, 0x4197D783FFCCCCCCu64)
+    put(data, 0x41CDCD64FFBFFFFFu64)
+    put(data, 0x3F1A36E2EB16A205u64)
+    put(data, 0x3F50624DD2EE2543u64)
+    put(data, 0x3F847AE147A9AE94u64)
+    put(data, 0x3FB9999999941A39u64)
+    put(data, 0x3FEFFFFFFFF920C8u64)
+    put(data, 0x4023FFFFFFFBB47Du64)
+    put(data, 0x4058FFFFFFFAA19Cu64)
+    put(data, 0x408F3FFFFFF94A03u64)
+    put(data, 0x40C387FFFFFBCE42u64)
+    put(data, 0x40F869FFFFFAC1D2u64)
+    put(data, 0x412E847FFFF97247u64)
+    put(data, 0x416312CFFFFBE76Cu64)
+    put(data, 0x4197D783FFFAE147u64)
+    put(data, 0x41CDCD64FFF99999u64)
+    put(data, 0x4202A05F1FFBFFFFu64)
+    put(data, 0x3F1A36E2EB1BB30Fu64)
+    put(data, 0x3F50624DD2F14FE9u64)
+    put(data, 0x3F847AE147ADA3E3u64)
+    put(data, 0x3FB9999999990CDCu64)
+    put(data, 0x3FEFFFFFFFFF5014u64)
+    put(data, 0x4023FFFFFFFF920Cu64)
+    put(data, 0x4058FFFFFFFF768Fu64)
+    put(data, 0x408F3FFFFFFF5433u64)
+    put(data, 0x40C387FFFFFF94A0u64)
+    put(data, 0x40F869FFFFFF79C8u64)
+    put(data, 0x412E847FFFFF583Au64)
+    put(data, 0x416312CFFFFF9724u64)
+    put(data, 0x4197D783FFFF7CEDu64)
+    put(data, 0x41CDCD64FFFF5C28u64)
+    put(data, 0x4202A05F1FFF9999u64)
+    put(data, 0x42374876E7FF7FFFu64)
+    put(data, 0x3F1A36E2EB1C34C3u64)
+    put(data, 0x3F50624DD2F1A0FAu64)
+    put(data, 0x3F847AE147AE0938u64)
+    put(data, 0x3FB9999999998B86u64)
+    put(data, 0x3FEFFFFFFFFFEE68u64)
+    put(data, 0x4023FFFFFFFFF501u64)
+    put(data, 0x4058FFFFFFFFF241u64)
+    put(data, 0x408F3FFFFFFFEED1u64)
+    put(data, 0x40C387FFFFFFF543u64)
+    put(data, 0x40F869FFFFFFF294u64)
+    put(data, 0x412E847FFFFFEF39u64)
+    put(data, 0x416312CFFFFFF583u64)
+    put(data, 0x4197D783FFFFF2E4u64)
+    put(data, 0x41CDCD64FFFFEF9Du64)
+    put(data, 0x4202A05F1FFFF5C2u64)
+    put(data, 0x42374876E7FFF333u64)
+    put(data, 0x426D1A94A1FFEFFFu64)
+    put(data, 0x3F1A36E2EB1C41BBu64)
+    put(data, 0x3F50624DD2F1A915u64)
+    put(data, 0x3F847AE147AE135Au64)
+    put(data, 0x3FB9999999999831u64)
+    put(data, 0x3FEFFFFFFFFFFE3Du64)
+    put(data, 0x4023FFFFFFFFFEE6u64)
+    put(data, 0x4058FFFFFFFFFEA0u64)
+    put(data, 0x408F3FFFFFFFFE48u64)
+    put(data, 0x40C387FFFFFFFEEDu64)
+    put(data, 0x40F869FFFFFFFEA8u64)
+    put(data, 0x412E847FFFFFFE52u64)
+    put(data, 0x416312CFFFFFFEF3u64)
+    put(data, 0x4197D783FFFFFEB0u64)
+    put(data, 0x41CDCD64FFFFFE5Cu64)
+    put(data, 0x4202A05F1FFFFEF9u64)
+    put(data, 0x42374876E7FFFEB8u64)
+    put(data, 0x426D1A94A1FFFE66u64)
+    put(data, 0x42A2309CE53FFEFFu64)
+    put(data, 0x3F1A36E2EB1C4307u64)
+    put(data, 0x3F50624DD2F1A9E4u64)
+    put(data, 0x3F847AE147AE145Eu64)
+    put(data, 0x3FB9999999999975u64)
+    put(data, 0x3FEFFFFFFFFFFFD2u64)
+    put(data, 0x4023FFFFFFFFFFE3u64)
+    put(data, 0x4058FFFFFFFFFFDCu64)
+    put(data, 0x408F3FFFFFFFFFD4u64)
+    put(data, 0x40C387FFFFFFFFE4u64)
+    put(data, 0x40F869FFFFFFFFDDu64)
+    put(data, 0x412E847FFFFFFFD5u64)
+    put(data, 0x416312CFFFFFFFE5u64)
+    put(data, 0x4197D783FFFFFFDEu64)
+    put(data, 0x41CDCD64FFFFFFD6u64)
+    put(data, 0x4202A05F1FFFFFE5u64)
+    put(data, 0x42374876E7FFFFDFu64)
+    put(data, 0x426D1A94A1FFFFD7u64)
+    put(data, 0x42A2309CE53FFFE6u64)
+    put(data, 0x42D6BCC41E8FFFDFu64)
+    put(data, 0x3F1A36E2EB1C4328u64)
+    put(data, 0x3F50624DD2F1A9F9u64)
+    put(data, 0x3F847AE147AE1477u64)
+    put(data, 0x3FB9999999999995u64)
+    put(data, 0x3FEFFFFFFFFFFFFBu64)
+    put(data, 0x4023FFFFFFFFFFFDu64)
+    put(data, 0x4058FFFFFFFFFFFCu64)
+    put(data, 0x408F3FFFFFFFFFFBu64)
+    put(data, 0x40C387FFFFFFFFFDu64)
+    put(data, 0x40F869FFFFFFFFFCu64)
+    put(data, 0x412E847FFFFFFFFBu64)
+    put(data, 0x416312CFFFFFFFFDu64)
+    put(data, 0x4197D783FFFFFFFCu64)
+    put(data, 0x41CDCD64FFFFFFFBu64)
+    put(data, 0x4202A05F1FFFFFFDu64)
+    put(data, 0x42374876E7FFFFFCu64)
+    put(data, 0x426D1A94A1FFFFFBu64)
+    put(data, 0x42A2309CE53FFFFDu64)
+    put(data, 0x42D6BCC41E8FFFFCu64)
+    put(data, 0x430C6BF52633FFFBu64)
+    data
+  end
+
+  private MAX_ORDINARY_P = 309_u32
+
+  private ORDINARY_X = begin
+    data = Array(UInt64).new(314)
+    put(data, 0x3F1A36E2EB1C432Cu64)
+    put(data, 0x3F50624DD2F1A9FBu64)
+    put(data, 0x3F847AE147AE147Au64)
+    put(data, 0x3FB9999999999999u64)
+    put(data, 0x3FEFFFFFFFFFFFFFu64)
+    put(data, 0x4023FFFFFFFFFFFFu64)
+    put(data, 0x4058FFFFFFFFFFFFu64)
+    put(data, 0x408F3FFFFFFFFFFFu64)
+    put(data, 0x40C387FFFFFFFFFFu64)
+    put(data, 0x40F869FFFFFFFFFFu64)
+    put(data, 0x412E847FFFFFFFFFu64)
+    put(data, 0x416312CFFFFFFFFFu64)
+    put(data, 0x4197D783FFFFFFFFu64)
+    put(data, 0x41CDCD64FFFFFFFFu64)
+    put(data, 0x4202A05F1FFFFFFFu64)
+    put(data, 0x42374876E7FFFFFFu64)
+    put(data, 0x426D1A94A1FFFFFFu64)
+    put(data, 0x42A2309CE53FFFFFu64)
+    put(data, 0x42D6BCC41E8FFFFFu64)
+    put(data, 0x430C6BF52633FFFFu64)
+    put(data, 0x4341C37937E07FFFu64)
+    put(data, 0x4376345785D89FFFu64)
+    put(data, 0x43ABC16D674EC7FFu64)
+    put(data, 0x43E158E460913CFFu64)
+    put(data, 0x4415AF1D78B58C3Fu64)
+    put(data, 0x444B1AE4D6E2EF4Fu64)
+    put(data, 0x4480F0CF064DD591u64)
+    put(data, 0x44B52D02C7E14AF6u64)
+    put(data, 0x44EA784379D99DB4u64)
+    put(data, 0x45208B2A2C280290u64)
+    put(data, 0x4554ADF4B7320334u64)
+    put(data, 0x4589D971E4FE8401u64)
+    put(data, 0x45C027E72F1F1281u64)
+    put(data, 0x45F431E0FAE6D721u64)
+    put(data, 0x46293E5939A08CE9u64)
+    put(data, 0x465F8DEF8808B024u64)
+    put(data, 0x4693B8B5B5056E16u64)
+    put(data, 0x46C8A6E32246C99Cu64)
+    put(data, 0x46FED09BEAD87C03u64)
+    put(data, 0x4733426172C74D82u64)
+    put(data, 0x476812F9CF7920E2u64)
+    put(data, 0x479E17B84357691Bu64)
+    put(data, 0x47D2CED32A16A1B1u64)
+    put(data, 0x48078287F49C4A1Du64)
+    put(data, 0x483D6329F1C35CA4u64)
+    put(data, 0x48725DFA371A19E6u64)
+    put(data, 0x48A6F578C4E0A060u64)
+    put(data, 0x48DCB2D6F618C878u64)
+    put(data, 0x4911EFC659CF7D4Bu64)
+    put(data, 0x49466BB7F0435C9Eu64)
+    put(data, 0x497C06A5EC5433C6u64)
+    put(data, 0x49B18427B3B4A05Bu64)
+    put(data, 0x49E5E531A0A1C872u64)
+    put(data, 0x4A1B5E7E08CA3A8Fu64)
+    put(data, 0x4A511B0EC57E6499u64)
+    put(data, 0x4A8561D276DDFDC0u64)
+    put(data, 0x4ABABA4714957D30u64)
+    put(data, 0x4AF0B46C6CDD6E3Eu64)
+    put(data, 0x4B24E1878814C9CDu64)
+    put(data, 0x4B5A19E96A19FC40u64)
+    put(data, 0x4B905031E2503DA8u64)
+    put(data, 0x4BC4643E5AE44D12u64)
+    put(data, 0x4BF97D4DF19D6057u64)
+    put(data, 0x4C2FDCA16E04B86Du64)
+    put(data, 0x4C63E9E4E4C2F344u64)
+    put(data, 0x4C98E45E1DF3B015u64)
+    put(data, 0x4CCF1D75A5709C1Au64)
+    put(data, 0x4D03726987666190u64)
+    put(data, 0x4D384F03E93FF9F4u64)
+    put(data, 0x4D6E62C4E38FF872u64)
+    put(data, 0x4DA2FDBB0E39FB47u64)
+    put(data, 0x4DD7BD29D1C87A19u64)
+    put(data, 0x4E0DAC74463A989Fu64)
+    put(data, 0x4E428BC8ABE49F63u64)
+    put(data, 0x4E772EBAD6DDC73Cu64)
+    put(data, 0x4EACFA698C95390Bu64)
+    put(data, 0x4EE21C81F7DD43A7u64)
+    put(data, 0x4F16A3A275D49491u64)
+    put(data, 0x4F4C4C8B1349B9B5u64)
+    put(data, 0x4F81AFD6EC0E1411u64)
+    put(data, 0x4FB61BCCA7119915u64)
+    put(data, 0x4FEBA2BFD0D5FF5Bu64)
+    put(data, 0x502145B7E285BF98u64)
+    put(data, 0x50559725DB272F7Fu64)
+    put(data, 0x508AFCEF51F0FB5Eu64)
+    put(data, 0x50C0DE1593369D1Bu64)
+    put(data, 0x50F5159AF8044462u64)
+    put(data, 0x512A5B01B605557Au64)
+    put(data, 0x516078E111C3556Cu64)
+    put(data, 0x5194971956342AC7u64)
+    put(data, 0x51C9BCDFABC13579u64)
+    put(data, 0x5200160BCB58C16Cu64)
+    put(data, 0x52341B8EBE2EF1C7u64)
+    put(data, 0x526922726DBAAE39u64)
+    put(data, 0x529F6B0F092959C7u64)
+    put(data, 0x52D3A2E965B9D81Cu64)
+    put(data, 0x53088BA3BF284E23u64)
+    put(data, 0x533EAE8CAEF261ACu64)
+    put(data, 0x53732D17ED577D0Bu64)
+    put(data, 0x53A7F85DE8AD5C4Eu64)
+    put(data, 0x53DDF67562D8B362u64)
+    put(data, 0x5412BA095DC7701Du64)
+    put(data, 0x5447688BB5394C25u64)
+    put(data, 0x547D42AEA2879F2Eu64)
+    put(data, 0x54B249AD2594C37Cu64)
+    put(data, 0x54E6DC186EF9F45Cu64)
+    put(data, 0x551C931E8AB87173u64)
+    put(data, 0x5551DBF316B346E7u64)
+    put(data, 0x558652EFDC6018A1u64)
+    put(data, 0x55BBE7ABD3781ECAu64)
+    put(data, 0x55F170CB642B133Eu64)
+    put(data, 0x5625CCFE3D35D80Eu64)
+    put(data, 0x565B403DCC834E11u64)
+    put(data, 0x569108269FD210CBu64)
+    put(data, 0x56C54A3047C694FDu64)
+    put(data, 0x56FA9CBC59B83A3Du64)
+    put(data, 0x5730A1F5B8132466u64)
+    put(data, 0x5764CA732617ED7Fu64)
+    put(data, 0x5799FD0FEF9DE8DFu64)
+    put(data, 0x57D03E29F5C2B18Bu64)
+    put(data, 0x58044DB473335DEEu64)
+    put(data, 0x583961219000356Au64)
+    put(data, 0x586FB969F40042C5u64)
+    put(data, 0x58A3D3E2388029BBu64)
+    put(data, 0x58D8C8DAC6A0342Au64)
+    put(data, 0x590EFB1178484134u64)
+    put(data, 0x59435CEAEB2D28C0u64)
+    put(data, 0x59783425A5F872F1u64)
+    put(data, 0x59AE412F0F768FADu64)
+    put(data, 0x59E2E8BD69AA19CCu64)
+    put(data, 0x5A17A2ECC414A03Fu64)
+    put(data, 0x5A4D8BA7F519C84Fu64)
+    put(data, 0x5A827748F9301D31u64)
+    put(data, 0x5AB7151B377C247Eu64)
+    put(data, 0x5AECDA62055B2D9Du64)
+    put(data, 0x5B22087D4358FC82u64)
+    put(data, 0x5B568A9C942F3BA3u64)
+    put(data, 0x5B8C2D43B93B0A8Bu64)
+    put(data, 0x5BC19C4A53C4E697u64)
+    put(data, 0x5BF6035CE8B6203Du64)
+    put(data, 0x5C2B843422E3A84Cu64)
+    put(data, 0x5C6132A095CE492Fu64)
+    put(data, 0x5C957F48BB41DB7Bu64)
+    put(data, 0x5CCADF1AEA12525Au64)
+    put(data, 0x5D00CB70D24B7378u64)
+    put(data, 0x5D34FE4D06DE5056u64)
+    put(data, 0x5D6A3DE04895E46Cu64)
+    put(data, 0x5DA066AC2D5DAEC3u64)
+    put(data, 0x5DD4805738B51A74u64)
+    put(data, 0x5E09A06D06E26112u64)
+    put(data, 0x5E400444244D7CABu64)
+    put(data, 0x5E7405552D60DBD6u64)
+    put(data, 0x5EA906AA78B912CBu64)
+    put(data, 0x5EDF485516E7577Eu64)
+    put(data, 0x5F138D352E5096AFu64)
+    put(data, 0x5F48708279E4BC5Au64)
+    put(data, 0x5F7E8CA3185DEB71u64)
+    put(data, 0x5FB317E5EF3AB327u64)
+    put(data, 0x5FE7DDDF6B095FF0u64)
+    put(data, 0x601DD55745CBB7ECu64)
+    put(data, 0x6052A5568B9F52F4u64)
+    put(data, 0x60874EAC2E8727B1u64)
+    put(data, 0x60BD22573A28F19Du64)
+    put(data, 0x60F2357684599702u64)
+    put(data, 0x6126C2D4256FFCC2u64)
+    put(data, 0x615C73892ECBFBF3u64)
+    put(data, 0x6191C835BD3F7D78u64)
+    put(data, 0x61C63A432C8F5CD6u64)
+    put(data, 0x61FBC8D3F7B3340Bu64)
+    put(data, 0x62315D847AD00087u64)
+    put(data, 0x6265B4E5998400A9u64)
+    put(data, 0x629B221EFFE500D3u64)
+    put(data, 0x62D0F5535FEF2084u64)
+    put(data, 0x630532A837EAE8A5u64)
+    put(data, 0x633A7F5245E5A2CEu64)
+    put(data, 0x63708F936BAF85C1u64)
+    put(data, 0x63A4B378469B6731u64)
+    put(data, 0x63D9E056584240FDu64)
+    put(data, 0x64102C35F729689Eu64)
+    put(data, 0x6444374374F3C2C6u64)
+    put(data, 0x647945145230B377u64)
+    put(data, 0x64AF965966BCE055u64)
+    put(data, 0x64E3BDF7E0360C35u64)
+    put(data, 0x6518AD75D8438F43u64)
+    put(data, 0x654ED8D34E547313u64)
+    put(data, 0x6583478410F4C7ECu64)
+    put(data, 0x65B819651531F9E7u64)
+    put(data, 0x65EE1FBE5A7E7861u64)
+    put(data, 0x6622D3D6F88F0B3Cu64)
+    put(data, 0x665788CCB6B2CE0Cu64)
+    put(data, 0x668D6AFFE45F818Fu64)
+    put(data, 0x66C262DFEEBBB0F9u64)
+    put(data, 0x66F6FB97EA6A9D37u64)
+    put(data, 0x672CBA7DE5054485u64)
+    put(data, 0x6761F48EAF234AD3u64)
+    put(data, 0x679671B25AEC1D88u64)
+    put(data, 0x67CC0E1EF1A724EAu64)
+    put(data, 0x680188D357087712u64)
+    put(data, 0x6835EB082CCA94D7u64)
+    put(data, 0x686B65CA37FD3A0Du64)
+    put(data, 0x68A11F9E62FE4448u64)
+    put(data, 0x68D56785FBBDD55Au64)
+    put(data, 0x690AC1677AAD4AB0u64)
+    put(data, 0x6940B8E0ACAC4EAEu64)
+    put(data, 0x6974E718D7D7625Au64)
+    put(data, 0x69AA20DF0DCD3AF0u64)
+    put(data, 0x69E0548B68A044D6u64)
+    put(data, 0x6A1469AE42C8560Cu64)
+    put(data, 0x6A498419D37A6B8Fu64)
+    put(data, 0x6A7FE52048590672u64)
+    put(data, 0x6AB3EF342D37A407u64)
+    put(data, 0x6AE8EB0138858D09u64)
+    put(data, 0x6B1F25C186A6F04Cu64)
+    put(data, 0x6B537798F428562Fu64)
+    put(data, 0x6B88557F31326BBBu64)
+    put(data, 0x6BBE6ADEFD7F06AAu64)
+    put(data, 0x6BF302CB5E6F642Au64)
+    put(data, 0x6C27C37E360B3D35u64)
+    put(data, 0x6C5DB45DC38E0C82u64)
+    put(data, 0x6C9290BA9A38C7D1u64)
+    put(data, 0x6CC734E940C6F9C5u64)
+    put(data, 0x6CFD022390F8B837u64)
+    put(data, 0x6D3221563A9B7322u64)
+    put(data, 0x6D66A9ABC9424FEBu64)
+    put(data, 0x6D9C5416BB92E3E6u64)
+    put(data, 0x6DD1B48E353BCE6Fu64)
+    put(data, 0x6E0621B1C28AC20Bu64)
+    put(data, 0x6E3BAA1E332D728Eu64)
+    put(data, 0x6E714A52DFFC6799u64)
+    put(data, 0x6EA59CE797FB817Fu64)
+    put(data, 0x6EDB04217DFA61DFu64)
+    put(data, 0x6F10E294EEBC7D2Bu64)
+    put(data, 0x6F451B3A2A6B9C76u64)
+    put(data, 0x6F7A6208B5068394u64)
+    put(data, 0x6FB07D457124123Cu64)
+    put(data, 0x6FE49C96CD6D16CBu64)
+    put(data, 0x7019C3BC80C85C7Eu64)
+    put(data, 0x70501A55D07D39CFu64)
+    put(data, 0x708420EB449C8842u64)
+    put(data, 0x70B9292615C3AA53u64)
+    put(data, 0x70EF736F9B3494E8u64)
+    put(data, 0x7123A825C100DD11u64)
+    put(data, 0x7158922F31411455u64)
+    put(data, 0x718EB6BAFD91596Bu64)
+    put(data, 0x71C33234DE7AD7E2u64)
+    put(data, 0x71F7FEC216198DDBu64)
+    put(data, 0x722DFE729B9FF152u64)
+    put(data, 0x7262BF07A143F6D3u64)
+    put(data, 0x72976EC98994F488u64)
+    put(data, 0x72CD4A7BEBFA31AAu64)
+    put(data, 0x73024E8D737C5F0Au64)
+    put(data, 0x7336E230D05B76CDu64)
+    put(data, 0x736C9ABD04725480u64)
+    put(data, 0x73A1E0B622C774D0u64)
+    put(data, 0x73D658E3AB795204u64)
+    put(data, 0x740BEF1C9657A685u64)
+    put(data, 0x74417571DDF6C813u64)
+    put(data, 0x7475D2CE55747A18u64)
+    put(data, 0x74AB4781EAD1989Eu64)
+    put(data, 0x74E10CB132C2FF63u64)
+    put(data, 0x75154FDD7F73BF3Bu64)
+    put(data, 0x754AA3D4DF50AF0Au64)
+    put(data, 0x7580A6650B926D66u64)
+    put(data, 0x75B4CFFE4E7708C0u64)
+    put(data, 0x75EA03FDE214CAF0u64)
+    put(data, 0x7620427EAD4CFED6u64)
+    put(data, 0x7654531E58A03E8Bu64)
+    put(data, 0x768967E5EEC84E2Eu64)
+    put(data, 0x76BFC1DF6A7A61BAu64)
+    put(data, 0x76F3D92BA28C7D14u64)
+    put(data, 0x7728CF768B2F9C59u64)
+    put(data, 0x775F03542DFB8370u64)
+    put(data, 0x779362149CBD3226u64)
+    put(data, 0x77C83A99C3EC7EAFu64)
+    put(data, 0x77FE494034E79E5Bu64)
+    put(data, 0x7832EDC82110C2F9u64)
+    put(data, 0x7867A93A2954F3B7u64)
+    put(data, 0x789D9388B3AA30A5u64)
+    put(data, 0x78D27C35704A5E67u64)
+    put(data, 0x79071B42CC5CF601u64)
+    put(data, 0x793CE2137F743381u64)
+    put(data, 0x79720D4C2FA8A030u64)
+    put(data, 0x79A6909F3B92C83Du64)
+    put(data, 0x79DC34C70A777A4Cu64)
+    put(data, 0x7A11A0FC668AAC6Fu64)
+    put(data, 0x7A46093B802D578Bu64)
+    put(data, 0x7A7B8B8A6038AD6Eu64)
+    put(data, 0x7AB137367C236C65u64)
+    put(data, 0x7AE585041B2C477Eu64)
+    put(data, 0x7B1AE64521F7595Eu64)
+    put(data, 0x7B50CFEB353A97DAu64)
+    put(data, 0x7B8503E602893DD1u64)
+    put(data, 0x7BBA44DF832B8D45u64)
+    put(data, 0x7BF06B0BB1FB384Bu64)
+    put(data, 0x7C2485CE9E7A065Eu64)
+    put(data, 0x7C59A742461887F6u64)
+    put(data, 0x7C9008896BCF54F9u64)
+    put(data, 0x7CC40AABC6C32A38u64)
+    put(data, 0x7CF90D56B873F4C6u64)
+    put(data, 0x7D2F50AC6690F1F8u64)
+    put(data, 0x7D63926BC01A973Bu64)
+    put(data, 0x7D987706B0213D09u64)
+    put(data, 0x7DCE94C85C298C4Cu64)
+    put(data, 0x7E031CFD3999F7AFu64)
+    put(data, 0x7E37E43C8800759Bu64)
+    put(data, 0x7E6DDD4BAA009302u64)
+    put(data, 0x7EA2AA4F4A405BE1u64)
+    put(data, 0x7ED754E31CD072D9u64)
+    put(data, 0x7F0D2A1BE4048F90u64)
+    put(data, 0x7F423A516E82D9BAu64)
+    put(data, 0x7F76C8E5CA239028u64)
+    put(data, 0x7FAC7B1F3CAC7433u64)
+    put(data, 0x7FE1CCF385EBC89Fu64)
+    put(data, 0x7FEFFFFFFFFFFFFFu64)
+    data
+  end
+
   private POW10_OFFSET = [
     0, 2, 5, 8, 12, 16, 21, 26, 32, 39,
     46, 54, 62, 71, 80, 90, 100, 111, 122, 134,
diff --git a/src/string/formatter.cr b/src/string/formatter.cr
index e85322f39d2e..31239f42ee4d 100644
--- a/src/string/formatter.cr
+++ b/src/string/formatter.cr
@@ -430,8 +430,37 @@ struct String::Formatter(A)
 
     # Formats floats with `%g` or `%G`
     private def float_general(float, flags)
-      # TODO: implement using `Float::Printer::RyuPrintf`
-      float_fallback(float, flags)
+      # `d2gen_buffered_n` will always take care of trailing zeros and return
+      # the number of stripped digits
+      precision = flags.precision.try(&.to_u32) || 6_u32
+
+      printf_buf = uninitialized UInt8[773]
+      printf_size, trailing_zeros =
+        Float::Printer::RyuPrintf.d2gen_buffered_n(float.abs, precision, printf_buf.to_unsafe, flags.sharp)
+      printf_slice = printf_buf.to_slice[0, printf_size]
+      dot_index = printf_slice.index('.'.ord)
+      e_index = printf_slice.rindex('e'.ord)
+      sign = Math.copysign(1.0, float)
+
+      printf_slice[e_index] = 'E'.ord.to_u8! if e_index && flags.uppercase?
+
+      str_size = printf_size
+      str_size += 1 if sign < 0 || flags.plus || flags.space
+      str_size += (dot_index.nil? ? 1 : 0) + trailing_zeros if flags.sharp
+
+      pad(str_size, flags) if flags.left_padding? && flags.padding_char != '0'
+
+      # this preserves -0.0's sign correctly
+      write_plus_or_space(sign, flags)
+      @io << '-' if sign < 0
+
+      pad(str_size, flags) if flags.left_padding? && flags.padding_char == '0'
+      @io.write_string(printf_slice[0...e_index])
+      trailing_zeros.times { @io << '0' } if flags.sharp
+      @io << '.' if flags.sharp && dot_index.nil?
+      @io.write_string(printf_slice[e_index..]) if e_index
+
+      pad(str_size, flags) if flags.right_padding?
     end
 
     # Formats floats with `%a` or `%A`

From ddee6c6c5c277f58bf1017c7b39bba1e31ae3770 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Fri, 22 Dec 2023 17:03:35 +0800
Subject: [PATCH 002/105] Implement most of `Crystal::System.print_error` in
 native Crystal (#14116)

---
 spec/std/crystal/system_spec.cr   |  46 +++++++++
 src/crystal/system/print_error.cr | 153 ++++++++++++++++++++++++++++--
 2 files changed, 191 insertions(+), 8 deletions(-)
 create mode 100644 spec/std/crystal/system_spec.cr

diff --git a/spec/std/crystal/system_spec.cr b/spec/std/crystal/system_spec.cr
new file mode 100644
index 000000000000..06bc789055d4
--- /dev/null
+++ b/spec/std/crystal/system_spec.cr
@@ -0,0 +1,46 @@
+require "spec"
+
+private def print_error_to_s(format, *args)
+  io = IO::Memory.new
+  Crystal::System.print_error(format, *args) do |bytes|
+    io.write_string(bytes)
+  end
+  io.to_s
+end
+
+describe "Crystal::System" do
+  describe ".print_error" do
+    it "works" do
+      print_error_to_s("abcde").should eq("abcde")
+    end
+
+    it "supports %d" do
+      print_error_to_s("%d,%d,%d,%d,%d", 0, 1234, Int32::MAX, Int32::MIN, UInt64::MAX).should eq("0,1234,2147483647,-2147483648,-1")
+    end
+
+    it "supports %u" do
+      print_error_to_s("%u,%u,%u,%u,%u", 0, 1234, UInt32::MAX, Int32::MIN, UInt64::MAX).should eq("0,1234,4294967295,2147483648,4294967295")
+    end
+
+    it "supports %x" do
+      print_error_to_s("%x,%x,%x,%x,%x", 0, 0x1234, UInt32::MAX, Int32::MIN, UInt64::MAX).should eq("0,1234,ffffffff,80000000,ffffffff")
+    end
+
+    it "supports %p" do
+      print_error_to_s("%p,%p,%p", Pointer(Void).new(0x0), Pointer(Void).new(0x1234), Pointer(Void).new(UInt64::MAX)).should eq("0x0,0x1234,0xffffffffffffffff")
+    end
+
+    it "supports %s" do
+      print_error_to_s("%s,%s,%s", "abc\0def", "ghi".to_unsafe, Pointer(UInt8).null).should eq("abc\0def,ghi,(null)")
+    end
+
+    it "supports %l width" do
+      values = {LibC::Long::MIN, LibC::Long::MAX, LibC::LongLong::MIN, LibC::LongLong::MAX}
+      print_error_to_s("%ld,%ld,%lld,%lld", *values).should eq(values.join(','))
+
+      values = {LibC::ULong::MIN, LibC::ULong::MAX, LibC::ULongLong::MIN, LibC::ULongLong::MAX}
+      print_error_to_s("%lu,%lu,%llu,%llu", *values).should eq(values.join(','))
+      print_error_to_s("%lx,%lx,%llx,%llx", *values).should eq(values.join(',', &.to_s(16)))
+    end
+  end
+end
diff --git a/src/crystal/system/print_error.cr b/src/crystal/system/print_error.cr
index 18f68d923507..3832eed5d9f4 100644
--- a/src/crystal/system/print_error.cr
+++ b/src/crystal/system/print_error.cr
@@ -1,15 +1,152 @@
 module Crystal::System
-  # Prints directly to stderr without going through an IO.
+  # Prints directly to stderr without going through an `IO::FileDescriptor`.
   # This is useful for error messages from components that are required for
   # IO to work (fibers, scheduler, event_loop).
   def self.print_error(message, *args)
-    {% if flag?(:unix) %}
-      LibC.dprintf 2, message, *args
-    {% elsif flag?(:win32) %}
-      buffer = StaticArray(UInt8, 512).new(0_u8)
-      len = LibC.snprintf(buffer, buffer.size, message, *args)
-      LibC._write 2, buffer, len
-    {% end %}
+    print_error(message, *args) do |bytes|
+      {% if flag?(:unix) || flag?(:wasm32) %}
+        LibC.write 2, bytes, bytes.size
+      {% elsif flag?(:win32) %}
+        LibC._write 2, bytes, bytes.size
+      {% end %}
+    end
+  end
+
+  # Minimal drop-in replacement for a C `printf` function. Yields successive
+  # non-empty `Bytes` to the block, which should do the actual printing.
+  #
+  # *format* only supports the `%(l|ll)?[dpsux]` format specifiers; more should
+  # be added only when we need them or an external library passes its own format
+  # string to here. *format* must also be null-terminated.
+  #
+  # Since this method may be called under low memory conditions or even with a
+  # corrupted heap, its implementation should be as low-level as possible,
+  # avoiding memory allocations.
+  #
+  # NOTE: C's `printf` is incompatible with Crystal's `sprintf`, because the
+  # latter does not support argument width specifiers nor `%p`.
+  def self.print_error(format, *args, &)
+    format = to_string_slice(format)
+    format_len = format.size
+    ptr = format.to_unsafe
+    finish = ptr + format_len
+    arg_index = 0
+
+    while ptr < finish
+      next_percent = ptr
+      while next_percent < finish && !(next_percent.value === '%')
+        next_percent += 1
+      end
+      unless next_percent == ptr
+        yield Slice.new(ptr, next_percent - ptr)
+      end
+
+      fmt_ptr = next_percent + 1
+      width = 0
+      if fmt_ptr.value === 'l'
+        width = 1
+        fmt_ptr += 1
+        if fmt_ptr.value === 'l'
+          width = 2
+          fmt_ptr += 1
+        end
+      end
+
+      break unless fmt_ptr < finish
+
+      case fmt_ptr.value
+      when 's'
+        read_arg(String | Pointer(UInt8)) do |arg|
+          yield to_string_slice(arg)
+        end
+      when 'd'
+        read_arg(Int::Primitive) do |arg|
+          to_int_slice(arg, 10, true, width) { |bytes| yield bytes }
+        end
+      when 'u'
+        read_arg(Int::Primitive) do |arg|
+          to_int_slice(arg, 10, false, width) { |bytes| yield bytes }
+        end
+      when 'x'
+        read_arg(Int::Primitive) do |arg|
+          to_int_slice(arg, 16, false, width) { |bytes| yield bytes }
+        end
+      when 'p'
+        read_arg(Pointer(Void)) do |arg|
+          # NOTE: MSVC uses `%X` rather than `0x%x`, we follow the latter on all platforms
+          yield "0x".to_slice
+          to_int_slice(arg.address, 16, false, 2) { |bytes| yield bytes }
+        end
+      else
+        yield Slice.new(next_percent, fmt_ptr + 1 - next_percent)
+      end
+
+      ptr = fmt_ptr + 1
+    end
+  end
+
+  private macro read_arg(type, &block)
+    {{ block.args[0] }} = args[arg_index].as?({{ type }})
+    if !{{ block.args[0] }}.nil?
+      {{ block.body }}
+    else
+      yield "(???)".to_slice
+    end
+    arg_index += 1
+  end
+
+  private def self.to_string_slice(str)
+    if str.is_a?(UInt8*)
+      if str.null?
+        "(null)".to_slice
+      else
+        Slice.new(str, LibC.strlen(str))
+      end
+    else
+      str.to_s.to_slice
+    end
+  end
+
+  # simplified version of `Int#internal_to_s`
+  private def self.to_int_slice(num, base, signed, width, &)
+    if num == 0
+      yield "0".to_slice
+      return
+    end
+
+    # Given sizeof(num) <= 64 bits, we need at most 20 bytes for `%d` or `%u`
+    # note that `chars` does not have to be null-terminated, since we are
+    # only yielding a `Bytes`
+    chars = uninitialized UInt8[20]
+    ptr_end = chars.to_unsafe + 20
+    ptr = ptr_end
+
+    num = case {signed, width}
+          when {true, 2}  then LibC::LongLong.new!(num)
+          when {true, 1}  then LibC::Long.new!(num)
+          when {true, 0}  then LibC::Int.new!(num)
+          when {false, 2} then LibC::ULongLong.new!(num)
+          when {false, 1} then LibC::ULong.new!(num)
+          else                 LibC::UInt.new!(num)
+          end
+
+    neg = num < 0
+
+    # do not assume Crystal constant initialization succeeds, hence not `DIGITS`
+    digits = "0123456789abcdef".to_unsafe
+
+    while num != 0
+      ptr -= 1
+      ptr.value = digits[num.remainder(base).abs]
+      num = num.tdiv(base)
+    end
+
+    if neg
+      ptr -= 1
+      ptr.value = '-'.ord.to_u8
+    end
+
+    yield Slice.new(ptr, ptr_end - ptr)
   end
 
   def self.print_exception(message, ex)

From 3ecdf161afab5f810e949560d637b76fa43841b1 Mon Sep 17 00:00:00 2001
From: Erdian718 <erdian718@qq.com>
Date: Fri, 22 Dec 2023 17:03:47 +0800
Subject: [PATCH 003/105] Fix UTF-8 console input on Windows (#13758)

Co-authored-by: Quinton Miller <nicetas.c@gmail.com>
---
 src/crystal/system/win32/file_descriptor.cr   | 71 ++++++++++++++++++-
 src/lib_c/x86_64-windows-msvc/c/consoleapi.cr |  8 +++
 src/string/utf16.cr                           |  4 +-
 3 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/src/crystal/system/win32/file_descriptor.cr b/src/crystal/system/win32/file_descriptor.cr
index 6e4f42d46b17..109c353c0325 100644
--- a/src/crystal/system/win32/file_descriptor.cr
+++ b/src/crystal/system/win32/file_descriptor.cr
@@ -11,7 +11,10 @@ module Crystal::System::FileDescriptor
   @system_blocking = true
 
   private def unbuffered_read(slice : Bytes)
-    if system_blocking?
+    handle = windows_handle
+    if ConsoleUtils.console?(handle)
+      ConsoleUtils.read(handle, slice)
+    elsif system_blocking?
       bytes_read = LibC._read(fd, slice, slice.size)
       if bytes_read == -1
         if Errno.value == Errno::EBADF
@@ -22,7 +25,6 @@ module Crystal::System::FileDescriptor
       end
       bytes_read
     else
-      handle = windows_handle
       overlapped_operation(handle, "ReadFile", read_timeout) do |overlapped|
         ret = LibC.ReadFile(handle, slice, slice.size, out byte_count, overlapped)
         {ret, byte_count}
@@ -276,6 +278,71 @@ module Crystal::System::FileDescriptor
   end
 end
 
+private module ConsoleUtils
+  # N UTF-16 code units correspond to no more than 3*N UTF-8 code units.
+  # NOTE: For very large buffers, `ReadConsoleW` may fail.
+  private BUFFER_SIZE = 10000
+  @@utf8_buffer = Slice(UInt8).new(3 * BUFFER_SIZE)
+
+  # `@@buffer` points to part of `@@utf8_buffer`.
+  # It represents data that has not been read yet.
+  @@buffer : Bytes = @@utf8_buffer[0, 0]
+
+  # Remaining UTF-16 code unit.
+  @@remaining_unit : UInt16?
+
+  # Determines if *handle* is a console.
+  def self.console?(handle : LibC::HANDLE) : Bool
+    LibC.GetConsoleMode(handle, out _) != 0
+  end
+
+  # Reads to *slice* from the console specified by *handle*,
+  # and return the actual number of bytes read.
+  def self.read(handle : LibC::HANDLE, slice : Bytes) : Int32
+    return 0 if slice.empty?
+    fill_buffer(handle) if @@buffer.empty?
+
+    bytes_read = {slice.size, @@buffer.size}.min
+    @@buffer[0, bytes_read].copy_to(slice)
+    @@buffer += bytes_read
+    bytes_read
+  end
+
+  private def self.fill_buffer(handle : LibC::HANDLE) : Nil
+    utf16_buffer = uninitialized UInt16[BUFFER_SIZE]
+    remaining_unit = @@remaining_unit
+    if remaining_unit
+      utf16_buffer[0] = remaining_unit
+      index = read_console(handle, utf16_buffer.to_slice + 1)
+    else
+      index = read_console(handle, utf16_buffer.to_slice) - 1
+    end
+
+    if index >= 0 && utf16_buffer[index] & 0xFC00 == 0xD800
+      @@remaining_unit = utf16_buffer[index]
+      index -= 1
+    else
+      @@remaining_unit = nil
+    end
+    return if index < 0
+
+    appender = @@utf8_buffer.to_unsafe.appender
+    String.each_utf16_char(utf16_buffer.to_slice[..index]) do |char|
+      char.each_byte do |byte|
+        appender << byte
+      end
+    end
+    @@buffer = @@utf8_buffer[0, appender.size]
+  end
+
+  private def self.read_console(handle : LibC::HANDLE, slice : Slice(UInt16)) : Int32
+    if 0 == LibC.ReadConsoleW(handle, slice, slice.size, out units_read, nil)
+      raise IO::Error.from_winerror("ReadConsoleW")
+    end
+    units_read.to_i32
+  end
+end
+
 # Enable UTF-8 console I/O for the duration of program execution
 if LibC.IsValidCodePage(LibC::CP_UTF8) != 0
   old_input_cp = LibC.GetConsoleCP
diff --git a/src/lib_c/x86_64-windows-msvc/c/consoleapi.cr b/src/lib_c/x86_64-windows-msvc/c/consoleapi.cr
index 680e199be2ab..796369c65a85 100644
--- a/src/lib_c/x86_64-windows-msvc/c/consoleapi.cr
+++ b/src/lib_c/x86_64-windows-msvc/c/consoleapi.cr
@@ -14,6 +14,14 @@ lib LibC
   fun GetConsoleCP : DWORD
   fun GetConsoleOutputCP : DWORD
 
+  fun ReadConsoleW(
+    hConsoleInput : HANDLE,
+    lpBuffer : Void*,
+    nNumberOfCharsToRead : DWORD,
+    lpNumberOfCharsRead : DWORD*,
+    pInputControl : Void*
+  ) : BOOL
+
   CTRL_C_EVENT     = 0
   CTRL_BREAK_EVENT = 1
 
diff --git a/src/string/utf16.cr b/src/string/utf16.cr
index b3fdc09301af..042391cca15d 100644
--- a/src/string/utf16.cr
+++ b/src/string/utf16.cr
@@ -128,8 +128,10 @@ class String
     {string, pointer + 1}
   end
 
+  # :nodoc:
+  #
   # Yields each decoded char in the given slice.
-  private def self.each_utf16_char(slice : Slice(UInt16), &)
+  def self.each_utf16_char(slice : Slice(UInt16), &)
     i = 0
     while i < slice.size
       byte = slice[i].to_i

From ac6b56e061bc6b86dd9d8c1045074ca4b7e61500 Mon Sep 17 00:00:00 2001
From: Julien Portalier <julien@portalier.com>
Date: Fri, 22 Dec 2023 15:15:23 +0100
Subject: [PATCH 004/105] Workaround regular timeouts in `HTTP::Server` specs
 with MT (#14097)

---
 spec/std/http/server/server_spec.cr | 5 +----
 spec/std/http/spec_helper.cr        | 5 +++++
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/spec/std/http/server/server_spec.cr b/spec/std/http/server/server_spec.cr
index e5aa0ec261a7..f5a82a514e0b 100644
--- a/spec/std/http/server/server_spec.cr
+++ b/spec/std/http/server/server_spec.cr
@@ -45,12 +45,9 @@ describe HTTP::Server do
     server = HTTP::Server.new { }
     server.bind_unused_port
 
-    spawn do
+    run_server(server) do
       server.close
-      sleep 0.001
     end
-
-    server.listen
   end
 
   it "closes the server" do
diff --git a/spec/std/http/spec_helper.cr b/spec/std/http/spec_helper.cr
index 410e211e4dbe..18ec9e0bab46 100644
--- a/spec/std/http/spec_helper.cr
+++ b/spec/std/http/spec_helper.cr
@@ -46,6 +46,11 @@ def run_server(server, &)
     wait_for { server.listening? }
     wait_until_blocked f
 
+    {% if flag?(:preview_mt) %}
+      # avoids fiber synchronization issues in specs, like closing the server
+      # before we properly listen, ...
+      sleep 0.001
+    {% end %}
     yield server_done
   ensure
     server.close unless server.closed?

From 2514ac42b2a1ea0692a7a2ffe7fb37e9ef537e7b Mon Sep 17 00:00:00 2001
From: George Dietrich <george@dietrich.app>
Date: Fri, 22 Dec 2023 09:15:40 -0500
Subject: [PATCH 005/105] Add location information to implicit flag enum
 members (#14127)

---
 spec/compiler/semantic/doc_spec.cr             | 18 ++++++++++++++++++
 .../crystal/semantic/top_level_visitor.cr      | 15 +++++++++++++--
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/spec/compiler/semantic/doc_spec.cr b/spec/compiler/semantic/doc_spec.cr
index 9b38339b6485..3338f920a938 100644
--- a/spec/compiler/semantic/doc_spec.cr
+++ b/spec/compiler/semantic/doc_spec.cr
@@ -353,6 +353,24 @@ describe "Semantic: doc" do
     a.locations.not_nil!.size.should eq(1)
   end
 
+  it "stores location for implicit flag enum members" do
+    result = semantic %(
+      @[Flags]
+      enum Foo
+        A = 1
+        B = 2
+      end
+    ), wants_doc: true
+    program = result.program
+    foo = program.types["Foo"]
+
+    a_loc = foo.types["All"].locations.should_not be_nil
+    a_loc.should_not be_empty
+
+    b_loc = foo.types["None"].locations.should_not be_nil
+    b_loc.should_not be_empty
+  end
+
   it "stores doc for constant" do
     result = semantic %(
       # Hello
diff --git a/src/compiler/crystal/semantic/top_level_visitor.cr b/src/compiler/crystal/semantic/top_level_visitor.cr
index 5d0cbc477260..05d8918f8383 100644
--- a/src/compiler/crystal/semantic/top_level_visitor.cr
+++ b/src/compiler/crystal/semantic/top_level_visitor.cr
@@ -655,16 +655,27 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
 
       if enum_type.flags?
         unless enum_type.types.has_key?("None")
-          enum_type.add_constant("None", 0)
+          none_member = enum_type.add_constant("None", 0)
+
+          if node_location = node.location
+            none_member.add_location node_location
+          end
+
           define_enum_none_question_method(enum_type, node)
         end
 
         unless enum_type.types.has_key?("All")
           all_value = enum_type.base_type.kind.cast(0).as(Int::Primitive)
+
           enum_type.types.each_value do |member|
             all_value |= interpret_enum_value(member.as(Const).value, enum_type.base_type)
           end
-          enum_type.add_constant("All", all_value)
+
+          all_member = enum_type.add_constant("All", all_value)
+
+          if node_location = node.location
+            all_member.add_location node_location
+          end
         end
       end
 

From f362827ed2f1766c8f15d480354238a67556ca31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 22 Dec 2023 15:16:16 +0100
Subject: [PATCH 006/105] Add `--tallies` option to `crystal tool unreachable`
 (#13969)

Co-authored-by: Quinton Miller <nicetas.c@gmail.com>
---
 .../crystal/tools/unreachable_spec.cr         | 44 +++++++++++++---
 src/compiler/crystal/command.cr               | 10 +++-
 src/compiler/crystal/tools/unreachable.cr     | 50 +++++++++++--------
 3 files changed, 73 insertions(+), 31 deletions(-)

diff --git a/spec/compiler/crystal/tools/unreachable_spec.cr b/spec/compiler/crystal/tools/unreachable_spec.cr
index 6fffb17e4ca6..12ed82499740 100644
--- a/spec/compiler/crystal/tools/unreachable_spec.cr
+++ b/spec/compiler/crystal/tools/unreachable_spec.cr
@@ -15,28 +15,37 @@ def processed_unreachable_visitor(code)
 end
 
 private def assert_unreachable(code, file = __FILE__, line = __LINE__)
-  expected_locations = [] of Location
+  expected = Hash(String, Int32).new
 
   code.lines.each_with_index do |line, line_number_0|
-    if column_number = line.index('༓')
-      expected_locations << Location.new(".", line_number_0 + 1, column_number + 1)
+    if match = line.match(/༓(?:\[(\d+)\])?/)
+      location = Location.new(".", line_number_0 + 1, match.begin + 1)
+      expected[location.to_s] = (match[1]? || 0).to_i
     end
   end
 
-  code = code.gsub('༓', "")
+  code = code.gsub(/༓(?:\[(\d+)\])?/, "")
 
-  defs = processed_unreachable_visitor(code)
+  tallies = processed_unreachable_visitor(code)
 
-  result_location = defs.try &.compact_map(&.location).sort_by! do |loc|
+  processed_results = [] of {Location, Int32}
+  tallies.each do |k, v|
+    location = k.location.not_nil!
+    next unless v.zero? || expected.has_key?(location.to_s)
+    processed_results << {location, v}
+  end
+
+  processed_results = processed_results.sort_by! do |loc, v|
     {loc.filename.as(String), loc.line_number, loc.column_number}
-  end.map(&.to_s)
+  end.map { |k, v| {k.to_s, v} }
 
-  result_location.should eq(expected_locations.map(&.to_s)), file: file, line: line
+  processed_results.should eq(expected.to_a), file: file, line: line
 end
 
 # References
 #
 #   ༓ marks the expected unreachable code to be found
+#   ༓[n] marks the expected code to be called n times
 #
 describe "unreachable" do
   it "finds top level methods" do
@@ -424,4 +433,23 @@ describe "unreachable" do
       {% end %}
       CRYSTAL
   end
+
+  it "tallies calls" do
+    assert_unreachable <<-CRYSTAL
+      ༓def foo
+        1
+      end
+
+      ༓[2]def bar
+        2
+      end
+
+      ༓[1]def baz
+        bar
+      end
+
+      bar
+      baz
+      CRYSTAL
+  end
 end
diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr
index 2c5492445e0b..69b4ab2d221c 100644
--- a/src/compiler/crystal/command.cr
+++ b/src/compiler/crystal/command.cr
@@ -349,7 +349,8 @@ class Crystal::Command
     includes : Array(String),
     excludes : Array(String),
     verbose : Bool,
-    check : Bool do
+    check : Bool,
+    tallies : Bool do
     def compile(output_filename = self.output_filename)
       compiler.emit_base_filename = emit_base_filename || output_filename.rchop(File.extname(output_filename))
       compiler.compile sources, output_filename, combine_rpath: combine_rpath
@@ -381,6 +382,7 @@ class Crystal::Command
     includes = [] of String
     verbose = false
     check = false
+    tallies = false
 
     option_parser = parse_with_crystal_opts do |opts|
       opts.banner = "Usage: crystal #{command} [options] [programfile] [--] [arguments]\n\nOptions:"
@@ -443,6 +445,10 @@ class Crystal::Command
       end
 
       if unreachable_command
+        opts.on("--tallies", "Print reachable methods and their call counts as well") do
+          tallies = true
+        end
+
         opts.on("--check", "Exits with error if there is any unreachable code") do |f|
           check = true
         end
@@ -613,7 +619,7 @@ class Crystal::Command
     combine_rpath = run && !no_codegen
     @config = CompilerConfig.new compiler, sources, output_filename, emit_base_filename,
       arguments, specified_output, hierarchy_exp, cursor_location, output_format.not_nil!,
-      combine_rpath, includes, excludes, verbose, check
+      combine_rpath, includes, excludes, verbose, check, tallies
   end
 
   private def gather_sources(filenames)
diff --git a/src/compiler/crystal/tools/unreachable.cr b/src/compiler/crystal/tools/unreachable.cr
index f89f90e4c37d..a8886fecf596 100644
--- a/src/compiler/crystal/tools/unreachable.cr
+++ b/src/compiler/crystal/tools/unreachable.cr
@@ -15,8 +15,8 @@ module Crystal
       unreachable.excludes.concat CrystalPath.default_paths.map { |path| ::Path[path].expand.to_posix.to_s }
       unreachable.excludes.concat config.excludes.map { |path| ::Path[path].expand.to_posix.to_s }
 
-      defs = unreachable.process(result)
-      defs.sort_by! do |a_def|
+      tallies = unreachable.process(result)
+      tallies.sort_by! do |a_def, _|
         location = a_def.location.not_nil!
         {
           location.filename.as(String),
@@ -25,15 +25,15 @@ module Crystal
         }
       end
 
-      UnreachablePresenter.new(defs, format: config.output_format).to_s(STDOUT)
+      UnreachablePresenter.new(tallies, format: config.output_format, print_tallies: config.tallies).to_s(STDOUT)
 
       if config.check
-        exit 1 unless defs.empty?
+        exit 1 if tallies.any?(&.[1].zero?)
       end
     end
   end
 
-  record UnreachablePresenter, defs : Array(Def), format : String? do
+  record UnreachablePresenter, tallies : Array({Def, Int32}), format : String?, print_tallies : Bool do
     include JSON::Serializable
 
     def to_s(io)
@@ -49,16 +49,19 @@ module Crystal
 
     def each(&)
       current_dir = Dir.current
-      defs.each do |a_def|
+      tallies.each do |a_def, count|
+        next unless print_tallies || count.zero?
+
         location = a_def.location.not_nil!
         filename = ::Path[location.filename.as(String)].relative_to(current_dir).to_s
         location = Location.new(filename, location.line_number, location.column_number)
-        yield a_def, location
+        yield a_def, location, count
       end
     end
 
     def to_text(io)
-      each do |a_def, location|
+      each do |a_def, location, count|
+        io << count << "\t" if print_tallies
         io << location << "\t"
         io << a_def.short_reference << "\t"
         io << a_def.length << " lines"
@@ -72,13 +75,14 @@ module Crystal
 
     def to_json(builder : JSON::Builder)
       builder.array do
-        each do |a_def, location|
+        each do |a_def, location, count|
           builder.object do
             builder.field "name", a_def.short_reference
             builder.field "location", location.to_s
             if lines = a_def.length
               builder.field "lines", lines
             end
+            builder.field "count", count if print_tallies
             if annotations = a_def.all_annotations
               builder.field "annotations", annotations.map(&.to_s)
             end
@@ -89,9 +93,14 @@ module Crystal
 
     def to_csv(io)
       CSV.build(io) do |builder|
-        builder.row %w[name file line column length annotations]
-        each do |a_def, location|
+        builder.row do |row|
+          row << "count" if print_tallies
+          row.concat %w[name file line column length annotations]
+        end
+
+        each do |a_def, location, count|
           builder.row do |row|
+            row << count if print_tallies
             row << a_def.short_reference
             row << location.filename
             row << location.line_number
@@ -111,8 +120,8 @@ module Crystal
   # Then it traverses all types and their defs and reports those that are not
   # in `@used_def_locations` (and match the filter).
   class UnreachableVisitor < Visitor
-    @used_def_locations = Set(Location).new
-    @defs : Set(Def) = Set(Def).new.compare_by_identity
+    @used_def_locations = Hash(Location, Int32).new(0)
+    @tallies : Hash(Def, Int32) = Hash(Def, Int32).new.compare_by_identity
     @visited : Set(ASTNode) = Set(ASTNode).new.compare_by_identity
 
     property includes = [] of String
@@ -130,14 +139,14 @@ module Crystal
       process_type(type.metaclass) if type.metaclass != type
     end
 
-    def process(result : Compiler::Result) : Array(Def)
-      @defs.clear
+    def process(result : Compiler::Result) : Array({Def, Int32})
+      @tallies.clear
 
       result.node.accept(self)
 
       process_type(result.program)
 
-      @defs.to_a
+      @tallies.to_a
     end
 
     def visit(node)
@@ -163,7 +172,7 @@ module Crystal
 
       node.target_defs.try &.each do |a_def|
         if (location = a_def.location)
-          @used_def_locations << location if interested_in(location)
+          @used_def_locations.update(location, &.+(1)) if interested_in(location)
         end
 
         if @visited.add?(a_def)
@@ -199,11 +208,10 @@ module Crystal
 
       check_def(previous) if previous && !a_def.calls_previous_def?
 
-      return if @used_def_locations.includes?(a_def.location)
-
-      check_def(previous) if previous && a_def.calls_previous_def?
+      tally = @used_def_locations[a_def.location]
+      @tallies[a_def] = tally
 
-      @defs << a_def
+      check_def(previous) if previous && a_def.calls_previous_def? && tally == 0
     end
 
     private def interested_in(location)

From a3bedf968c9c60092ed222686c8f1c5d63b43a3f Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 23 Dec 2023 16:50:26 +0800
Subject: [PATCH 007/105] Avoid double rounding in `Float#format` for
 nonnegative `decimal_place` (#14129)

---
 spec/std/humanize_spec.cr | 8 ++++++++
 src/humanize.cr           | 2 +-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/spec/std/humanize_spec.cr b/spec/std/humanize_spec.cr
index 841fde6cb2ba..c909417aca36 100644
--- a/spec/std/humanize_spec.cr
+++ b/spec/std/humanize_spec.cr
@@ -99,6 +99,14 @@ describe Number do
       assert_prints 1.9999998.format, "1.9999998"
       assert_prints 1111111.999999998.format, "1,111,111.999999998"
     end
+
+    it "does not perform double rounding when decimal places are given" do
+      assert_prints 1.2345.format(decimal_places: 24), "1.234499999999999930722083"
+      assert_prints 1.2345.format(decimal_places: 65), "1.23449999999999993072208326339023187756538391113281250000000000000"
+      assert_prints 1.2345.format(decimal_places: 71), "1.23449999999999993072208326339023187756538391113281250000000000000000000"
+      assert_prints 1.2345.format(decimal_places: 83), "1.23449999999999993072208326339023187756538391113281250000000000000000000000000000000"
+      assert_prints 1.2345.format(decimal_places: 99), "1.234499999999999930722083263390231877565383911132812500000000000000000000000000000000000000000000000"
+    end
   end
 
   describe "#humanize" do
diff --git a/src/humanize.cr b/src/humanize.cr
index e0c69a37b3ad..bb285fe3a07d 100644
--- a/src/humanize.cr
+++ b/src/humanize.cr
@@ -20,7 +20,7 @@ struct Number
   def format(io : IO, separator = '.', delimiter = ',', decimal_places : Int? = nil, *, group : Int = 3, only_significant : Bool = false) : Nil
     number = self
     # TODO: Optimize implementation for Int
-    if decimal_places
+    if decimal_places && (decimal_places < 0 || !number.is_a?(Float))
       number = number.round(decimal_places)
     end
 

From 15010d39dd42bc2c10c2597ca19aac5fd0521898 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 23 Dec 2023 16:50:40 +0800
Subject: [PATCH 008/105] Add `ReferenceStorage` for manual allocation of
 references (#14106)

Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
---
 .../semantic/reference_storage_spec.cr        | 40 ++++++++++++++
 spec/primitives/reference_spec.cr             |  4 +-
 src/compiler/crystal/codegen/llvm_typer.cr    |  4 ++
 src/compiler/crystal/program.cr               |  6 ++-
 src/compiler/crystal/types.cr                 | 28 +++++++++-
 src/prelude.cr                                |  1 +
 src/reference_storage.cr                      | 54 +++++++++++++++++++
 7 files changed, 132 insertions(+), 5 deletions(-)
 create mode 100644 spec/compiler/semantic/reference_storage_spec.cr
 create mode 100644 src/reference_storage.cr

diff --git a/spec/compiler/semantic/reference_storage_spec.cr b/spec/compiler/semantic/reference_storage_spec.cr
new file mode 100644
index 000000000000..791fed054275
--- /dev/null
+++ b/spec/compiler/semantic/reference_storage_spec.cr
@@ -0,0 +1,40 @@
+require "../../spec_helper"
+
+describe "Semantic: ReferenceStorage" do
+  it "errors if T is a struct type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Foo (T must be a reference type)"
+      struct Foo
+        @x = 1
+      end
+
+      ReferenceStorage(Foo)
+      CRYSTAL
+  end
+
+  it "errors if T is a value type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Int32 (T must be a reference type)"
+      ReferenceStorage(Int32)
+      CRYSTAL
+  end
+
+  it "errors if T is a union type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Bar | Foo) (T must be a reference type)"
+      class Foo
+      end
+
+      class Bar
+      end
+
+      ReferenceStorage(Foo | Bar)
+      CRYSTAL
+  end
+
+  it "errors if T is a nilable type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Foo | Nil) (T must be a reference type)"
+      class Foo
+      end
+
+      ReferenceStorage(Foo?)
+      CRYSTAL
+  end
+end
diff --git a/spec/primitives/reference_spec.cr b/spec/primitives/reference_spec.cr
index b73553748b65..52f179296ee8 100644
--- a/spec/primitives/reference_spec.cr
+++ b/spec/primitives/reference_spec.cr
@@ -43,9 +43,7 @@ describe "Primitives: reference" do
     end
 
     it "works when address is on the stack" do
-      # suitably aligned, sufficient storage for type ID + i64 + ptr
-      # TODO: use `ReferenceStorage` instead
-      foo_buffer = uninitialized UInt64[3]
+      foo_buffer = uninitialized ReferenceStorage(Foo)
       foo = Foo.pre_initialize(pointerof(foo_buffer))
       pointerof(foo_buffer).as(typeof(Foo.crystal_instance_type_id)*).value.should eq(Foo.crystal_instance_type_id)
       foo.str.should eq("abc")
diff --git a/src/compiler/crystal/codegen/llvm_typer.cr b/src/compiler/crystal/codegen/llvm_typer.cr
index d20fbd59fa9a..d72a25ecd3cb 100644
--- a/src/compiler/crystal/codegen/llvm_typer.cr
+++ b/src/compiler/crystal/codegen/llvm_typer.cr
@@ -245,6 +245,10 @@ module Crystal
       llvm_type(type.remove_alias, wants_size)
     end
 
+    private def create_llvm_type(type : ReferenceStorageType, wants_size)
+      llvm_struct_type(type.reference_type, wants_size)
+    end
+
     private def create_llvm_type(type : NonGenericModuleType | GenericClassType, wants_size)
       # This can only be reached if the module or generic class don't have implementors
       @llvm_context.int1
diff --git a/src/compiler/crystal/program.cr b/src/compiler/crystal/program.cr
index 936fc6a0a270..6d3d185774af 100644
--- a/src/compiler/crystal/program.cr
+++ b/src/compiler/crystal/program.cr
@@ -197,6 +197,10 @@ module Crystal
       types["Struct"] = struct_t = @struct_t = NonGenericClassType.new self, self, "Struct", value
       abstract_value_type(struct_t)
 
+      types["ReferenceStorage"] = @reference_storage = reference_storage = GenericReferenceStorageType.new self, self, "ReferenceStorage", value, ["T"]
+      reference_storage.declare_instance_var("@type_id", int32)
+      reference_storage.can_be_stored = false
+
       types["Enumerable"] = @enumerable = GenericModuleType.new self, self, "Enumerable", ["T"]
       types["Indexable"] = @indexable = GenericModuleType.new self, self, "Indexable", ["T"]
 
@@ -493,7 +497,7 @@ module Crystal
 
     {% for name in %w(object no_return value number reference void nil bool char int int8 int16 int32 int64 int128
                      uint8 uint16 uint32 uint64 uint128 float float32 float64 string symbol pointer enumerable indexable
-                     array static_array exception tuple named_tuple proc union enum range regex crystal
+                     array static_array reference_storage exception tuple named_tuple proc union enum range regex crystal
                      packed_annotation thread_local_annotation no_inline_annotation
                      always_inline_annotation naked_annotation returns_twice_annotation
                      raises_annotation primitive_annotation call_convention_annotation
diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr
index ad9f3d391fa6..64bcdda9a3d9 100644
--- a/src/compiler/crystal/types.cr
+++ b/src/compiler/crystal/types.cr
@@ -550,7 +550,7 @@ module Crystal
     def allows_instance_vars?
       case self
       when program.object, program.value, program.struct,
-           program.reference, program.class_type,
+           program.reference, program.class_type, program.reference_storage,
            program.number, program.int, program.float,
            program.tuple, program.named_tuple,
            program.pointer, program.static_array,
@@ -2642,6 +2642,32 @@ module Crystal
     end
   end
 
+  # The non-instantiated ReferenceStorage(T) type.
+  class GenericReferenceStorageType < GenericClassType
+    @struct = true
+
+    def new_generic_instance(program, generic_type, type_vars)
+      t = type_vars["T"].type
+
+      unless t.is_a?(TypeParameter) || (t.class? && !t.struct?)
+        raise TypeException.new "Can't instantiate ReferenceStorage(T) with T = #{t} (T must be a reference type)"
+      end
+
+      ReferenceStorageType.new program, t
+    end
+  end
+
+  class ReferenceStorageType < GenericClassInstanceType
+    getter reference_type : Type
+
+    def initialize(program, @reference_type)
+      t_var = Var.new("T", @reference_type)
+      t_var.bind_to t_var
+
+      super(program, program.reference_storage, program.struct, {"T" => t_var} of String => ASTNode)
+    end
+  end
+
   # A lib type, like `lib LibC`.
   class LibType < ModuleType
     getter link_annotations : Array(LinkAnnotation)?
diff --git a/src/prelude.cr b/src/prelude.cr
index f06f5bc87015..f84bb86cb3c1 100644
--- a/src/prelude.cr
+++ b/src/prelude.cr
@@ -65,6 +65,7 @@ require "raise"
 require "random"
 require "range"
 require "reference"
+require "reference_storage"
 require "regex"
 require "set"
 {% unless flag?(:wasm32) %}
diff --git a/src/reference_storage.cr b/src/reference_storage.cr
new file mode 100644
index 000000000000..4f6e39a8cca0
--- /dev/null
+++ b/src/reference_storage.cr
@@ -0,0 +1,54 @@
+# a `ReferenceStorage(T)` provides the minimum storage for the instance data of
+# an object of type `T`. The compiler guarantees that
+# `sizeof(ReferenceStorage(T)) == instance_sizeof(T)` and
+# `alignof(ReferenceStorage(T)) == instance_alignof(T)` always hold, which means
+# `Pointer(ReferenceStorage(T))` and `T` are binary-compatible.
+#
+# `T` must be a non-union reference type.
+#
+# WARNING: `ReferenceStorage` is only necessary for manual memory management,
+# such as creating instances of `T` with a non-default allocator. Therefore,
+# this type is unsafe and no public constructors are defined.
+#
+# WARNING: `ReferenceStorage` is unsuitable when instances of `T` require more
+# than `instance_sizeof(T)` bytes, such as `String` and `Log::Metadata`.
+@[Experimental("This type's API is still under development. Join the discussion about custom reference allocation at [#13481](https://github.com/crystal-lang/crystal/issues/13481).")]
+struct ReferenceStorage(T)
+  private def initialize
+  end
+
+  # Returns whether `self` and *other* are bytewise equal.
+  #
+  # NOTE: This does not call `T#==`, so it works even if `self` or *other* does
+  # not represent a valid instance of `T`. If validity is guaranteed, call
+  # `to_reference == other.to_reference` instead to use `T#==`.
+  def ==(other : ReferenceStorage(T)) : Bool
+    to_bytes == other.to_bytes
+  end
+
+  def ==(other) : Bool
+    false
+  end
+
+  def hash(hasher)
+    to_bytes.hash(hasher)
+  end
+
+  def to_s(io : IO) : Nil
+    io << "ReferenceStorage(#<" << T << ":0x"
+    pointerof(@type_id).address.to_s(io, 16)
+    io << ">)"
+  end
+
+  # Returns a `T` whose instance data refers to `self`.
+  #
+  # WARNING: The caller is responsible for ensuring that the instance data is
+  # correctly initialized and outlives the returned `T`.
+  def to_reference : T
+    pointerof(@type_id).as(T)
+  end
+
+  protected def to_bytes
+    Slice.new(pointerof(@type_id).as(UInt8*), instance_sizeof(T))
+  end
+end

From 899ec69a2bc91169e871002063b37fcb6469cb65 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 23 Dec 2023 16:51:02 +0800
Subject: [PATCH 009/105] Support `dll` parameter in `@[Link]` (#14131)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Johannes Müller <straightshoota@gmail.com>
---
 spec/compiler/semantic/lib_spec.cr   | 50 +++++++++++++++++++++++++-
 src/annotations.cr                   |  9 ++++-
 src/compiler/crystal/codegen/link.cr | 53 ++++++++++++++++++++++++++--
 src/compiler/crystal/compiler.cr     | 23 ++++++++++++
 src/compiler/crystal/ffi/lib_ffi.cr  |  3 ++
 src/crystal/lib_iconv.cr             |  3 ++
 src/gc/boehm.cr                      |  3 ++
 src/lib_z/lib_z.cr                   |  3 ++
 src/llvm/lib_llvm.cr                 |  3 ++
 src/openssl/lib_crypto.cr            |  4 +++
 src/openssl/lib_ssl.cr               |  5 +++
 src/regex/lib_pcre.cr                |  3 ++
 src/regex/lib_pcre2.cr               |  3 ++
 src/xml/libxml2.cr                   |  3 ++
 src/yaml/lib_yaml.cr                 |  3 ++
 15 files changed, 166 insertions(+), 5 deletions(-)

diff --git a/spec/compiler/semantic/lib_spec.cr b/spec/compiler/semantic/lib_spec.cr
index 1ee3c7aa99c6..92526402177d 100644
--- a/spec/compiler/semantic/lib_spec.cr
+++ b/spec/compiler/semantic/lib_spec.cr
@@ -345,7 +345,55 @@ describe "Semantic: lib" do
       lib LibFoo
       end
       ),
-      "unknown link argument: 'boo' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config', 'framework', and 'wasm_import_module')"
+      "unknown link argument: 'boo' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config', 'framework', 'wasm_import_module', and 'dll')"
+  end
+
+  it "allows dll argument" do
+    assert_no_errors <<-CRYSTAL
+      @[Link(dll: "foo.dll")]
+      lib LibFoo
+      end
+      CRYSTAL
+
+    assert_no_errors <<-CRYSTAL
+      @[Link(dll: "BAR.DLL")]
+      lib LibFoo
+      end
+      CRYSTAL
+  end
+
+  it "errors if dll argument contains directory separators" do
+    assert_error <<-CRYSTAL, "'dll' link argument must not include directory separators"
+      @[Link(dll: "foo/bar.dll")]
+      lib LibFoo
+      end
+      CRYSTAL
+
+    assert_error <<-CRYSTAL, "'dll' link argument must not include directory separators"
+      @[Link(dll: %q(foo\\bar.dll))]
+      lib LibFoo
+      end
+      CRYSTAL
+  end
+
+  it "errors if dll argument does not end with '.dll'" do
+    assert_error <<-CRYSTAL, "'dll' link argument must use a '.dll' file extension"
+      @[Link(dll: "foo")]
+      lib LibFoo
+      end
+      CRYSTAL
+
+    assert_error <<-CRYSTAL, "'dll' link argument must use a '.dll' file extension"
+      @[Link(dll: "foo.dylib")]
+      lib LibFoo
+      end
+      CRYSTAL
+
+    assert_error <<-CRYSTAL, "'dll' link argument must use a '.dll' file extension"
+      @[Link(dll: "")]
+      lib LibFoo
+      end
+      CRYSTAL
   end
 
   it "errors if lib already specified with positional argument" do
diff --git a/src/annotations.cr b/src/annotations.cr
index c906f61b9b79..929ed73533f9 100644
--- a/src/annotations.cr
+++ b/src/annotations.cr
@@ -27,7 +27,7 @@ end
 annotation Flags
 end
 
-# A `lib` can be marked with `@[Link(lib : String, *, ldflags : String, framework : String, pkg_config : String)]`
+# A `lib` can be marked with `@[Link(lib : String, *, ldflags : String, static : Bool, framework : String, pkg_config : String, wasm_import_module : String, dll : String)]`
 # to declare the library that should be linked when compiling the program.
 #
 # At least one of the *lib*, *ldflags*, *framework* arguments needs to be specified.
@@ -45,6 +45,13 @@ end
 #
 # `@[Link(framework: "Cocoa")]` will pass `-framework Cocoa` to the linker.
 #
+# `@[Link(dll: "gc.dll")]` will copy `gc.dll` to any built program. The DLL name
+# must use `.dll` as its file extension and cannot contain any directory
+# separators. The actual DLL is searched among `CRYSTAL_LIBRARY_PATH`, the
+# compiler's own directory, and `PATH` in that order; a warning is printed if
+# the DLL isn't found, although it might still run correctly if the DLLs are
+# available in other DLL search paths on the system.
+#
 # When an `-l` option is passed to the linker, it will lookup the libraries in
 # paths passed with the `-L` option. Any paths in `CRYSTAL_LIBRARY_PATH` are
 # added by default. Custom paths can be passed using `ldflags`:
diff --git a/src/compiler/crystal/codegen/link.cr b/src/compiler/crystal/codegen/link.cr
index 7ef2ab85f92c..cc703ec81eef 100644
--- a/src/compiler/crystal/codegen/link.cr
+++ b/src/compiler/crystal/codegen/link.cr
@@ -5,8 +5,9 @@ module Crystal
     getter ldflags : String?
     getter framework : String?
     getter wasm_import_module : String?
+    getter dll : String?
 
-    def initialize(@lib = nil, @pkg_config = @lib, @ldflags = nil, @static = false, @framework = nil, @wasm_import_module = nil)
+    def initialize(@lib = nil, @pkg_config = @lib, @ldflags = nil, @static = false, @framework = nil, @wasm_import_module = nil, @dll = nil)
     end
 
     def static?
@@ -27,6 +28,7 @@ module Crystal
       lib_pkg_config = nil
       lib_framework = nil
       lib_wasm_import_module = nil
+      lib_dll = nil
       count = 0
 
       args.each do |arg|
@@ -76,12 +78,21 @@ module Crystal
         when "wasm_import_module"
           named_arg.raise "'wasm_import_module' link argument must be a String" unless value.is_a?(StringLiteral)
           lib_wasm_import_module = value.value
+        when "dll"
+          named_arg.raise "'dll' link argument must be a String" unless value.is_a?(StringLiteral)
+          lib_dll = value.value
+          unless lib_dll.size >= 4 && lib_dll[-4..].compare(".dll", case_insensitive: true) == 0
+            named_arg.raise "'dll' link argument must use a '.dll' file extension"
+          end
+          if ::Path.separators(::Path::Kind::WINDOWS).any? { |separator| lib_dll.includes?(separator) }
+            named_arg.raise "'dll' link argument must not include directory separators"
+          end
         else
-          named_arg.raise "unknown link argument: '#{named_arg.name}' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config', 'framework', and 'wasm_import_module')"
+          named_arg.raise "unknown link argument: '#{named_arg.name}' (valid arguments are 'lib', 'ldflags', 'static', 'pkg_config', 'framework', 'wasm_import_module', and 'dll')"
         end
       end
 
-      new(lib_name, lib_pkg_config, lib_ldflags, lib_static, lib_framework, lib_wasm_import_module)
+      new(lib_name, lib_pkg_config, lib_ldflags, lib_static, lib_framework, lib_wasm_import_module, lib_dll)
     end
   end
 
@@ -221,6 +232,42 @@ module Crystal
       flags.join(" ")
     end
 
+    def each_dll_path(& : String, Bool ->)
+      executable_path = nil
+      compiler_origin = nil
+      paths = nil
+
+      link_annotations.each do |ann|
+        next unless dll = ann.dll
+
+        dll_path = CrystalLibraryPath.paths.each do |path|
+          full_path = File.join(path, dll)
+          break full_path if File.file?(full_path)
+        end
+
+        unless dll_path
+          executable_path ||= Process.executable_path
+          compiler_origin ||= File.dirname(executable_path) if executable_path
+
+          if compiler_origin
+            full_path = File.join(compiler_origin, dll)
+            dll_path = full_path if File.file?(full_path)
+          end
+        end
+
+        unless dll_path
+          paths ||= ENV["PATH"]?.try &.split(Process::PATH_DELIMITER, remove_empty: true)
+
+          dll_path = paths.try &.each do |path|
+            full_path = File.join(path, dll)
+            break full_path if File.file?(full_path)
+          end
+        end
+
+        yield dll_path || dll, !dll_path.nil?
+      end
+    end
+
     PKG_CONFIG_PATH = Process.find_executable("pkg-config")
 
     # Returns the result of running `pkg-config mod` but returns nil if
diff --git a/src/compiler/crystal/compiler.cr b/src/compiler/crystal/compiler.cr
index 237783c2ed8c..283f44289468 100644
--- a/src/compiler/crystal/compiler.cr
+++ b/src/compiler/crystal/compiler.cr
@@ -321,6 +321,10 @@ module Crystal
         {% if flag?(:darwin) %}
           run_dsymutil(output_filename) unless debug.none?
         {% end %}
+
+        {% if flag?(:windows) %}
+          copy_dlls(program, output_filename) if program.has_flag?("preview_dll")
+        {% end %}
       end
 
       CacheDir.instance.cleanup if @cleanup
@@ -345,6 +349,25 @@ module Crystal
       end
     end
 
+    private def copy_dlls(program, output_filename)
+      not_found = nil
+      output_directory = File.dirname(output_filename)
+
+      program.each_dll_path do |path, found|
+        if found
+          FileUtils.cp(path, output_directory)
+        else
+          not_found ||= [] of String
+          not_found << path
+        end
+      end
+
+      if not_found
+        stderr << "Warning: The following DLLs are required at run time, but Crystal is unable to locate them in CRYSTAL_LIBRARY_PATH, the compiler's directory, or PATH: "
+        not_found.sort!.join(stderr, ", ")
+      end
+    end
+
     private def cross_compile(program, units, output_filename)
       unit = units.first
       llvm_mod = unit.llvm_mod
diff --git a/src/compiler/crystal/ffi/lib_ffi.cr b/src/compiler/crystal/ffi/lib_ffi.cr
index 699a0c125468..97163c989ee5 100644
--- a/src/compiler/crystal/ffi/lib_ffi.cr
+++ b/src/compiler/crystal/ffi/lib_ffi.cr
@@ -1,5 +1,8 @@
 module Crystal
   @[Link("ffi")]
+  {% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+    @[Link(dll: "libffi.dll")]
+  {% end %}
   lib LibFFI
     {% begin %}
     enum ABI
diff --git a/src/crystal/lib_iconv.cr b/src/crystal/lib_iconv.cr
index a180a770a67a..5f1506758454 100644
--- a/src/crystal/lib_iconv.cr
+++ b/src/crystal/lib_iconv.cr
@@ -5,6 +5,9 @@ require "c/stddef"
 {% end %}
 
 @[Link("iconv")]
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  @[Link(dll: "libiconv.dll")]
+{% end %}
 lib LibIconv
   type IconvT = Void*
 
diff --git a/src/gc/boehm.cr b/src/gc/boehm.cr
index b4dfb0061900..6c1ff5020cbf 100644
--- a/src/gc/boehm.cr
+++ b/src/gc/boehm.cr
@@ -25,6 +25,9 @@
   @[Link("gc")]
 {% end %}
 
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  @[Link(dll: "gc.dll")]
+{% end %}
 lib LibGC
   alias Int = LibC::Int
   alias SizeT = LibC::SizeT
diff --git a/src/lib_z/lib_z.cr b/src/lib_z/lib_z.cr
index e261cde29683..1c88cb67bba8 100644
--- a/src/lib_z/lib_z.cr
+++ b/src/lib_z/lib_z.cr
@@ -1,4 +1,7 @@
 @[Link("z")]
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  @[Link(dll: "zlib1.dll")]
+{% end %}
 lib LibZ
   alias Char = LibC::Char
   alias Int = LibC::Int
diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr
index ee18eddfbce3..d5e7c2488002 100644
--- a/src/llvm/lib_llvm.cr
+++ b/src/llvm/lib_llvm.cr
@@ -15,6 +15,9 @@
     {% llvm_ldflags = lines[2] %}
 
     @[Link("llvm")]
+    {% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+      @[Link(dll: "LLVM-C.dll")]
+    {% end %}
     lib LibLLVM
     end
   {% else %}
diff --git a/src/openssl/lib_crypto.cr b/src/openssl/lib_crypto.cr
index c783aa7903a9..caca9c11c520 100644
--- a/src/openssl/lib_crypto.cr
+++ b/src/openssl/lib_crypto.cr
@@ -36,6 +36,10 @@
 {% else %}
   @[Link(ldflags: "`command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libcrypto || printf %s '-lcrypto'`")]
 {% end %}
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  # TODO: if someone brings their own OpenSSL 1.x.y on Windows, will this have a different name?
+  @[Link(dll: "libcrypto-3-x64.dll")]
+{% end %}
 lib LibCrypto
   alias Char = LibC::Char
   alias Int = LibC::Int
diff --git a/src/openssl/lib_ssl.cr b/src/openssl/lib_ssl.cr
index 37a4cea3a161..27faf9bbe185 100644
--- a/src/openssl/lib_ssl.cr
+++ b/src/openssl/lib_ssl.cr
@@ -43,6 +43,11 @@ require "./lib_crypto"
 {% else %}
   @[Link(ldflags: "`command -v pkg-config > /dev/null && pkg-config --libs --silence-errors libssl || printf %s '-lssl -lcrypto'`")]
 {% end %}
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  # TODO: if someone brings their own OpenSSL 1.x.y on Windows, will this have a different name?
+  @[Link(dll: "libssl-3-x64.dll")]
+  @[Link(dll: "libcrypto-3-x64.dll")]
+{% end %}
 lib LibSSL
   alias Int = LibC::Int
   alias Char = LibC::Char
diff --git a/src/regex/lib_pcre.cr b/src/regex/lib_pcre.cr
index 5f110eba0ce7..647a172a9d43 100644
--- a/src/regex/lib_pcre.cr
+++ b/src/regex/lib_pcre.cr
@@ -1,4 +1,7 @@
 @[Link("pcre")]
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  @[Link(dll: "pcre.dll")]
+{% end %}
 lib LibPCRE
   alias Int = LibC::Int
 
diff --git a/src/regex/lib_pcre2.cr b/src/regex/lib_pcre2.cr
index a04761cbe07e..71a0fd4b6639 100644
--- a/src/regex/lib_pcre2.cr
+++ b/src/regex/lib_pcre2.cr
@@ -1,4 +1,7 @@
 @[Link("pcre2-8")]
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  @[Link(dll: "pcre2-8.dll")]
+{% end %}
 lib LibPCRE2
   alias Int = LibC::Int
 
diff --git a/src/xml/libxml2.cr b/src/xml/libxml2.cr
index 68c9943425d2..3dff7fb6cb40 100644
--- a/src/xml/libxml2.cr
+++ b/src/xml/libxml2.cr
@@ -5,6 +5,9 @@ require "./html_parser_options"
 require "./save_options"
 
 @[Link("xml2", pkg_config: "libxml-2.0")]
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  @[Link(dll: "libxml2.dll")]
+{% end %}
 lib LibXML
   alias Int = LibC::Int
 
diff --git a/src/yaml/lib_yaml.cr b/src/yaml/lib_yaml.cr
index 4c0d329f8f36..0b4248afc793 100644
--- a/src/yaml/lib_yaml.cr
+++ b/src/yaml/lib_yaml.cr
@@ -1,6 +1,9 @@
 require "./enums"
 
 @[Link("yaml", pkg_config: "yaml-0.1")]
+{% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
+  @[Link(dll: "yaml.dll")]
+{% end %}
 lib LibYAML
   alias Int = LibC::Int
 

From 16864334ab92a0e88942b67c68a19ad7a7703e07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Sun, 24 Dec 2023 10:41:15 +0100
Subject: [PATCH 010/105] Update shards 0.17.4 (#14133)

---
 .github/workflows/win_build_portable.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/win_build_portable.yml b/.github/workflows/win_build_portable.yml
index 18eea4f1f317..21d849c2dcf0 100644
--- a/.github/workflows/win_build_portable.yml
+++ b/.github/workflows/win_build_portable.yml
@@ -120,7 +120,7 @@ jobs:
         uses: actions/checkout@v4
         with:
           repository: crystal-lang/shards
-          ref: v0.17.3
+          ref: v0.17.4
           path: shards
 
       - name: Download molinillo release

From af31a4e84869e53f1b2a906be4399884936fc1bd Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sun, 24 Dec 2023 17:41:24 +0800
Subject: [PATCH 011/105] Simplify `String::Formatter` when Ryu Printf is
 available (#14132)

---
 spec/std/float_printer/ryu_printf_spec.cr |    3 +-
 spec/std/sprintf_spec.cr                  | 1452 +++++++++++----------
 src/float/printer/ryu_printf.cr           |    3 +-
 src/float/printer/ryu_printf_table.cr     |    3 +-
 src/string/formatter.cr                   |  193 +--
 5 files changed, 838 insertions(+), 816 deletions(-)

diff --git a/spec/std/float_printer/ryu_printf_spec.cr b/spec/std/float_printer/ryu_printf_spec.cr
index 4610485f2270..02ac2944a37d 100644
--- a/spec/std/float_printer/ryu_printf_spec.cr
+++ b/spec/std/float_printer/ryu_printf_spec.cr
@@ -1,5 +1,4 @@
-# FIXME: this leads to an OOB on wasm32 (#13918)
-{% skip_file if flag?(:wasm32) %}
+{% skip_file unless String::Formatter::HAS_RYU_PRINTF %}
 
 # This file contains test cases derived from:
 #
diff --git a/spec/std/sprintf_spec.cr b/spec/std/sprintf_spec.cr
index d2da4369827b..67cc1ac1604c 100644
--- a/spec/std/sprintf_spec.cr
+++ b/spec/std/sprintf_spec.cr
@@ -378,798 +378,802 @@ describe "::sprintf" do
     assert_sprintf "1\u{0}%i\u{0}3", 2, "1\u00002\u00003"
   end
 
-  describe "floats" do
-    context "fixed format" do
-      it "works" do
-        assert_sprintf "%f", 123, "123.000000"
-
-        assert_sprintf "%12f", 123.45, "  123.450000"
-        assert_sprintf "%-12f", 123.45, "123.450000  "
-        assert_sprintf "% f", 123.45, " 123.450000"
-        assert_sprintf "%+f", 123, "+123.000000"
-        assert_sprintf "%012f", 123, "00123.000000"
-        assert_sprintf "%.f", 1234.56, "1235"
-        assert_sprintf "%.2f", 1234.5678, "1234.57"
-        assert_sprintf "%10.2f", 1234.5678, "   1234.57"
-        assert_sprintf "%*.2f", [10, 1234.5678], "   1234.57"
-        assert_sprintf "%*.*f", [10, 2, 1234.5678], "   1234.57"
-        assert_sprintf "%.2f", 2.536_f32, "2.54"
-        assert_sprintf "%+0*.*f", [10, 2, 2.536_f32], "+000002.54"
-        assert_sprintf "%#.0f", 1234.56, "1235."
-        assert_sprintf "%#.1f", 1234.56, "1234.6"
-
-        expect_raises(ArgumentError, "Expected dynamic value '*' to be an Int - \"not a number\" (String)") do
-          sprintf("%*f", ["not a number", 2.536_f32])
+  if String::Formatter::HAS_RYU_PRINTF
+    describe "floats" do
+      context "fixed format" do
+        it "works" do
+          assert_sprintf "%f", 123, "123.000000"
+
+          assert_sprintf "%12f", 123.45, "  123.450000"
+          assert_sprintf "%-12f", 123.45, "123.450000  "
+          assert_sprintf "% f", 123.45, " 123.450000"
+          assert_sprintf "%+f", 123, "+123.000000"
+          assert_sprintf "%012f", 123, "00123.000000"
+          assert_sprintf "%.f", 1234.56, "1235"
+          assert_sprintf "%.2f", 1234.5678, "1234.57"
+          assert_sprintf "%10.2f", 1234.5678, "   1234.57"
+          assert_sprintf "%*.2f", [10, 1234.5678], "   1234.57"
+          assert_sprintf "%*.*f", [10, 2, 1234.5678], "   1234.57"
+          assert_sprintf "%.2f", 2.536_f32, "2.54"
+          assert_sprintf "%+0*.*f", [10, 2, 2.536_f32], "+000002.54"
+          assert_sprintf "%#.0f", 1234.56, "1235."
+          assert_sprintf "%#.1f", 1234.56, "1234.6"
+
+          expect_raises(ArgumentError, "Expected dynamic value '*' to be an Int - \"not a number\" (String)") do
+            sprintf("%*f", ["not a number", 2.536_f32])
+          end
+
+          assert_sprintf "%12.2f %12.2f %6.2f %.2f", [2.0, 3.0, 4.0, 5.0], "        2.00         3.00   4.00 5.00"
+
+          assert_sprintf "%f", 1e15, "1000000000000000.000000"
         end
-
-        assert_sprintf "%12.2f %12.2f %6.2f %.2f", [2.0, 3.0, 4.0, 5.0], "        2.00         3.00   4.00 5.00"
-
-        assert_sprintf "%f", 1e15, "1000000000000000.000000"
-      end
-    end
-
-    context "scientific format" do
-      it "works" do
-        assert_sprintf "%e", 123.45, "1.234500e+2"
-        assert_sprintf "%E", 123.45, "1.234500E+2"
-
-        assert_sprintf "%e", Float64::MAX, "1.797693e+308"
-        assert_sprintf "%e", Float64::MIN_POSITIVE, "2.225074e-308"
-        assert_sprintf "%e", Float64::MIN_SUBNORMAL, "4.940656e-324"
-        assert_sprintf "%e", 0.0, "0.000000e+0"
-        assert_sprintf "%e", -0.0, "-0.000000e+0"
-        assert_sprintf "%e", -Float64::MIN_SUBNORMAL, "-4.940656e-324"
-        assert_sprintf "%e", -Float64::MIN_POSITIVE, "-2.225074e-308"
-        assert_sprintf "%e", Float64::MIN, "-1.797693e+308"
       end
 
-      context "width specifier" do
-        it "sets the minimum length of the string" do
-          assert_sprintf "%20e", 123.45, "         1.234500e+2"
-          assert_sprintf "%20e", -123.45, "        -1.234500e+2"
-          assert_sprintf "%+20e", 123.45, "        +1.234500e+2"
-
-          assert_sprintf "%12e", 123.45, " 1.234500e+2"
-          assert_sprintf "%12e", -123.45, "-1.234500e+2"
-          assert_sprintf "%+12e", 123.45, "+1.234500e+2"
-
-          assert_sprintf "%11e", 123.45, "1.234500e+2"
-          assert_sprintf "%11e", -123.45, "-1.234500e+2"
-          assert_sprintf "%+11e", 123.45, "+1.234500e+2"
-
-          assert_sprintf "%2e", 123.45, "1.234500e+2"
-          assert_sprintf "%2e", -123.45, "-1.234500e+2"
-          assert_sprintf "%+2e", 123.45, "+1.234500e+2"
+      context "scientific format" do
+        it "works" do
+          assert_sprintf "%e", 123.45, "1.234500e+2"
+          assert_sprintf "%E", 123.45, "1.234500E+2"
+
+          assert_sprintf "%e", Float64::MAX, "1.797693e+308"
+          assert_sprintf "%e", Float64::MIN_POSITIVE, "2.225074e-308"
+          assert_sprintf "%e", Float64::MIN_SUBNORMAL, "4.940656e-324"
+          assert_sprintf "%e", 0.0, "0.000000e+0"
+          assert_sprintf "%e", -0.0, "-0.000000e+0"
+          assert_sprintf "%e", -Float64::MIN_SUBNORMAL, "-4.940656e-324"
+          assert_sprintf "%e", -Float64::MIN_POSITIVE, "-2.225074e-308"
+          assert_sprintf "%e", Float64::MIN, "-1.797693e+308"
         end
 
-        it "left-justifies on negative width" do
-          assert_sprintf "%*e", [-20, 123.45], "1.234500e+2         "
-        end
-      end
+        context "width specifier" do
+          it "sets the minimum length of the string" do
+            assert_sprintf "%20e", 123.45, "         1.234500e+2"
+            assert_sprintf "%20e", -123.45, "        -1.234500e+2"
+            assert_sprintf "%+20e", 123.45, "        +1.234500e+2"
 
-      context "precision specifier" do
-        it "sets the minimum length of the fractional part" do
-          assert_sprintf "%.0e", 2.0, "2e+0"
-          assert_sprintf "%.0e", 2.5.prev_float, "2e+0"
-          assert_sprintf "%.0e", 2.5, "2e+0"
-          assert_sprintf "%.0e", 2.5.next_float, "3e+0"
-          assert_sprintf "%.0e", 3.0, "3e+0"
-          assert_sprintf "%.0e", 3.5.prev_float, "3e+0"
-          assert_sprintf "%.0e", 3.5, "4e+0"
-          assert_sprintf "%.0e", 3.5.next_float, "4e+0"
-          assert_sprintf "%.0e", 4.0, "4e+0"
-
-          assert_sprintf "%.0e", 9.5, "1e+1"
-
-          assert_sprintf "%.100e", 1.1, "1.1000000000000000888178419700125232338905334472656250000000000000000000000000000000000000000000000000e+0"
-
-          assert_sprintf "%.10000e", 1.0, "1.#{"0" * 10000}e+0"
-
-          assert_sprintf "%.1000e", Float64::MIN_POSITIVE.prev_float,
-            "2.2250738585072008890245868760858598876504231122409594654935248025624400092282356951" \
-            "787758888037591552642309780950434312085877387158357291821993020294379224223559819827" \
-            "501242041788969571311791082261043971979604000454897391938079198936081525613113376149" \
-            "842043271751033627391549782731594143828136275113838604094249464942286316695429105080" \
-            "201815926642134996606517803095075913058719846423906068637102005108723282784678843631" \
-            "944515866135041223479014792369585208321597621066375401613736583044193603714778355306" \
-            "682834535634005074073040135602968046375918583163124224521599262546494300836851861719" \
-            "422417646455137135420132217031370496583210154654068035397417906022589503023501937519" \
-            "773030945763173210852507299305089761582519159720757232455434770912461317493580281734" \
-            "466552734375000000000000000000000000000000000000000000000000000000000000000000000000" \
-            "000000000000000000000000000000000000000000000000000000000000000000000000000000000000" \
-            "000000000000000000000000000000000000000000000000000000000000000000000000000000e-308"
-        end
+            assert_sprintf "%12e", 123.45, " 1.234500e+2"
+            assert_sprintf "%12e", -123.45, "-1.234500e+2"
+            assert_sprintf "%+12e", 123.45, "+1.234500e+2"
 
-        it "can be used with width" do
-          assert_sprintf "%20.12e", 123.45, "   1.234500000000e+2"
-          assert_sprintf "%20.12e", -123.45, "  -1.234500000000e+2"
-          assert_sprintf "%20.12e", 0.0, "   0.000000000000e+0"
+            assert_sprintf "%11e", 123.45, "1.234500e+2"
+            assert_sprintf "%11e", -123.45, "-1.234500e+2"
+            assert_sprintf "%+11e", 123.45, "+1.234500e+2"
 
-          assert_sprintf "%-20.12e", 123.45, "1.234500000000e+2   "
-          assert_sprintf "%-20.12e", -123.45, "-1.234500000000e+2  "
-          assert_sprintf "%-20.12e", 0.0, "0.000000000000e+0   "
-
-          assert_sprintf "%8.12e", 123.45, "1.234500000000e+2"
-          assert_sprintf "%8.12e", -123.45, "-1.234500000000e+2"
-          assert_sprintf "%8.12e", 0.0, "0.000000000000e+0"
-        end
-
-        it "is ignored if precision argument is negative" do
-          assert_sprintf "%.*e", [-2, 123.45], "1.234500e+2"
-        end
-      end
-
-      context "sharp flag" do
-        it "prints a decimal point even if no digits follow" do
-          assert_sprintf "%#.0e", 1.0, "1.e+0"
-          assert_sprintf "%#.0e", 10000.0, "1.e+4"
-          assert_sprintf "%#.0e", 1.0e+23, "1.e+23"
-          assert_sprintf "%#.0e", 1.0e-100, "1.e-100"
-          assert_sprintf "%#.0e", 0.0, "0.e+0"
-          assert_sprintf "%#.0e", -0.0, "-0.e+0"
-        end
-      end
-
-      context "plus flag" do
-        it "writes a plus sign for positive values" do
-          assert_sprintf "%+e", 123.45, "+1.234500e+2"
-          assert_sprintf "%+e", -123.45, "-1.234500e+2"
-          assert_sprintf "%+e", 0.0, "+0.000000e+0"
-        end
-
-        it "writes plus sign after left space-padding" do
-          assert_sprintf "%+20e", 123.45, "        +1.234500e+2"
-          assert_sprintf "%+20e", -123.45, "        -1.234500e+2"
-          assert_sprintf "%+20e", 0.0, "        +0.000000e+0"
-        end
-
-        it "writes plus sign before left zero-padding" do
-          assert_sprintf "%+020e", 123.45, "+000000001.234500e+2"
-          assert_sprintf "%+020e", -123.45, "-000000001.234500e+2"
-          assert_sprintf "%+020e", 0.0, "+000000000.000000e+0"
-        end
-      end
-
-      context "space flag" do
-        it "writes a space for positive values" do
-          assert_sprintf "% e", 123.45, " 1.234500e+2"
-          assert_sprintf "% e", -123.45, "-1.234500e+2"
-          assert_sprintf "% e", 0.0, " 0.000000e+0"
-        end
-
-        it "writes space before left space-padding" do
-          assert_sprintf "% 20e", 123.45, "         1.234500e+2"
-          assert_sprintf "% 20e", -123.45, "        -1.234500e+2"
-          assert_sprintf "% 20e", 0.0, "         0.000000e+0"
-
-          assert_sprintf "% 020e", 123.45, " 000000001.234500e+2"
-          assert_sprintf "% 020e", -123.45, "-000000001.234500e+2"
-          assert_sprintf "% 020e", 0.0, " 000000000.000000e+0"
-        end
-
-        it "is ignored if plus flag is also specified" do
-          assert_sprintf "% +e", 123.45, "+1.234500e+2"
-          assert_sprintf "%+ e", -123.45, "-1.234500e+2"
-        end
-      end
-
-      context "zero flag" do
-        it "left-pads the result with zeros" do
-          assert_sprintf "%020e", 123.45, "0000000001.234500e+2"
-          assert_sprintf "%020e", -123.45, "-000000001.234500e+2"
-          assert_sprintf "%020e", 0.0, "0000000000.000000e+0"
-        end
-
-        it "is ignored if string is left-justified" do
-          assert_sprintf "%-020e", 123.45, "1.234500e+2         "
-          assert_sprintf "%-020e", -123.45, "-1.234500e+2        "
-          assert_sprintf "%-020e", 0.0, "0.000000e+0         "
-        end
-
-        it "can be used with precision" do
-          assert_sprintf "%020.12e", 123.45, "0001.234500000000e+2"
-          assert_sprintf "%020.12e", -123.45, "-001.234500000000e+2"
-          assert_sprintf "%020.12e", 0.0, "0000.000000000000e+0"
-        end
-      end
+            assert_sprintf "%2e", 123.45, "1.234500e+2"
+            assert_sprintf "%2e", -123.45, "-1.234500e+2"
+            assert_sprintf "%+2e", 123.45, "+1.234500e+2"
+          end
 
-      context "minus flag" do
-        it "left-justifies the string" do
-          assert_sprintf "%-20e", 123.45, "1.234500e+2         "
-          assert_sprintf "%-20e", -123.45, "-1.234500e+2        "
-          assert_sprintf "%-20e", 0.0, "0.000000e+0         "
+          it "left-justifies on negative width" do
+            assert_sprintf "%*e", [-20, 123.45], "1.234500e+2         "
+          end
         end
-      end
-    end
-
-    context "general format" do
-      it "works" do
-        assert_sprintf "%g", 123.45, "123.45"
-        assert_sprintf "%G", 123.45, "123.45"
-
-        assert_sprintf "%g", 1.2345e-5, "1.2345e-5"
-        assert_sprintf "%G", 1.2345e-5, "1.2345E-5"
-
-        assert_sprintf "%g", 1.2345e+25, "1.2345e+25"
-        assert_sprintf "%G", 1.2345e+25, "1.2345E+25"
-
-        assert_sprintf "%g", Float64::MAX, "1.79769e+308"
-        assert_sprintf "%g", Float64::MIN_POSITIVE, "2.22507e-308"
-        assert_sprintf "%g", Float64::MIN_SUBNORMAL, "4.94066e-324"
-        assert_sprintf "%g", 0.0, "0"
-        assert_sprintf "%g", -0.0, "-0"
-        assert_sprintf "%g", -Float64::MIN_SUBNORMAL, "-4.94066e-324"
-        assert_sprintf "%g", -Float64::MIN_POSITIVE, "-2.22507e-308"
-        assert_sprintf "%g", Float64::MIN, "-1.79769e+308"
-      end
-
-      context "width specifier" do
-        it "sets the minimum length of the string" do
-          assert_sprintf "%10g", 123.45, "    123.45"
-          assert_sprintf "%10g", -123.45, "   -123.45"
-          assert_sprintf "%+10g", 123.45, "   +123.45"
-
-          assert_sprintf "%7g", 123.45, " 123.45"
-          assert_sprintf "%7g", -123.45, "-123.45"
-          assert_sprintf "%+7g", 123.45, "+123.45"
 
-          assert_sprintf "%6g", 123.45, "123.45"
-          assert_sprintf "%6g", -123.45, "-123.45"
-          assert_sprintf "%+6g", 123.45, "+123.45"
-
-          assert_sprintf "%2g", 123.45, "123.45"
-          assert_sprintf "%2g", -123.45, "-123.45"
-          assert_sprintf "%+2g", 123.45, "+123.45"
+        context "precision specifier" do
+          it "sets the minimum length of the fractional part" do
+            assert_sprintf "%.0e", 2.0, "2e+0"
+            assert_sprintf "%.0e", 2.5.prev_float, "2e+0"
+            assert_sprintf "%.0e", 2.5, "2e+0"
+            assert_sprintf "%.0e", 2.5.next_float, "3e+0"
+            assert_sprintf "%.0e", 3.0, "3e+0"
+            assert_sprintf "%.0e", 3.5.prev_float, "3e+0"
+            assert_sprintf "%.0e", 3.5, "4e+0"
+            assert_sprintf "%.0e", 3.5.next_float, "4e+0"
+            assert_sprintf "%.0e", 4.0, "4e+0"
+
+            assert_sprintf "%.0e", 9.5, "1e+1"
+
+            assert_sprintf "%.100e", 1.1, "1.1000000000000000888178419700125232338905334472656250000000000000000000000000000000000000000000000000e+0"
+
+            assert_sprintf "%.10000e", 1.0, "1.#{"0" * 10000}e+0"
+
+            assert_sprintf "%.1000e", Float64::MIN_POSITIVE.prev_float,
+              "2.2250738585072008890245868760858598876504231122409594654935248025624400092282356951" \
+              "787758888037591552642309780950434312085877387158357291821993020294379224223559819827" \
+              "501242041788969571311791082261043971979604000454897391938079198936081525613113376149" \
+              "842043271751033627391549782731594143828136275113838604094249464942286316695429105080" \
+              "201815926642134996606517803095075913058719846423906068637102005108723282784678843631" \
+              "944515866135041223479014792369585208321597621066375401613736583044193603714778355306" \
+              "682834535634005074073040135602968046375918583163124224521599262546494300836851861719" \
+              "422417646455137135420132217031370496583210154654068035397417906022589503023501937519" \
+              "773030945763173210852507299305089761582519159720757232455434770912461317493580281734" \
+              "466552734375000000000000000000000000000000000000000000000000000000000000000000000000" \
+              "000000000000000000000000000000000000000000000000000000000000000000000000000000000000" \
+              "000000000000000000000000000000000000000000000000000000000000000000000000000000e-308"
+          end
+
+          it "can be used with width" do
+            assert_sprintf "%20.12e", 123.45, "   1.234500000000e+2"
+            assert_sprintf "%20.12e", -123.45, "  -1.234500000000e+2"
+            assert_sprintf "%20.12e", 0.0, "   0.000000000000e+0"
+
+            assert_sprintf "%-20.12e", 123.45, "1.234500000000e+2   "
+            assert_sprintf "%-20.12e", -123.45, "-1.234500000000e+2  "
+            assert_sprintf "%-20.12e", 0.0, "0.000000000000e+0   "
+
+            assert_sprintf "%8.12e", 123.45, "1.234500000000e+2"
+            assert_sprintf "%8.12e", -123.45, "-1.234500000000e+2"
+            assert_sprintf "%8.12e", 0.0, "0.000000000000e+0"
+          end
+
+          it "is ignored if precision argument is negative" do
+            assert_sprintf "%.*e", [-2, 123.45], "1.234500e+2"
+          end
         end
 
-        it "left-justifies on negative width" do
-          assert_sprintf "%*g", [-10, 123.45], "123.45    "
+        context "sharp flag" do
+          it "prints a decimal point even if no digits follow" do
+            assert_sprintf "%#.0e", 1.0, "1.e+0"
+            assert_sprintf "%#.0e", 10000.0, "1.e+4"
+            assert_sprintf "%#.0e", 1.0e+23, "1.e+23"
+            assert_sprintf "%#.0e", 1.0e-100, "1.e-100"
+            assert_sprintf "%#.0e", 0.0, "0.e+0"
+            assert_sprintf "%#.0e", -0.0, "-0.e+0"
+          end
         end
-      end
 
-      context "precision specifier" do
-        it "sets the precision of the value" do
-          assert_sprintf "%.0g", 123.45, "1e+2"
-          assert_sprintf "%.1g", 123.45, "1e+2"
-          assert_sprintf "%.2g", 123.45, "1.2e+2"
-          assert_sprintf "%.3g", 123.45, "123"
-          assert_sprintf "%.4g", 123.45, "123.5"
-          assert_sprintf "%.5g", 123.45, "123.45"
-          assert_sprintf "%.6g", 123.45, "123.45"
-          assert_sprintf "%.7g", 123.45, "123.45"
-          assert_sprintf "%.8g", 123.45, "123.45"
-
-          assert_sprintf "%.1000g", 123.45, "123.4500000000000028421709430404007434844970703125"
-
-          assert_sprintf "%.0g", 1.23e-45, "1e-45"
-          assert_sprintf "%.1g", 1.23e-45, "1e-45"
-          assert_sprintf "%.2g", 1.23e-45, "1.2e-45"
-          assert_sprintf "%.3g", 1.23e-45, "1.23e-45"
-          assert_sprintf "%.4g", 1.23e-45, "1.23e-45"
-          assert_sprintf "%.5g", 1.23e-45, "1.23e-45"
-          assert_sprintf "%.6g", 1.23e-45, "1.23e-45"
-
-          assert_sprintf "%.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125e-5"
+        context "plus flag" do
+          it "writes a plus sign for positive values" do
+            assert_sprintf "%+e", 123.45, "+1.234500e+2"
+            assert_sprintf "%+e", -123.45, "-1.234500e+2"
+            assert_sprintf "%+e", 0.0, "+0.000000e+0"
+          end
+
+          it "writes plus sign after left space-padding" do
+            assert_sprintf "%+20e", 123.45, "        +1.234500e+2"
+            assert_sprintf "%+20e", -123.45, "        -1.234500e+2"
+            assert_sprintf "%+20e", 0.0, "        +0.000000e+0"
+          end
+
+          it "writes plus sign before left zero-padding" do
+            assert_sprintf "%+020e", 123.45, "+000000001.234500e+2"
+            assert_sprintf "%+020e", -123.45, "-000000001.234500e+2"
+            assert_sprintf "%+020e", 0.0, "+000000000.000000e+0"
+          end
         end
 
-        it "can be used with width" do
-          assert_sprintf "%10.1g", 123.45, "      1e+2"
-          assert_sprintf "%10.2g", 123.45, "    1.2e+2"
-          assert_sprintf "%10.3g", 123.45, "       123"
-          assert_sprintf "%10.4g", 123.45, "     123.5"
-          assert_sprintf "%10.5g", 123.45, "    123.45"
-          assert_sprintf "%10.1g", -123.45, "     -1e+2"
-          assert_sprintf "%10.2g", -123.45, "   -1.2e+2"
-          assert_sprintf "%10.3g", -123.45, "      -123"
-          assert_sprintf "%10.4g", -123.45, "    -123.5"
-          assert_sprintf "%10.5g", -123.45, "   -123.45"
-          assert_sprintf "%10.5g", 0, "         0"
-
-          assert_sprintf "%-10.1g", 123.45, "1e+2      "
-          assert_sprintf "%-10.2g", 123.45, "1.2e+2    "
-          assert_sprintf "%-10.3g", 123.45, "123       "
-          assert_sprintf "%-10.4g", 123.45, "123.5     "
-          assert_sprintf "%-10.5g", 123.45, "123.45    "
-          assert_sprintf "%-10.1g", -123.45, "-1e+2     "
-          assert_sprintf "%-10.2g", -123.45, "-1.2e+2   "
-          assert_sprintf "%-10.3g", -123.45, "-123      "
-          assert_sprintf "%-10.4g", -123.45, "-123.5    "
-          assert_sprintf "%-10.5g", -123.45, "-123.45   "
-          assert_sprintf "%-10.5g", 0, "0         "
-
-          assert_sprintf "%3.1g", 123.45, "1e+2"
-          assert_sprintf "%3.2g", 123.45, "1.2e+2"
-          assert_sprintf "%3.3g", 123.45, "123"
-          assert_sprintf "%3.4g", 123.45, "123.5"
-          assert_sprintf "%3.5g", 123.45, "123.45"
-          assert_sprintf "%3.1g", -123.45, "-1e+2"
-          assert_sprintf "%3.2g", -123.45, "-1.2e+2"
-          assert_sprintf "%3.3g", -123.45, "-123"
-          assert_sprintf "%3.4g", -123.45, "-123.5"
-          assert_sprintf "%3.5g", -123.45, "-123.45"
-
-          assert_sprintf "%1000.800g", 123.45, "#{" " * 950}123.4500000000000028421709430404007434844970703125"
+        context "space flag" do
+          it "writes a space for positive values" do
+            assert_sprintf "% e", 123.45, " 1.234500e+2"
+            assert_sprintf "% e", -123.45, "-1.234500e+2"
+            assert_sprintf "% e", 0.0, " 0.000000e+0"
+          end
+
+          it "writes space before left space-padding" do
+            assert_sprintf "% 20e", 123.45, "         1.234500e+2"
+            assert_sprintf "% 20e", -123.45, "        -1.234500e+2"
+            assert_sprintf "% 20e", 0.0, "         0.000000e+0"
+
+            assert_sprintf "% 020e", 123.45, " 000000001.234500e+2"
+            assert_sprintf "% 020e", -123.45, "-000000001.234500e+2"
+            assert_sprintf "% 020e", 0.0, " 000000000.000000e+0"
+          end
+
+          it "is ignored if plus flag is also specified" do
+            assert_sprintf "% +e", 123.45, "+1.234500e+2"
+            assert_sprintf "%+ e", -123.45, "-1.234500e+2"
+          end
         end
 
-        it "is ignored if precision argument is negative" do
-          assert_sprintf "%.*g", [-2, 123.45], "123.45"
+        context "zero flag" do
+          it "left-pads the result with zeros" do
+            assert_sprintf "%020e", 123.45, "0000000001.234500e+2"
+            assert_sprintf "%020e", -123.45, "-000000001.234500e+2"
+            assert_sprintf "%020e", 0.0, "0000000000.000000e+0"
+          end
+
+          it "is ignored if string is left-justified" do
+            assert_sprintf "%-020e", 123.45, "1.234500e+2         "
+            assert_sprintf "%-020e", -123.45, "-1.234500e+2        "
+            assert_sprintf "%-020e", 0.0, "0.000000e+0         "
+          end
+
+          it "can be used with precision" do
+            assert_sprintf "%020.12e", 123.45, "0001.234500000000e+2"
+            assert_sprintf "%020.12e", -123.45, "-001.234500000000e+2"
+            assert_sprintf "%020.12e", 0.0, "0000.000000000000e+0"
+          end
         end
-      end
 
-      context "sharp flag" do
-        it "prints decimal point and trailing zeros" do
-          assert_sprintf "%#.0g", 12345, "1.e+4"
-          assert_sprintf "%#.6g", 12345, "12345.0"
-          assert_sprintf "%#.10g", 12345, "12345.00000"
-          assert_sprintf "%#.100g", 12345, "12345.#{"0" * 95}"
-          assert_sprintf "%#.1000g", 12345, "12345.#{"0" * 995}"
-
-          assert_sprintf "%#.0g", 1e-5, "1.e-5"
-          assert_sprintf "%#.6g", 1e-5, "1.00000e-5"
-          assert_sprintf "%#.10g", 1e-5, "1.000000000e-5"
-          assert_sprintf "%#.100g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 35}e-5"
-          assert_sprintf "%#.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 935}e-5"
-
-          assert_sprintf "%#15.0g", 12345, "          1.e+4"
-          assert_sprintf "%#15.6g", 12345, "        12345.0"
-          assert_sprintf "%#15.10g", 12345, "    12345.00000"
+        context "minus flag" do
+          it "left-justifies the string" do
+            assert_sprintf "%-20e", 123.45, "1.234500e+2         "
+            assert_sprintf "%-20e", -123.45, "-1.234500e+2        "
+            assert_sprintf "%-20e", 0.0, "0.000000e+0         "
+          end
         end
       end
 
-      context "plus flag" do
-        it "writes a plus sign for positive values" do
-          assert_sprintf "%+g", 123.45, "+123.45"
-          assert_sprintf "%+g", -123.45, "-123.45"
-          assert_sprintf "%+g", 0.0, "+0"
+      context "general format" do
+        it "works" do
+          assert_sprintf "%g", 123.45, "123.45"
+          assert_sprintf "%G", 123.45, "123.45"
+
+          assert_sprintf "%g", 1.2345e-5, "1.2345e-5"
+          assert_sprintf "%G", 1.2345e-5, "1.2345E-5"
+
+          assert_sprintf "%g", 1.2345e+25, "1.2345e+25"
+          assert_sprintf "%G", 1.2345e+25, "1.2345E+25"
+
+          assert_sprintf "%g", Float64::MAX, "1.79769e+308"
+          assert_sprintf "%g", Float64::MIN_POSITIVE, "2.22507e-308"
+          assert_sprintf "%g", Float64::MIN_SUBNORMAL, "4.94066e-324"
+          assert_sprintf "%g", 0.0, "0"
+          assert_sprintf "%g", -0.0, "-0"
+          assert_sprintf "%g", -Float64::MIN_SUBNORMAL, "-4.94066e-324"
+          assert_sprintf "%g", -Float64::MIN_POSITIVE, "-2.22507e-308"
+          assert_sprintf "%g", Float64::MIN, "-1.79769e+308"
         end
 
-        it "writes plus sign after left space-padding" do
-          assert_sprintf "%+10g", 123.45, "   +123.45"
-          assert_sprintf "%+10g", -123.45, "   -123.45"
-          assert_sprintf "%+10g", 0.0, "        +0"
-        end
+        context "width specifier" do
+          it "sets the minimum length of the string" do
+            assert_sprintf "%10g", 123.45, "    123.45"
+            assert_sprintf "%10g", -123.45, "   -123.45"
+            assert_sprintf "%+10g", 123.45, "   +123.45"
 
-        it "writes plus sign before left zero-padding" do
-          assert_sprintf "%+010g", 123.45, "+000123.45"
-          assert_sprintf "%+010g", -123.45, "-000123.45"
-          assert_sprintf "%+010g", 0.0, "+000000000"
-        end
-      end
+            assert_sprintf "%7g", 123.45, " 123.45"
+            assert_sprintf "%7g", -123.45, "-123.45"
+            assert_sprintf "%+7g", 123.45, "+123.45"
 
-      context "space flag" do
-        it "writes a space for positive values" do
-          assert_sprintf "% g", 123.45, " 123.45"
-          assert_sprintf "% g", -123.45, "-123.45"
-          assert_sprintf "% g", 0.0, " 0"
-        end
+            assert_sprintf "%6g", 123.45, "123.45"
+            assert_sprintf "%6g", -123.45, "-123.45"
+            assert_sprintf "%+6g", 123.45, "+123.45"
 
-        it "writes space before left space-padding" do
-          assert_sprintf "% 10g", 123.45, "    123.45"
-          assert_sprintf "% 10g", -123.45, "   -123.45"
-          assert_sprintf "% 10g", 0.0, "         0"
+            assert_sprintf "%2g", 123.45, "123.45"
+            assert_sprintf "%2g", -123.45, "-123.45"
+            assert_sprintf "%+2g", 123.45, "+123.45"
+          end
 
-          assert_sprintf "% 010g", 123.45, " 000123.45"
-          assert_sprintf "% 010g", -123.45, "-000123.45"
-          assert_sprintf "% 010g", 0.0, " 000000000"
+          it "left-justifies on negative width" do
+            assert_sprintf "%*g", [-10, 123.45], "123.45    "
+          end
         end
 
-        it "is ignored if plus flag is also specified" do
-          assert_sprintf "% +g", 123.45, "+123.45"
-          assert_sprintf "%+ g", -123.45, "-123.45"
+        context "precision specifier" do
+          it "sets the precision of the value" do
+            assert_sprintf "%.0g", 123.45, "1e+2"
+            assert_sprintf "%.1g", 123.45, "1e+2"
+            assert_sprintf "%.2g", 123.45, "1.2e+2"
+            assert_sprintf "%.3g", 123.45, "123"
+            assert_sprintf "%.4g", 123.45, "123.5"
+            assert_sprintf "%.5g", 123.45, "123.45"
+            assert_sprintf "%.6g", 123.45, "123.45"
+            assert_sprintf "%.7g", 123.45, "123.45"
+            assert_sprintf "%.8g", 123.45, "123.45"
+
+            assert_sprintf "%.1000g", 123.45, "123.4500000000000028421709430404007434844970703125"
+
+            assert_sprintf "%.0g", 1.23e-45, "1e-45"
+            assert_sprintf "%.1g", 1.23e-45, "1e-45"
+            assert_sprintf "%.2g", 1.23e-45, "1.2e-45"
+            assert_sprintf "%.3g", 1.23e-45, "1.23e-45"
+            assert_sprintf "%.4g", 1.23e-45, "1.23e-45"
+            assert_sprintf "%.5g", 1.23e-45, "1.23e-45"
+            assert_sprintf "%.6g", 1.23e-45, "1.23e-45"
+
+            assert_sprintf "%.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125e-5"
+          end
+
+          it "can be used with width" do
+            assert_sprintf "%10.1g", 123.45, "      1e+2"
+            assert_sprintf "%10.2g", 123.45, "    1.2e+2"
+            assert_sprintf "%10.3g", 123.45, "       123"
+            assert_sprintf "%10.4g", 123.45, "     123.5"
+            assert_sprintf "%10.5g", 123.45, "    123.45"
+            assert_sprintf "%10.1g", -123.45, "     -1e+2"
+            assert_sprintf "%10.2g", -123.45, "   -1.2e+2"
+            assert_sprintf "%10.3g", -123.45, "      -123"
+            assert_sprintf "%10.4g", -123.45, "    -123.5"
+            assert_sprintf "%10.5g", -123.45, "   -123.45"
+            assert_sprintf "%10.5g", 0, "         0"
+
+            assert_sprintf "%-10.1g", 123.45, "1e+2      "
+            assert_sprintf "%-10.2g", 123.45, "1.2e+2    "
+            assert_sprintf "%-10.3g", 123.45, "123       "
+            assert_sprintf "%-10.4g", 123.45, "123.5     "
+            assert_sprintf "%-10.5g", 123.45, "123.45    "
+            assert_sprintf "%-10.1g", -123.45, "-1e+2     "
+            assert_sprintf "%-10.2g", -123.45, "-1.2e+2   "
+            assert_sprintf "%-10.3g", -123.45, "-123      "
+            assert_sprintf "%-10.4g", -123.45, "-123.5    "
+            assert_sprintf "%-10.5g", -123.45, "-123.45   "
+            assert_sprintf "%-10.5g", 0, "0         "
+
+            assert_sprintf "%3.1g", 123.45, "1e+2"
+            assert_sprintf "%3.2g", 123.45, "1.2e+2"
+            assert_sprintf "%3.3g", 123.45, "123"
+            assert_sprintf "%3.4g", 123.45, "123.5"
+            assert_sprintf "%3.5g", 123.45, "123.45"
+            assert_sprintf "%3.1g", -123.45, "-1e+2"
+            assert_sprintf "%3.2g", -123.45, "-1.2e+2"
+            assert_sprintf "%3.3g", -123.45, "-123"
+            assert_sprintf "%3.4g", -123.45, "-123.5"
+            assert_sprintf "%3.5g", -123.45, "-123.45"
+
+            assert_sprintf "%1000.800g", 123.45, "#{" " * 950}123.4500000000000028421709430404007434844970703125"
+          end
+
+          it "is ignored if precision argument is negative" do
+            assert_sprintf "%.*g", [-2, 123.45], "123.45"
+          end
         end
-      end
 
-      context "zero flag" do
-        it "left-pads the result with zeros" do
-          assert_sprintf "%010g", 123.45, "0000123.45"
-          assert_sprintf "%010g", -123.45, "-000123.45"
-          assert_sprintf "%010g", 0.0, "0000000000"
+        context "sharp flag" do
+          it "prints decimal point and trailing zeros" do
+            assert_sprintf "%#.0g", 12345, "1.e+4"
+            assert_sprintf "%#.6g", 12345, "12345.0"
+            assert_sprintf "%#.10g", 12345, "12345.00000"
+            assert_sprintf "%#.100g", 12345, "12345.#{"0" * 95}"
+            assert_sprintf "%#.1000g", 12345, "12345.#{"0" * 995}"
+
+            assert_sprintf "%#.0g", 1e-5, "1.e-5"
+            assert_sprintf "%#.6g", 1e-5, "1.00000e-5"
+            assert_sprintf "%#.10g", 1e-5, "1.000000000e-5"
+            assert_sprintf "%#.100g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 35}e-5"
+            assert_sprintf "%#.1000g", 1e-5, "1.0000000000000000818030539140313095458623138256371021270751953125#{"0" * 935}e-5"
+
+            assert_sprintf "%#15.0g", 12345, "          1.e+4"
+            assert_sprintf "%#15.6g", 12345, "        12345.0"
+            assert_sprintf "%#15.10g", 12345, "    12345.00000"
+          end
         end
 
-        it "is ignored if string is left-justified" do
-          assert_sprintf "%-010g", 123.45, "123.45    "
-          assert_sprintf "%-010g", -123.45, "-123.45   "
-          assert_sprintf "%-010g", 0.0, "0         "
+        context "plus flag" do
+          it "writes a plus sign for positive values" do
+            assert_sprintf "%+g", 123.45, "+123.45"
+            assert_sprintf "%+g", -123.45, "-123.45"
+            assert_sprintf "%+g", 0.0, "+0"
+          end
+
+          it "writes plus sign after left space-padding" do
+            assert_sprintf "%+10g", 123.45, "   +123.45"
+            assert_sprintf "%+10g", -123.45, "   -123.45"
+            assert_sprintf "%+10g", 0.0, "        +0"
+          end
+
+          it "writes plus sign before left zero-padding" do
+            assert_sprintf "%+010g", 123.45, "+000123.45"
+            assert_sprintf "%+010g", -123.45, "-000123.45"
+            assert_sprintf "%+010g", 0.0, "+000000000"
+          end
         end
 
-        it "can be used with precision" do
-          assert_sprintf "%010.2g", 123.45, "00001.2e+2"
-          assert_sprintf "%010.2g", -123.45, "-0001.2e+2"
-          assert_sprintf "%010.2g", 0.0, "0000000000"
+        context "space flag" do
+          it "writes a space for positive values" do
+            assert_sprintf "% g", 123.45, " 123.45"
+            assert_sprintf "% g", -123.45, "-123.45"
+            assert_sprintf "% g", 0.0, " 0"
+          end
+
+          it "writes space before left space-padding" do
+            assert_sprintf "% 10g", 123.45, "    123.45"
+            assert_sprintf "% 10g", -123.45, "   -123.45"
+            assert_sprintf "% 10g", 0.0, "         0"
+
+            assert_sprintf "% 010g", 123.45, " 000123.45"
+            assert_sprintf "% 010g", -123.45, "-000123.45"
+            assert_sprintf "% 010g", 0.0, " 000000000"
+          end
+
+          it "is ignored if plus flag is also specified" do
+            assert_sprintf "% +g", 123.45, "+123.45"
+            assert_sprintf "%+ g", -123.45, "-123.45"
+          end
         end
-      end
-
-      context "minus flag" do
-        it "left-justifies the string" do
-          assert_sprintf "%-10g", 123.45, "123.45    "
-          assert_sprintf "%-10g", -123.45, "-123.45   "
-          assert_sprintf "%-10g", 0.0, "0         "
 
-          assert_sprintf "%- 10g", 123.45, " 123.45   "
-          assert_sprintf "%- 10g", -123.45, "-123.45   "
-          assert_sprintf "%- 10g", 0.0, " 0        "
+        context "zero flag" do
+          it "left-pads the result with zeros" do
+            assert_sprintf "%010g", 123.45, "0000123.45"
+            assert_sprintf "%010g", -123.45, "-000123.45"
+            assert_sprintf "%010g", 0.0, "0000000000"
+          end
+
+          it "is ignored if string is left-justified" do
+            assert_sprintf "%-010g", 123.45, "123.45    "
+            assert_sprintf "%-010g", -123.45, "-123.45   "
+            assert_sprintf "%-010g", 0.0, "0         "
+          end
+
+          it "can be used with precision" do
+            assert_sprintf "%010.2g", 123.45, "00001.2e+2"
+            assert_sprintf "%010.2g", -123.45, "-0001.2e+2"
+            assert_sprintf "%010.2g", 0.0, "0000000000"
+          end
         end
-      end
-    end
 
-    context "hex format" do
-      it "works" do
-        assert_sprintf "%a", 1194684.0, "0x1.23abcp+20"
-        assert_sprintf "%A", 1194684.0, "0X1.23ABCP+20"
-        assert_sprintf "%a", 12345678.45, "0x1.78c29ce666666p+23"
-        assert_sprintf "%A", 12345678.45, "0X1.78C29CE666666P+23"
-
-        assert_sprintf "%a", Float64::MAX, "0x1.fffffffffffffp+1023"
-        assert_sprintf "%a", Float64::MIN_POSITIVE, "0x1p-1022"
-        assert_sprintf "%a", Float64::MIN_SUBNORMAL, "0x0.0000000000001p-1022"
-        assert_sprintf "%a", 0.0, "0x0p+0"
-        assert_sprintf "%a", -0.0, "-0x0p+0"
-        assert_sprintf "%a", -Float64::MIN_SUBNORMAL, "-0x0.0000000000001p-1022"
-        assert_sprintf "%a", -Float64::MIN_POSITIVE, "-0x1p-1022"
-        assert_sprintf "%a", Float64::MIN, "-0x1.fffffffffffffp+1023"
-      end
-
-      context "width specifier" do
-        it "sets the minimum length of the string" do
-          assert_sprintf "%20a", hexfloat("0x1p+0"), "              0x1p+0"
-          assert_sprintf "%20a", hexfloat("0x1.2p+0"), "            0x1.2p+0"
-          assert_sprintf "%20a", hexfloat("0x1.23p+0"), "           0x1.23p+0"
-          assert_sprintf "%20a", hexfloat("0x1.234p+0"), "          0x1.234p+0"
-          assert_sprintf "%20a", hexfloat("0x1.2345p+0"), "         0x1.2345p+0"
-          assert_sprintf "%20a", hexfloat("0x1.23456p+0"), "        0x1.23456p+0"
-          assert_sprintf "%20a", hexfloat("0x1.234567p+0"), "       0x1.234567p+0"
-          assert_sprintf "%20a", hexfloat("0x1.2345678p+0"), "      0x1.2345678p+0"
-          assert_sprintf "%20a", hexfloat("0x1.23456789p+0"), "     0x1.23456789p+0"
-          assert_sprintf "%20a", hexfloat("0x1.23456789ap+0"), "    0x1.23456789ap+0"
-          assert_sprintf "%20a", hexfloat("0x1.23456789abp+0"), "   0x1.23456789abp+0"
-          assert_sprintf "%20a", hexfloat("0x1.23456789abcp+0"), "  0x1.23456789abcp+0"
-
-          assert_sprintf "%20a", hexfloat("-0x1p+0"), "             -0x1p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.2p+0"), "           -0x1.2p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.23p+0"), "          -0x1.23p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.234p+0"), "         -0x1.234p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.2345p+0"), "        -0x1.2345p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.23456p+0"), "       -0x1.23456p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.234567p+0"), "      -0x1.234567p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.2345678p+0"), "     -0x1.2345678p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.23456789p+0"), "    -0x1.23456789p+0"
-          assert_sprintf "%20a", hexfloat("-0x1.23456789ap+0"), "   -0x1.23456789ap+0"
-          assert_sprintf "%20a", hexfloat("-0x1.23456789abp+0"), "  -0x1.23456789abp+0"
-          assert_sprintf "%20a", hexfloat("-0x1.23456789abcp+0"), " -0x1.23456789abcp+0"
-
-          assert_sprintf "%+20a", 1194684.0, "      +0x1.23abcp+20"
-
-          assert_sprintf "%14a", 1194684.0, " 0x1.23abcp+20"
-          assert_sprintf "%14a", -1194684.0, "-0x1.23abcp+20"
-          assert_sprintf "%+14a", 1194684.0, "+0x1.23abcp+20"
-
-          assert_sprintf "%13a", 1194684.0, "0x1.23abcp+20"
-          assert_sprintf "%13a", -1194684.0, "-0x1.23abcp+20"
-          assert_sprintf "%+13a", 1194684.0, "+0x1.23abcp+20"
-
-          assert_sprintf "%2a", 1194684.0, "0x1.23abcp+20"
-          assert_sprintf "%2a", -1194684.0, "-0x1.23abcp+20"
-          assert_sprintf "%+2a", 1194684.0, "+0x1.23abcp+20"
-        end
+        context "minus flag" do
+          it "left-justifies the string" do
+            assert_sprintf "%-10g", 123.45, "123.45    "
+            assert_sprintf "%-10g", -123.45, "-123.45   "
+            assert_sprintf "%-10g", 0.0, "0         "
 
-        it "left-justifies on negative width" do
-          assert_sprintf "%*a", [-20, 1194684.0], "0x1.23abcp+20       "
+            assert_sprintf "%- 10g", 123.45, " 123.45   "
+            assert_sprintf "%- 10g", -123.45, "-123.45   "
+            assert_sprintf "%- 10g", 0.0, " 0        "
+          end
         end
       end
 
-      context "precision specifier" do
-        it "sets the minimum length of the fractional part" do
-          assert_sprintf "%.0a", 0.0, "0x0p+0"
-
-          assert_sprintf "%.0a", (Float64::MIN_POSITIVE / 2).prev_float, "0x0p-1022"
-          assert_sprintf "%.0a", Float64::MIN_POSITIVE / 2, "0x0p-1022"
-          assert_sprintf "%.0a", (Float64::MIN_POSITIVE / 2).next_float, "0x1p-1022"
-          assert_sprintf "%.0a", Float64::MIN_POSITIVE.prev_float, "0x1p-1022"
-          assert_sprintf "%.0a", Float64::MIN_POSITIVE, "0x1p-1022"
-
-          assert_sprintf "%.0a", 0.0625, "0x1p-4"
-          assert_sprintf "%.0a", 0.0625.next_float, "0x1p-4"
-          assert_sprintf "%.0a", 0.09375.prev_float, "0x1p-4"
-          assert_sprintf "%.0a", 0.09375, "0x2p-4"
-          assert_sprintf "%.0a", 0.09375.next_float, "0x2p-4"
-          assert_sprintf "%.0a", 0.125.prev_float, "0x2p-4"
-          assert_sprintf "%.0a", 0.125, "0x1p-3"
-
-          assert_sprintf "%.1a", 2.0, "0x1.0p+1"
-          assert_sprintf "%.1a", 2.0.next_float, "0x1.0p+1"
-          assert_sprintf "%.1a", 2.0625.prev_float, "0x1.0p+1"
-          assert_sprintf "%.1a", 2.0625, "0x1.0p+1"
-          assert_sprintf "%.1a", 2.0625.next_float, "0x1.1p+1"
-          assert_sprintf "%.1a", 2.125.prev_float, "0x1.1p+1"
-          assert_sprintf "%.1a", 2.125, "0x1.1p+1"
-          assert_sprintf "%.1a", 2.125.next_float, "0x1.1p+1"
-          assert_sprintf "%.1a", 2.1875.prev_float, "0x1.1p+1"
-          assert_sprintf "%.1a", 2.1875, "0x1.2p+1"
-          assert_sprintf "%.1a", 2.1875.next_float, "0x1.2p+1"
-          assert_sprintf "%.1a", 2.25.prev_float, "0x1.2p+1"
-          assert_sprintf "%.1a", 2.25, "0x1.2p+1"
-
-          assert_sprintf "%.1a", 60.0, "0x1.ep+5"
-          assert_sprintf "%.1a", 60.0.next_float, "0x1.ep+5"
-          assert_sprintf "%.1a", 61.0.prev_float, "0x1.ep+5"
-          assert_sprintf "%.1a", 61.0, "0x1.ep+5"
-          assert_sprintf "%.1a", 61.0.next_float, "0x1.fp+5"
-          assert_sprintf "%.1a", 62.0.prev_float, "0x1.fp+5"
-          assert_sprintf "%.1a", 62.0, "0x1.fp+5"
-          assert_sprintf "%.1a", 62.0.next_float, "0x1.fp+5"
-          assert_sprintf "%.1a", 63.0.prev_float, "0x1.fp+5"
-          assert_sprintf "%.1a", 63.0, "0x2.0p+5"
-          assert_sprintf "%.1a", 63.0.next_float, "0x2.0p+5"
-          assert_sprintf "%.1a", 64.0.prev_float, "0x2.0p+5"
-          assert_sprintf "%.1a", 64.0, "0x1.0p+6"
-
-          assert_sprintf "%.4a", 65536.0, "0x1.0000p+16"
-          assert_sprintf "%.4a", 65536.0.next_float, "0x1.0000p+16"
-          assert_sprintf "%.4a", 65536.5.prev_float, "0x1.0000p+16"
-          assert_sprintf "%.4a", 65536.5, "0x1.0000p+16"
-          assert_sprintf "%.4a", 65536.5.next_float, "0x1.0001p+16"
-          assert_sprintf "%.4a", 65537.0.prev_float, "0x1.0001p+16"
-          assert_sprintf "%.4a", 65537.0, "0x1.0001p+16"
-          assert_sprintf "%.4a", 65537.0.next_float, "0x1.0001p+16"
-          assert_sprintf "%.4a", 65537.5.prev_float, "0x1.0001p+16"
-          assert_sprintf "%.4a", 65537.5, "0x1.0002p+16"
-          assert_sprintf "%.4a", 65537.5.next_float, "0x1.0002p+16"
-          assert_sprintf "%.4a", 65538.0.prev_float, "0x1.0002p+16"
-          assert_sprintf "%.4a", 65538.0, "0x1.0002p+16"
-
-          assert_sprintf "%.4a", 131070.0, "0x1.fffep+16"
-          assert_sprintf "%.4a", 131070.0.next_float, "0x1.fffep+16"
-          assert_sprintf "%.4a", 131070.5.prev_float, "0x1.fffep+16"
-          assert_sprintf "%.4a", 131070.5, "0x1.fffep+16"
-          assert_sprintf "%.4a", 131070.5.next_float, "0x1.ffffp+16"
-          assert_sprintf "%.4a", 131071.0.prev_float, "0x1.ffffp+16"
-          assert_sprintf "%.4a", 131071.0, "0x1.ffffp+16"
-          assert_sprintf "%.4a", 131071.0.next_float, "0x1.ffffp+16"
-          assert_sprintf "%.4a", 131071.5.prev_float, "0x1.ffffp+16"
-          assert_sprintf "%.4a", 131071.5, "0x2.0000p+16"
-          assert_sprintf "%.4a", 131071.5.next_float, "0x2.0000p+16"
-          assert_sprintf "%.4a", 131072.0.prev_float, "0x2.0000p+16"
-          assert_sprintf "%.4a", 131072.0, "0x1.0000p+17"
-
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x01, "0x0.000000000000p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x07, "0x0.000000000000p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x08, "0x0.000000000000p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x09, "0x0.000000000001p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x0f, "0x0.000000000001p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x10, "0x0.000000000001p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x11, "0x0.000000000001p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x17, "0x0.000000000001p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x18, "0x0.000000000002p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x19, "0x0.000000000002p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x1f, "0x0.000000000002p-1022"
-          assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x20, "0x0.000000000002p-1022"
-
-          assert_sprintf "%.17a", Float64::MAX, "0x1.fffffffffffff0000p+1023"
-          assert_sprintf "%.16a", Float64::MAX, "0x1.fffffffffffff000p+1023"
-          assert_sprintf "%.15a", Float64::MAX, "0x1.fffffffffffff00p+1023"
-          assert_sprintf "%.14a", Float64::MAX, "0x1.fffffffffffff0p+1023"
-          assert_sprintf "%.13a", Float64::MAX, "0x1.fffffffffffffp+1023"
-          assert_sprintf "%.12a", Float64::MAX, "0x2.000000000000p+1023"
-          assert_sprintf "%.11a", Float64::MAX, "0x2.00000000000p+1023"
-          assert_sprintf "%.10a", Float64::MAX, "0x2.0000000000p+1023"
-          assert_sprintf "%.9a", Float64::MAX, "0x2.000000000p+1023"
-          assert_sprintf "%.8a", Float64::MAX, "0x2.00000000p+1023"
-          assert_sprintf "%.7a", Float64::MAX, "0x2.0000000p+1023"
-          assert_sprintf "%.6a", Float64::MAX, "0x2.000000p+1023"
-          assert_sprintf "%.5a", Float64::MAX, "0x2.00000p+1023"
-          assert_sprintf "%.4a", Float64::MAX, "0x2.0000p+1023"
-          assert_sprintf "%.3a", Float64::MAX, "0x2.000p+1023"
-          assert_sprintf "%.2a", Float64::MAX, "0x2.00p+1023"
-          assert_sprintf "%.1a", Float64::MAX, "0x2.0p+1023"
-          assert_sprintf "%.0a", Float64::MAX, "0x2p+1023"
-
-          assert_sprintf "%.1000a", 1194684.0, "0x1.23abc#{"0" * 995}p+20"
+      context "hex format" do
+        it "works" do
+          assert_sprintf "%a", 1194684.0, "0x1.23abcp+20"
+          assert_sprintf "%A", 1194684.0, "0X1.23ABCP+20"
+          assert_sprintf "%a", 12345678.45, "0x1.78c29ce666666p+23"
+          assert_sprintf "%A", 12345678.45, "0X1.78C29CE666666P+23"
+
+          assert_sprintf "%a", Float64::MAX, "0x1.fffffffffffffp+1023"
+          assert_sprintf "%a", Float64::MIN_POSITIVE, "0x1p-1022"
+          assert_sprintf "%a", Float64::MIN_SUBNORMAL, "0x0.0000000000001p-1022"
+          assert_sprintf "%a", 0.0, "0x0p+0"
+          assert_sprintf "%a", -0.0, "-0x0p+0"
+          assert_sprintf "%a", -Float64::MIN_SUBNORMAL, "-0x0.0000000000001p-1022"
+          assert_sprintf "%a", -Float64::MIN_POSITIVE, "-0x1p-1022"
+          assert_sprintf "%a", Float64::MIN, "-0x1.fffffffffffffp+1023"
         end
 
-        it "can be used with width" do
-          assert_sprintf "%20.8a", 1194684.0, "    0x1.23abc000p+20"
-          assert_sprintf "%20.8a", -1194684.0, "   -0x1.23abc000p+20"
-          assert_sprintf "%20.8a", 0.0, "     0x0.00000000p+0"
-
-          assert_sprintf "%-20.8a", 1194684.0, "0x1.23abc000p+20    "
-          assert_sprintf "%-20.8a", -1194684.0, "-0x1.23abc000p+20   "
-          assert_sprintf "%-20.8a", 0.0, "0x0.00000000p+0     "
-
-          assert_sprintf "%4.8a", 1194684.0, "0x1.23abc000p+20"
-          assert_sprintf "%4.8a", -1194684.0, "-0x1.23abc000p+20"
-          assert_sprintf "%4.8a", 0.0, "0x0.00000000p+0"
-        end
-
-        it "is ignored if precision argument is negative" do
-          assert_sprintf "%.*a", [-2, 1194684.0], "0x1.23abcp+20"
-        end
-      end
-
-      context "sharp flag" do
-        it "prints a decimal point even if no digits follow" do
-          assert_sprintf "%#a", 1.0, "0x1.p+0"
-          assert_sprintf "%#a", Float64::MIN_POSITIVE, "0x1.p-1022"
-          assert_sprintf "%#a", 2.0 ** -234, "0x1.p-234"
-          assert_sprintf "%#a", 2.0 ** 1021, "0x1.p+1021"
-          assert_sprintf "%#a", 0.0, "0x0.p+0"
-          assert_sprintf "%#a", -0.0, "-0x0.p+0"
-
-          assert_sprintf "%#.0a", 1.0, "0x1.p+0"
-          assert_sprintf "%#.0a", Float64::MIN_POSITIVE, "0x1.p-1022"
-          assert_sprintf "%#.0a", 2.0 ** -234, "0x1.p-234"
-          assert_sprintf "%#.0a", 2.0 ** 1021, "0x1.p+1021"
-          assert_sprintf "%#.0a", 1194684.0, "0x1.p+20"
-          assert_sprintf "%#.0a", 0.0, "0x0.p+0"
-          assert_sprintf "%#.0a", -0.0, "-0x0.p+0"
+        context "width specifier" do
+          it "sets the minimum length of the string" do
+            assert_sprintf "%20a", hexfloat("0x1p+0"), "              0x1p+0"
+            assert_sprintf "%20a", hexfloat("0x1.2p+0"), "            0x1.2p+0"
+            assert_sprintf "%20a", hexfloat("0x1.23p+0"), "           0x1.23p+0"
+            assert_sprintf "%20a", hexfloat("0x1.234p+0"), "          0x1.234p+0"
+            assert_sprintf "%20a", hexfloat("0x1.2345p+0"), "         0x1.2345p+0"
+            assert_sprintf "%20a", hexfloat("0x1.23456p+0"), "        0x1.23456p+0"
+            assert_sprintf "%20a", hexfloat("0x1.234567p+0"), "       0x1.234567p+0"
+            assert_sprintf "%20a", hexfloat("0x1.2345678p+0"), "      0x1.2345678p+0"
+            assert_sprintf "%20a", hexfloat("0x1.23456789p+0"), "     0x1.23456789p+0"
+            assert_sprintf "%20a", hexfloat("0x1.23456789ap+0"), "    0x1.23456789ap+0"
+            assert_sprintf "%20a", hexfloat("0x1.23456789abp+0"), "   0x1.23456789abp+0"
+            assert_sprintf "%20a", hexfloat("0x1.23456789abcp+0"), "  0x1.23456789abcp+0"
+
+            assert_sprintf "%20a", hexfloat("-0x1p+0"), "             -0x1p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.2p+0"), "           -0x1.2p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.23p+0"), "          -0x1.23p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.234p+0"), "         -0x1.234p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.2345p+0"), "        -0x1.2345p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.23456p+0"), "       -0x1.23456p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.234567p+0"), "      -0x1.234567p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.2345678p+0"), "     -0x1.2345678p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.23456789p+0"), "    -0x1.23456789p+0"
+            assert_sprintf "%20a", hexfloat("-0x1.23456789ap+0"), "   -0x1.23456789ap+0"
+            assert_sprintf "%20a", hexfloat("-0x1.23456789abp+0"), "  -0x1.23456789abp+0"
+            assert_sprintf "%20a", hexfloat("-0x1.23456789abcp+0"), " -0x1.23456789abcp+0"
+
+            assert_sprintf "%+20a", 1194684.0, "      +0x1.23abcp+20"
+
+            assert_sprintf "%14a", 1194684.0, " 0x1.23abcp+20"
+            assert_sprintf "%14a", -1194684.0, "-0x1.23abcp+20"
+            assert_sprintf "%+14a", 1194684.0, "+0x1.23abcp+20"
+
+            assert_sprintf "%13a", 1194684.0, "0x1.23abcp+20"
+            assert_sprintf "%13a", -1194684.0, "-0x1.23abcp+20"
+            assert_sprintf "%+13a", 1194684.0, "+0x1.23abcp+20"
+
+            assert_sprintf "%2a", 1194684.0, "0x1.23abcp+20"
+            assert_sprintf "%2a", -1194684.0, "-0x1.23abcp+20"
+            assert_sprintf "%+2a", 1194684.0, "+0x1.23abcp+20"
+          end
+
+          it "left-justifies on negative width" do
+            assert_sprintf "%*a", [-20, 1194684.0], "0x1.23abcp+20       "
+          end
         end
-      end
 
-      context "plus flag" do
-        it "writes a plus sign for positive values" do
-          assert_sprintf "%+a", 1194684.0, "+0x1.23abcp+20"
-          assert_sprintf "%+a", -1194684.0, "-0x1.23abcp+20"
-          assert_sprintf "%+a", 0.0, "+0x0p+0"
+        context "precision specifier" do
+          it "sets the minimum length of the fractional part" do
+            assert_sprintf "%.0a", 0.0, "0x0p+0"
+
+            assert_sprintf "%.0a", (Float64::MIN_POSITIVE / 2).prev_float, "0x0p-1022"
+            assert_sprintf "%.0a", Float64::MIN_POSITIVE / 2, "0x0p-1022"
+            assert_sprintf "%.0a", (Float64::MIN_POSITIVE / 2).next_float, "0x1p-1022"
+            assert_sprintf "%.0a", Float64::MIN_POSITIVE.prev_float, "0x1p-1022"
+            assert_sprintf "%.0a", Float64::MIN_POSITIVE, "0x1p-1022"
+
+            assert_sprintf "%.0a", 0.0625, "0x1p-4"
+            assert_sprintf "%.0a", 0.0625.next_float, "0x1p-4"
+            assert_sprintf "%.0a", 0.09375.prev_float, "0x1p-4"
+            assert_sprintf "%.0a", 0.09375, "0x2p-4"
+            assert_sprintf "%.0a", 0.09375.next_float, "0x2p-4"
+            assert_sprintf "%.0a", 0.125.prev_float, "0x2p-4"
+            assert_sprintf "%.0a", 0.125, "0x1p-3"
+
+            assert_sprintf "%.1a", 2.0, "0x1.0p+1"
+            assert_sprintf "%.1a", 2.0.next_float, "0x1.0p+1"
+            assert_sprintf "%.1a", 2.0625.prev_float, "0x1.0p+1"
+            assert_sprintf "%.1a", 2.0625, "0x1.0p+1"
+            assert_sprintf "%.1a", 2.0625.next_float, "0x1.1p+1"
+            assert_sprintf "%.1a", 2.125.prev_float, "0x1.1p+1"
+            assert_sprintf "%.1a", 2.125, "0x1.1p+1"
+            assert_sprintf "%.1a", 2.125.next_float, "0x1.1p+1"
+            assert_sprintf "%.1a", 2.1875.prev_float, "0x1.1p+1"
+            assert_sprintf "%.1a", 2.1875, "0x1.2p+1"
+            assert_sprintf "%.1a", 2.1875.next_float, "0x1.2p+1"
+            assert_sprintf "%.1a", 2.25.prev_float, "0x1.2p+1"
+            assert_sprintf "%.1a", 2.25, "0x1.2p+1"
+
+            assert_sprintf "%.1a", 60.0, "0x1.ep+5"
+            assert_sprintf "%.1a", 60.0.next_float, "0x1.ep+5"
+            assert_sprintf "%.1a", 61.0.prev_float, "0x1.ep+5"
+            assert_sprintf "%.1a", 61.0, "0x1.ep+5"
+            assert_sprintf "%.1a", 61.0.next_float, "0x1.fp+5"
+            assert_sprintf "%.1a", 62.0.prev_float, "0x1.fp+5"
+            assert_sprintf "%.1a", 62.0, "0x1.fp+5"
+            assert_sprintf "%.1a", 62.0.next_float, "0x1.fp+5"
+            assert_sprintf "%.1a", 63.0.prev_float, "0x1.fp+5"
+            assert_sprintf "%.1a", 63.0, "0x2.0p+5"
+            assert_sprintf "%.1a", 63.0.next_float, "0x2.0p+5"
+            assert_sprintf "%.1a", 64.0.prev_float, "0x2.0p+5"
+            assert_sprintf "%.1a", 64.0, "0x1.0p+6"
+
+            assert_sprintf "%.4a", 65536.0, "0x1.0000p+16"
+            assert_sprintf "%.4a", 65536.0.next_float, "0x1.0000p+16"
+            assert_sprintf "%.4a", 65536.5.prev_float, "0x1.0000p+16"
+            assert_sprintf "%.4a", 65536.5, "0x1.0000p+16"
+            assert_sprintf "%.4a", 65536.5.next_float, "0x1.0001p+16"
+            assert_sprintf "%.4a", 65537.0.prev_float, "0x1.0001p+16"
+            assert_sprintf "%.4a", 65537.0, "0x1.0001p+16"
+            assert_sprintf "%.4a", 65537.0.next_float, "0x1.0001p+16"
+            assert_sprintf "%.4a", 65537.5.prev_float, "0x1.0001p+16"
+            assert_sprintf "%.4a", 65537.5, "0x1.0002p+16"
+            assert_sprintf "%.4a", 65537.5.next_float, "0x1.0002p+16"
+            assert_sprintf "%.4a", 65538.0.prev_float, "0x1.0002p+16"
+            assert_sprintf "%.4a", 65538.0, "0x1.0002p+16"
+
+            assert_sprintf "%.4a", 131070.0, "0x1.fffep+16"
+            assert_sprintf "%.4a", 131070.0.next_float, "0x1.fffep+16"
+            assert_sprintf "%.4a", 131070.5.prev_float, "0x1.fffep+16"
+            assert_sprintf "%.4a", 131070.5, "0x1.fffep+16"
+            assert_sprintf "%.4a", 131070.5.next_float, "0x1.ffffp+16"
+            assert_sprintf "%.4a", 131071.0.prev_float, "0x1.ffffp+16"
+            assert_sprintf "%.4a", 131071.0, "0x1.ffffp+16"
+            assert_sprintf "%.4a", 131071.0.next_float, "0x1.ffffp+16"
+            assert_sprintf "%.4a", 131071.5.prev_float, "0x1.ffffp+16"
+            assert_sprintf "%.4a", 131071.5, "0x2.0000p+16"
+            assert_sprintf "%.4a", 131071.5.next_float, "0x2.0000p+16"
+            assert_sprintf "%.4a", 131072.0.prev_float, "0x2.0000p+16"
+            assert_sprintf "%.4a", 131072.0, "0x1.0000p+17"
+
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x01, "0x0.000000000000p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x07, "0x0.000000000000p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x08, "0x0.000000000000p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x09, "0x0.000000000001p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x0f, "0x0.000000000001p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x10, "0x0.000000000001p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x11, "0x0.000000000001p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x17, "0x0.000000000001p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x18, "0x0.000000000002p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x19, "0x0.000000000002p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x1f, "0x0.000000000002p-1022"
+            assert_sprintf "%.12a", Float64::MIN_SUBNORMAL * 0x20, "0x0.000000000002p-1022"
+
+            assert_sprintf "%.17a", Float64::MAX, "0x1.fffffffffffff0000p+1023"
+            assert_sprintf "%.16a", Float64::MAX, "0x1.fffffffffffff000p+1023"
+            assert_sprintf "%.15a", Float64::MAX, "0x1.fffffffffffff00p+1023"
+            assert_sprintf "%.14a", Float64::MAX, "0x1.fffffffffffff0p+1023"
+            assert_sprintf "%.13a", Float64::MAX, "0x1.fffffffffffffp+1023"
+            assert_sprintf "%.12a", Float64::MAX, "0x2.000000000000p+1023"
+            assert_sprintf "%.11a", Float64::MAX, "0x2.00000000000p+1023"
+            assert_sprintf "%.10a", Float64::MAX, "0x2.0000000000p+1023"
+            assert_sprintf "%.9a", Float64::MAX, "0x2.000000000p+1023"
+            assert_sprintf "%.8a", Float64::MAX, "0x2.00000000p+1023"
+            assert_sprintf "%.7a", Float64::MAX, "0x2.0000000p+1023"
+            assert_sprintf "%.6a", Float64::MAX, "0x2.000000p+1023"
+            assert_sprintf "%.5a", Float64::MAX, "0x2.00000p+1023"
+            assert_sprintf "%.4a", Float64::MAX, "0x2.0000p+1023"
+            assert_sprintf "%.3a", Float64::MAX, "0x2.000p+1023"
+            assert_sprintf "%.2a", Float64::MAX, "0x2.00p+1023"
+            assert_sprintf "%.1a", Float64::MAX, "0x2.0p+1023"
+            assert_sprintf "%.0a", Float64::MAX, "0x2p+1023"
+
+            assert_sprintf "%.1000a", 1194684.0, "0x1.23abc#{"0" * 995}p+20"
+          end
+
+          it "can be used with width" do
+            assert_sprintf "%20.8a", 1194684.0, "    0x1.23abc000p+20"
+            assert_sprintf "%20.8a", -1194684.0, "   -0x1.23abc000p+20"
+            assert_sprintf "%20.8a", 0.0, "     0x0.00000000p+0"
+
+            assert_sprintf "%-20.8a", 1194684.0, "0x1.23abc000p+20    "
+            assert_sprintf "%-20.8a", -1194684.0, "-0x1.23abc000p+20   "
+            assert_sprintf "%-20.8a", 0.0, "0x0.00000000p+0     "
+
+            assert_sprintf "%4.8a", 1194684.0, "0x1.23abc000p+20"
+            assert_sprintf "%4.8a", -1194684.0, "-0x1.23abc000p+20"
+            assert_sprintf "%4.8a", 0.0, "0x0.00000000p+0"
+          end
+
+          it "is ignored if precision argument is negative" do
+            assert_sprintf "%.*a", [-2, 1194684.0], "0x1.23abcp+20"
+          end
         end
 
-        it "writes plus sign after left space-padding" do
-          assert_sprintf "%+20a", 1194684.0, "      +0x1.23abcp+20"
-          assert_sprintf "%+20a", -1194684.0, "      -0x1.23abcp+20"
-          assert_sprintf "%+20a", 0.0, "             +0x0p+0"
+        context "sharp flag" do
+          it "prints a decimal point even if no digits follow" do
+            assert_sprintf "%#a", 1.0, "0x1.p+0"
+            assert_sprintf "%#a", Float64::MIN_POSITIVE, "0x1.p-1022"
+            assert_sprintf "%#a", 2.0 ** -234, "0x1.p-234"
+            assert_sprintf "%#a", 2.0 ** 1021, "0x1.p+1021"
+            assert_sprintf "%#a", 0.0, "0x0.p+0"
+            assert_sprintf "%#a", -0.0, "-0x0.p+0"
+
+            assert_sprintf "%#.0a", 1.0, "0x1.p+0"
+            assert_sprintf "%#.0a", Float64::MIN_POSITIVE, "0x1.p-1022"
+            assert_sprintf "%#.0a", 2.0 ** -234, "0x1.p-234"
+            assert_sprintf "%#.0a", 2.0 ** 1021, "0x1.p+1021"
+            assert_sprintf "%#.0a", 1194684.0, "0x1.p+20"
+            assert_sprintf "%#.0a", 0.0, "0x0.p+0"
+            assert_sprintf "%#.0a", -0.0, "-0x0.p+0"
+          end
         end
 
-        it "writes plus sign before left zero-padding" do
-          assert_sprintf "%+020a", 1194684.0, "+0x0000001.23abcp+20"
-          assert_sprintf "%+020a", -1194684.0, "-0x0000001.23abcp+20"
-          assert_sprintf "%+020a", 0.0, "+0x00000000000000p+0"
+        context "plus flag" do
+          it "writes a plus sign for positive values" do
+            assert_sprintf "%+a", 1194684.0, "+0x1.23abcp+20"
+            assert_sprintf "%+a", -1194684.0, "-0x1.23abcp+20"
+            assert_sprintf "%+a", 0.0, "+0x0p+0"
+          end
+
+          it "writes plus sign after left space-padding" do
+            assert_sprintf "%+20a", 1194684.0, "      +0x1.23abcp+20"
+            assert_sprintf "%+20a", -1194684.0, "      -0x1.23abcp+20"
+            assert_sprintf "%+20a", 0.0, "             +0x0p+0"
+          end
+
+          it "writes plus sign before left zero-padding" do
+            assert_sprintf "%+020a", 1194684.0, "+0x0000001.23abcp+20"
+            assert_sprintf "%+020a", -1194684.0, "-0x0000001.23abcp+20"
+            assert_sprintf "%+020a", 0.0, "+0x00000000000000p+0"
+          end
         end
-      end
 
-      context "space flag" do
-        it "writes a space for positive values" do
-          assert_sprintf "% a", 1194684.0, " 0x1.23abcp+20"
-          assert_sprintf "% a", -1194684.0, "-0x1.23abcp+20"
-          assert_sprintf "% a", 0.0, " 0x0p+0"
+        context "space flag" do
+          it "writes a space for positive values" do
+            assert_sprintf "% a", 1194684.0, " 0x1.23abcp+20"
+            assert_sprintf "% a", -1194684.0, "-0x1.23abcp+20"
+            assert_sprintf "% a", 0.0, " 0x0p+0"
+          end
+
+          it "writes space before left space-padding" do
+            assert_sprintf "% 20a", 1194684.0, "       0x1.23abcp+20"
+            assert_sprintf "% 20a", -1194684.0, "      -0x1.23abcp+20"
+            assert_sprintf "% 20a", 0.0, "              0x0p+0"
+
+            assert_sprintf "% 020a", 1194684.0, " 0x0000001.23abcp+20"
+            assert_sprintf "% 020a", -1194684.0, "-0x0000001.23abcp+20"
+            assert_sprintf "% 020a", 0.0, " 0x00000000000000p+0"
+          end
+
+          it "is ignored if plus flag is also specified" do
+            assert_sprintf "% +a", 1194684.0, "+0x1.23abcp+20"
+            assert_sprintf "%+ a", -1194684.0, "-0x1.23abcp+20"
+          end
         end
 
-        it "writes space before left space-padding" do
-          assert_sprintf "% 20a", 1194684.0, "       0x1.23abcp+20"
-          assert_sprintf "% 20a", -1194684.0, "      -0x1.23abcp+20"
-          assert_sprintf "% 20a", 0.0, "              0x0p+0"
-
-          assert_sprintf "% 020a", 1194684.0, " 0x0000001.23abcp+20"
-          assert_sprintf "% 020a", -1194684.0, "-0x0000001.23abcp+20"
-          assert_sprintf "% 020a", 0.0, " 0x00000000000000p+0"
+        context "zero flag" do
+          it "left-pads the result with zeros" do
+            assert_sprintf "%020a", 1194684.0, "0x00000001.23abcp+20"
+            assert_sprintf "%020a", -1194684.0, "-0x0000001.23abcp+20"
+            assert_sprintf "%020a", 0.0, "0x000000000000000p+0"
+          end
+
+          it "is ignored if string is left-justified" do
+            assert_sprintf "%-020a", 1194684.0, "0x1.23abcp+20       "
+            assert_sprintf "%-020a", -1194684.0, "-0x1.23abcp+20      "
+            assert_sprintf "%-020a", 0.0, "0x0p+0              "
+          end
+
+          it "can be used with precision" do
+            assert_sprintf "%020.8a", 1194684.0, "0x00001.23abc000p+20"
+            assert_sprintf "%020.8a", -1194684.0, "-0x0001.23abc000p+20"
+            assert_sprintf "%020.8a", 0.0, "0x000000.00000000p+0"
+          end
         end
 
-        it "is ignored if plus flag is also specified" do
-          assert_sprintf "% +a", 1194684.0, "+0x1.23abcp+20"
-          assert_sprintf "%+ a", -1194684.0, "-0x1.23abcp+20"
+        context "minus flag" do
+          it "left-justifies the string" do
+            assert_sprintf "%-20a", 1194684.0, "0x1.23abcp+20       "
+            assert_sprintf "%-20a", -1194684.0, "-0x1.23abcp+20      "
+            assert_sprintf "%-20a", 0.0, "0x0p+0              "
+          end
         end
       end
 
-      context "zero flag" do
-        it "left-pads the result with zeros" do
-          assert_sprintf "%020a", 1194684.0, "0x00000001.23abcp+20"
-          assert_sprintf "%020a", -1194684.0, "-0x0000001.23abcp+20"
-          assert_sprintf "%020a", 0.0, "0x000000000000000p+0"
+      [Float32, Float64].each do |float|
+        it "infinities" do
+          pos_inf = float.new(1) / float.new(0)
+          neg_inf = float.new(-1) / float.new(0)
+
+          assert_sprintf "%f", pos_inf, "inf"
+          assert_sprintf "%a", pos_inf, "inf"
+          assert_sprintf "%e", pos_inf, "inf"
+          assert_sprintf "%g", pos_inf, "inf"
+          assert_sprintf "%A", pos_inf, "INF"
+          assert_sprintf "%E", pos_inf, "INF"
+          assert_sprintf "%G", pos_inf, "INF"
+
+          assert_sprintf "%f", neg_inf, "-inf"
+          assert_sprintf "%G", neg_inf, "-INF"
+
+          assert_sprintf "%2f", pos_inf, "inf"
+          assert_sprintf "%4f", pos_inf, " inf"
+          assert_sprintf "%6f", pos_inf, "   inf"
+          assert_sprintf "%2f", neg_inf, "-inf"
+          assert_sprintf "%4f", neg_inf, "-inf"
+          assert_sprintf "%6f", neg_inf, "  -inf"
+
+          assert_sprintf "% f", pos_inf, " inf"
+          assert_sprintf "% 2f", pos_inf, " inf"
+          assert_sprintf "% 4f", pos_inf, " inf"
+          assert_sprintf "% 6f", pos_inf, "   inf"
+          assert_sprintf "% f", neg_inf, "-inf"
+          assert_sprintf "% 2f", neg_inf, "-inf"
+          assert_sprintf "% 4f", neg_inf, "-inf"
+          assert_sprintf "% 6f", neg_inf, "  -inf"
+
+          assert_sprintf "%+f", pos_inf, "+inf"
+          assert_sprintf "%+2f", pos_inf, "+inf"
+          assert_sprintf "%+4f", pos_inf, "+inf"
+          assert_sprintf "%+6f", pos_inf, "  +inf"
+          assert_sprintf "%+f", neg_inf, "-inf"
+          assert_sprintf "%+2f", neg_inf, "-inf"
+          assert_sprintf "%+4f", neg_inf, "-inf"
+          assert_sprintf "%+6f", neg_inf, "  -inf"
+
+          assert_sprintf "%+ f", pos_inf, "+inf"
+
+          assert_sprintf "%-4f", pos_inf, "inf "
+          assert_sprintf "%-6f", pos_inf, "inf   "
+          assert_sprintf "%-4f", neg_inf, "-inf"
+          assert_sprintf "%-6f", neg_inf, "-inf  "
+
+          assert_sprintf "% -4f", pos_inf, " inf"
+          assert_sprintf "% -6f", pos_inf, " inf  "
+          assert_sprintf "% -4f", neg_inf, "-inf"
+          assert_sprintf "% -6f", neg_inf, "-inf  "
+
+          assert_sprintf "%-+4f", pos_inf, "+inf"
+          assert_sprintf "%-+6f", pos_inf, "+inf  "
+          assert_sprintf "%-+4f", neg_inf, "-inf"
+          assert_sprintf "%-+6f", neg_inf, "-inf  "
+
+          assert_sprintf "%-+ 6f", pos_inf, "+inf  "
+
+          assert_sprintf "%06f", pos_inf, "   inf"
+          assert_sprintf "%-06f", pos_inf, "inf   "
+          assert_sprintf "%06f", neg_inf, "  -inf"
+          assert_sprintf "%-06f", neg_inf, "-inf  "
+
+          assert_sprintf "%.1f", pos_inf, "inf"
+
+          assert_sprintf "%#f", pos_inf, "inf"
         end
 
-        it "is ignored if string is left-justified" do
-          assert_sprintf "%-020a", 1194684.0, "0x1.23abcp+20       "
-          assert_sprintf "%-020a", -1194684.0, "-0x1.23abcp+20      "
-          assert_sprintf "%-020a", 0.0, "0x0p+0              "
+        it "not-a-numbers" do
+          pos_nan = Math.copysign(float.new(0) / float.new(0), 1)
+          neg_nan = Math.copysign(float.new(0) / float.new(0), -1)
+
+          assert_sprintf "%f", pos_nan, "nan"
+          assert_sprintf "%a", pos_nan, "nan"
+          assert_sprintf "%e", pos_nan, "nan"
+          assert_sprintf "%g", pos_nan, "nan"
+          assert_sprintf "%A", pos_nan, "NAN"
+          assert_sprintf "%E", pos_nan, "NAN"
+          assert_sprintf "%G", pos_nan, "NAN"
+
+          assert_sprintf "%f", neg_nan, "nan"
+          assert_sprintf "%a", neg_nan, "nan"
+          assert_sprintf "%e", neg_nan, "nan"
+          assert_sprintf "%g", neg_nan, "nan"
+          assert_sprintf "%A", neg_nan, "NAN"
+          assert_sprintf "%E", neg_nan, "NAN"
+          assert_sprintf "%G", neg_nan, "NAN"
+
+          assert_sprintf "%+f", pos_nan, "+nan"
+          assert_sprintf "%+f", neg_nan, "+nan"
         end
-
-        it "can be used with precision" do
-          assert_sprintf "%020.8a", 1194684.0, "0x00001.23abc000p+20"
-          assert_sprintf "%020.8a", -1194684.0, "-0x0001.23abc000p+20"
-          assert_sprintf "%020.8a", 0.0, "0x000000.00000000p+0"
-        end
-      end
-
-      context "minus flag" do
-        it "left-justifies the string" do
-          assert_sprintf "%-20a", 1194684.0, "0x1.23abcp+20       "
-          assert_sprintf "%-20a", -1194684.0, "-0x1.23abcp+20      "
-          assert_sprintf "%-20a", 0.0, "0x0p+0              "
-        end
-      end
-    end
-
-    [Float32, Float64].each do |float|
-      it "infinities" do
-        pos_inf = float.new(1) / float.new(0)
-        neg_inf = float.new(-1) / float.new(0)
-
-        assert_sprintf "%f", pos_inf, "inf"
-        assert_sprintf "%a", pos_inf, "inf"
-        assert_sprintf "%e", pos_inf, "inf"
-        assert_sprintf "%g", pos_inf, "inf"
-        assert_sprintf "%A", pos_inf, "INF"
-        assert_sprintf "%E", pos_inf, "INF"
-        assert_sprintf "%G", pos_inf, "INF"
-
-        assert_sprintf "%f", neg_inf, "-inf"
-        assert_sprintf "%G", neg_inf, "-INF"
-
-        assert_sprintf "%2f", pos_inf, "inf"
-        assert_sprintf "%4f", pos_inf, " inf"
-        assert_sprintf "%6f", pos_inf, "   inf"
-        assert_sprintf "%2f", neg_inf, "-inf"
-        assert_sprintf "%4f", neg_inf, "-inf"
-        assert_sprintf "%6f", neg_inf, "  -inf"
-
-        assert_sprintf "% f", pos_inf, " inf"
-        assert_sprintf "% 2f", pos_inf, " inf"
-        assert_sprintf "% 4f", pos_inf, " inf"
-        assert_sprintf "% 6f", pos_inf, "   inf"
-        assert_sprintf "% f", neg_inf, "-inf"
-        assert_sprintf "% 2f", neg_inf, "-inf"
-        assert_sprintf "% 4f", neg_inf, "-inf"
-        assert_sprintf "% 6f", neg_inf, "  -inf"
-
-        assert_sprintf "%+f", pos_inf, "+inf"
-        assert_sprintf "%+2f", pos_inf, "+inf"
-        assert_sprintf "%+4f", pos_inf, "+inf"
-        assert_sprintf "%+6f", pos_inf, "  +inf"
-        assert_sprintf "%+f", neg_inf, "-inf"
-        assert_sprintf "%+2f", neg_inf, "-inf"
-        assert_sprintf "%+4f", neg_inf, "-inf"
-        assert_sprintf "%+6f", neg_inf, "  -inf"
-
-        assert_sprintf "%+ f", pos_inf, "+inf"
-
-        assert_sprintf "%-4f", pos_inf, "inf "
-        assert_sprintf "%-6f", pos_inf, "inf   "
-        assert_sprintf "%-4f", neg_inf, "-inf"
-        assert_sprintf "%-6f", neg_inf, "-inf  "
-
-        assert_sprintf "% -4f", pos_inf, " inf"
-        assert_sprintf "% -6f", pos_inf, " inf  "
-        assert_sprintf "% -4f", neg_inf, "-inf"
-        assert_sprintf "% -6f", neg_inf, "-inf  "
-
-        assert_sprintf "%-+4f", pos_inf, "+inf"
-        assert_sprintf "%-+6f", pos_inf, "+inf  "
-        assert_sprintf "%-+4f", neg_inf, "-inf"
-        assert_sprintf "%-+6f", neg_inf, "-inf  "
-
-        assert_sprintf "%-+ 6f", pos_inf, "+inf  "
-
-        assert_sprintf "%06f", pos_inf, "   inf"
-        assert_sprintf "%-06f", pos_inf, "inf   "
-        assert_sprintf "%06f", neg_inf, "  -inf"
-        assert_sprintf "%-06f", neg_inf, "-inf  "
-
-        assert_sprintf "%.1f", pos_inf, "inf"
-
-        assert_sprintf "%#f", pos_inf, "inf"
-      end
-
-      it "not-a-numbers" do
-        pos_nan = Math.copysign(float.new(0) / float.new(0), 1)
-        neg_nan = Math.copysign(float.new(0) / float.new(0), -1)
-
-        assert_sprintf "%f", pos_nan, "nan"
-        assert_sprintf "%a", pos_nan, "nan"
-        assert_sprintf "%e", pos_nan, "nan"
-        assert_sprintf "%g", pos_nan, "nan"
-        assert_sprintf "%A", pos_nan, "NAN"
-        assert_sprintf "%E", pos_nan, "NAN"
-        assert_sprintf "%G", pos_nan, "NAN"
-
-        assert_sprintf "%f", neg_nan, "nan"
-        assert_sprintf "%a", neg_nan, "nan"
-        assert_sprintf "%e", neg_nan, "nan"
-        assert_sprintf "%g", neg_nan, "nan"
-        assert_sprintf "%A", neg_nan, "NAN"
-        assert_sprintf "%E", neg_nan, "NAN"
-        assert_sprintf "%G", neg_nan, "NAN"
-
-        assert_sprintf "%+f", pos_nan, "+nan"
-        assert_sprintf "%+f", neg_nan, "+nan"
       end
     end
+  else
+    pending "floats"
   end
 
   context "strings" do
diff --git a/src/float/printer/ryu_printf.cr b/src/float/printer/ryu_printf.cr
index 005e575c3806..feffb98fdb0e 100644
--- a/src/float/printer/ryu_printf.cr
+++ b/src/float/printer/ryu_printf.cr
@@ -1,5 +1,4 @@
-# FIXME: this leads to an OOB on wasm32 (#13918)
-{% skip_file if flag?(:wasm32) %}
+{% skip_file unless String::Formatter::HAS_RYU_PRINTF %}
 
 require "./ryu_printf_table"
 
diff --git a/src/float/printer/ryu_printf_table.cr b/src/float/printer/ryu_printf_table.cr
index 6e16b939f16c..b9db3363f072 100644
--- a/src/float/printer/ryu_printf_table.cr
+++ b/src/float/printer/ryu_printf_table.cr
@@ -1,5 +1,4 @@
-# FIXME: this leads to an OOB on wasm32 (#13918)
-{% skip_file if flag?(:wasm32) %}
+{% skip_file unless String::Formatter::HAS_RYU_PRINTF %}
 
 module Float::Printer::RyuPrintf
   {% begin %}
diff --git a/src/string/formatter.cr b/src/string/formatter.cr
index 31239f42ee4d..b5f80d2aee87 100644
--- a/src/string/formatter.cr
+++ b/src/string/formatter.cr
@@ -2,6 +2,13 @@ require "c/stdio"
 
 # :nodoc:
 struct String::Formatter(A)
+  # FIXME: wasm32 appears to run out of memory if we use Ryu Printf, which
+  # initializes very large lookup tables, so we fall back to `LibC.snprintf` for
+  # the floating-point format specifiers (#13918)
+  {% begin %}
+    HAS_RYU_PRINTF = {{ !flag?(:wasm32) }}
+  {% end %}
+
   private enum Mode
     None
 
@@ -15,15 +22,19 @@ struct String::Formatter(A)
     Named
   end
 
-  @format_buf = Pointer(UInt8).null
-  @temp_buf = Pointer(UInt8).null
+  {% unless HAS_RYU_PRINTF %}
+    @format_buf = Pointer(UInt8).null
+    @format_buf_len = 0
+
+    @temp_buf = Pointer(UInt8).null
+    @temp_buf_len = 0
+  {% end %}
+
   @arg_mode : Mode = :none
 
   def initialize(string, @args : A, @io : IO)
     @reader = Char::Reader.new(string)
     @arg_index = 0
-    @temp_buf_len = 0
-    @format_buf_len = 0
   end
 
   def format : Nil
@@ -118,13 +129,17 @@ struct String::Formatter(A)
           next
         else
           flags.width = val
-          flags.width_size = size
+          {% unless HAS_RYU_PRINTF %}
+            flags.width_size = size
+          {% end %}
           break
         end
       when '*'
         val = consume_dynamic_value
         flags.width = val
-        flags.width_size = val.to_s.size
+        {% unless HAS_RYU_PRINTF %}
+          flags.width_size = val.to_s.size
+        {% end %}
         break
       else
         break
@@ -141,16 +156,22 @@ struct String::Formatter(A)
       when '0'..'9'
         num, size = consume_number
         flags.precision = num
-        flags.precision_size = size
+        {% unless HAS_RYU_PRINTF %}
+          flags.precision_size = size
+        {% end %}
       when '*'
         val = consume_dynamic_value
         if val >= 0
           flags.precision = val
-          flags.precision_size = val.to_s.size
+          {% unless HAS_RYU_PRINTF %}
+            flags.precision_size = val.to_s.size
+          {% end %}
         end
       else
         flags.precision = 0
-        flags.precision_size = 1
+        {% unless HAS_RYU_PRINTF %}
+          flags.precision_size = 1
+        {% end %}
       end
     end
     flags
@@ -307,12 +328,7 @@ struct String::Formatter(A)
       elsif float.nan?
         float_special("nan", 1, flags)
       else
-        # FIXME: wasm32 appears to run out of memory if we use Ryu Printf, which
-        # initializes very large lookup tables, so we always fall back to
-        # `LibC.snprintf` (#13918)
-        {% if flag?(:wasm32) %}
-          float_fallback(float, flags)
-        {% else %}
+        {% if HAS_RYU_PRINTF %}
           case flags.type
           when 'f'
             float_fixed(float, flags)
@@ -325,6 +341,8 @@ struct String::Formatter(A)
           else
             raise "BUG: Unknown format type '#{flags.type}'"
           end
+        {% else %}
+          float_fallback(float, flags)
         {% end %}
       end
     else
@@ -346,7 +364,7 @@ struct String::Formatter(A)
     pad(str_size, flags) if flags.right_padding?
   end
 
-  {% unless flag?(:wasm32) %}
+  {% if HAS_RYU_PRINTF %}
     # Formats floats with `%f`
     private def float_fixed(float, flags)
       # the longest string possible is due to `Float64::MIN_SUBNORMAL`, which
@@ -485,50 +503,78 @@ struct String::Formatter(A)
 
       pad(str_size, flags) if flags.right_padding?
     end
-  {% end %}
+  {% else %}
+    # Delegate to `LibC.snprintf` for float formats if Ryu Printf is unavailable
+    private def float_fallback(float, flags)
+      format_buf = recreate_float_format_string(flags)
 
-  # Delegate to `LibC.snprintf` for float formats not yet ported to Crystal
-  private def float_fallback(float, flags)
-    format_buf = recreate_float_format_string(flags)
+      len = LibC.snprintf(nil, 0, format_buf, float) + 1
+      temp_buf = temp_buf(len)
+      LibC.snprintf(temp_buf, len, format_buf, float)
 
-    len = LibC.snprintf(nil, 0, format_buf, float) + 1
-    temp_buf = temp_buf(len)
-    LibC.snprintf(temp_buf, len, format_buf, float)
+      @io.write_string Slice.new(temp_buf, len - 1)
+    end
 
-    @io.write_string Slice.new(temp_buf, len - 1)
-  end
+    # Here we rebuild the original format string, like %f or %.2g and use snprintf
+    private def recreate_float_format_string(flags)
+      capacity = 3 # percent + type + \0
+      capacity += flags.width_size
+      capacity += flags.precision_size + 1 # size + .
+      capacity += 1 if flags.sharp
+      capacity += 1 if flags.plus
+      capacity += 1 if flags.minus
+      capacity += 1 if flags.zero
+      capacity += 1 if flags.space
+
+      format_buf = format_buf(capacity)
+      original_format_buf = format_buf
+
+      io = IO::Memory.new(Bytes.new(format_buf, capacity))
+      io << '%'
+      io << '#' if flags.sharp
+      io << '+' if flags.plus
+      io << '-' if flags.minus
+      io << '0' if flags.zero
+      io << ' ' if flags.space
+      io << flags.width if flags.width > 0
+      if precision = flags.precision
+        io << '.'
+        io << precision if precision != 0
+      end
+      io << flags.type
+      io.write_byte 0_u8
 
-  # Here we rebuild the original format string, like %f or %.2g and use snprintf
-  def recreate_float_format_string(flags)
-    capacity = 3 # percent + type + \0
-    capacity += flags.width_size
-    capacity += flags.precision_size + 1 # size + .
-    capacity += 1 if flags.sharp
-    capacity += 1 if flags.plus
-    capacity += 1 if flags.minus
-    capacity += 1 if flags.zero
-    capacity += 1 if flags.space
-
-    format_buf = format_buf(capacity)
-    original_format_buf = format_buf
-
-    io = IO::Memory.new(Bytes.new(format_buf, capacity))
-    io << '%'
-    io << '#' if flags.sharp
-    io << '+' if flags.plus
-    io << '-' if flags.minus
-    io << '0' if flags.zero
-    io << ' ' if flags.space
-    io << flags.width if flags.width > 0
-    if precision = flags.precision
-      io << '.'
-      io << precision if precision != 0
+      original_format_buf
     end
-    io << flags.type
-    io.write_byte 0_u8
 
-    original_format_buf
-  end
+    # We reuse a temporary buffer for snprintf
+    private def temp_buf(len)
+      temp_buf = @temp_buf
+      if temp_buf
+        if len > @temp_buf_len
+          @temp_buf_len = len
+          @temp_buf = temp_buf = temp_buf.realloc(len)
+        end
+        temp_buf
+      else
+        @temp_buf = Pointer(UInt8).malloc(len)
+      end
+    end
+
+    # We reuse a temporary buffer for the float format string
+    private def format_buf(len)
+      format_buf = @format_buf
+      if format_buf
+        if len > @format_buf_len
+          @format_buf_len = len
+          @format_buf = format_buf = format_buf.realloc(len)
+        end
+        format_buf
+      else
+        @format_buf = Pointer(UInt8).malloc(len)
+      end
+    end
+  {% end %} # HAS_RYU_PRINTF
 
   def pad(consumed, flags) : Nil
     padding_char = flags.padding_char
@@ -586,48 +632,23 @@ struct String::Formatter(A)
     @reader.next_char
   end
 
-  # We reuse a temporary buffer for snprintf
-  private def temp_buf(len)
-    temp_buf = @temp_buf
-    if temp_buf
-      if len > @temp_buf_len
-        @temp_buf_len = len
-        @temp_buf = temp_buf = temp_buf.realloc(len)
-      end
-      temp_buf
-    else
-      @temp_buf = Pointer(UInt8).malloc(len)
-    end
-  end
-
-  # We reuse a temporary buffer for the float format string
-  private def format_buf(len)
-    format_buf = @format_buf
-    if format_buf
-      if len > @format_buf_len
-        @format_buf_len = len
-        @format_buf = format_buf = format_buf.realloc(len)
-      end
-      format_buf
-    else
-      @format_buf = Pointer(UInt8).malloc(len)
-    end
-  end
-
   struct Flags
     property space : Bool, sharp : Bool, plus : Bool, minus : Bool, zero : Bool, float : Bool, base : Int32
-    property width : Int32, width_size : Int32
-    property type : Char, precision : Int32?, precision_size : Int32
+    property width : Int32
+    property type : Char, precision : Int32?
     property index : Int32?
 
+    {% unless HAS_RYU_PRINTF %}
+      property width_size : Int32 = 0
+      property precision_size : Int32 = 0
+    {% end %}
+
     def initialize
       @space = @sharp = @plus = @minus = @zero = @float = false
       @width = 0
-      @width_size = 0
       @base = 10
       @type = ' '
       @precision = nil
-      @precision_size = 0
     end
 
     def left_padding? : Bool

From e00a0a4f3788a8f5d85484bc22e7f9930b870b2b Mon Sep 17 00:00:00 2001
From: Caspian Baska <email@caspian.computer>
Date: Mon, 25 Dec 2023 03:29:35 +1100
Subject: [PATCH 012/105] Add `Enumerable(T)#to_a(& : T -> U) forall U`
 (#12653)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Johannes Müller <straightshoota@gmail.com>
---
 spec/std/enumerable_spec.cr      | 10 ++++++++++
 src/enumerable.cr                | 15 ++++++++++++---
 src/hash.cr                      | 18 ++++++++++++++++--
 src/indexable.cr                 | 10 +++++-----
 src/llvm/parameter_collection.cr |  2 +-
 src/named_tuple.cr               | 15 ++++++++++++++-
 src/set.cr                       | 13 +++++++++++++
 src/tuple.cr                     | 22 ++++++++++++++++++++--
 8 files changed, 91 insertions(+), 14 deletions(-)

diff --git a/spec/std/enumerable_spec.cr b/spec/std/enumerable_spec.cr
index 04d46c7976a3..0bcbac725cb5 100644
--- a/spec/std/enumerable_spec.cr
+++ b/spec/std/enumerable_spec.cr
@@ -131,6 +131,16 @@ describe "Enumerable" do
     end
   end
 
+  describe "to_a" do
+    context "with a block" do
+      SpecEnumerable.new.to_a { |e| e*2 }.should eq [2, 4, 6]
+    end
+
+    context "without a block" do
+      SpecEnumerable.new.to_a.should eq [1, 2, 3]
+    end
+  end
+
   describe "#to_set" do
     context "without block" do
       it "creates a Set from the unique elements of the collection" do
diff --git a/src/enumerable.cr b/src/enumerable.cr
index c7b566e647e4..6b24c833f44f 100644
--- a/src/enumerable.cr
+++ b/src/enumerable.cr
@@ -1997,9 +1997,18 @@ module Enumerable(T)
   # ```
   # (1..5).to_a # => [1, 2, 3, 4, 5]
   # ```
-  def to_a
-    ary = [] of T
-    each { |e| ary << e }
+  def to_a : Array(T)
+    to_a(&.itself)
+  end
+
+  # Returns an `Array` with the results of running *block* against each element of the collection.
+  #
+  # ```
+  # (1..5).to_a { |i| i * 2 } # => [2, 4, 6, 8, 10]
+  # ```
+  def to_a(& : T -> U) : Array(U) forall U
+    ary = [] of U
+    each { |e| ary << yield e }
     ary
   end
 
diff --git a/src/hash.cr b/src/hash.cr
index 8d8ccea22a0b..082f2a0a80e0 100644
--- a/src/hash.cr
+++ b/src/hash.cr
@@ -2055,16 +2055,30 @@ class Hash(K, V)
     pp.text "{...}" unless executed
   end
 
-  # Returns an array of tuples with key and values belonging to this Hash.
+  # Returns an `Array` of `Tuple(K, V)` with key and values belonging to this Hash.
   #
   # ```
   # h = {1 => 'a', 2 => 'b', 3 => 'c'}
   # h.to_a # => [{1, 'a'}, {2, 'b'}, {3, 'c'}]
   # ```
+  #
   # The order of the array follows the order the keys were inserted in the Hash.
   def to_a : Array({K, V})
+    to_a(&.itself)
+  end
+
+  # Returns an `Array` with the results of running *block* against tuples with key and values
+  # belonging to this Hash.
+  #
+  # ```
+  # h = {"first_name" => "foo", "last_name" => "bar"}
+  # h.to_a { |_k, v| v.capitalize } # => ["Foo", "Bar"]
+  # ```
+  #
+  # The order of the array follows the order the keys were inserted in the Hash.
+  def to_a(&block : {K, V} -> U) : Array(U) forall U
     to_a_impl do |entry|
-      {entry.key, entry.value}
+      yield ({entry.key, entry.value})
     end
   end
 
diff --git a/src/indexable.cr b/src/indexable.cr
index 3725c1552e38..7496a95e0df0 100644
--- a/src/indexable.cr
+++ b/src/indexable.cr
@@ -693,14 +693,14 @@ module Indexable(T)
     end
   end
 
-  # Returns an `Array` with all the elements in the collection.
+  # Returns an `Array` with the results of running *block* against each element of the collection.
   #
   # ```
-  # {1, 2, 3}.to_a # => [1, 2, 3]
+  # {1, 2, 3}.to_a { |i| i * 2 } # => [2, 4, 6]
   # ```
-  def to_a : Array(T)
-    ary = Array(T).new(size)
-    each { |e| ary << e }
+  def to_a(& : T -> U) : Array(U) forall U
+    ary = Array(U).new(size)
+    each { |e| ary << yield e }
     ary
   end
 
diff --git a/src/llvm/parameter_collection.cr b/src/llvm/parameter_collection.cr
index 937d9ec2edcc..dd9a7eae91d7 100644
--- a/src/llvm/parameter_collection.cr
+++ b/src/llvm/parameter_collection.cr
@@ -8,7 +8,7 @@ struct LLVM::ParameterCollection
     LibLLVM.get_count_params(@function).to_i
   end
 
-  def to_a
+  def to_a : Array(LLVM::Value)
     param_size = size()
     Array(LLVM::Value).build(param_size) do |buffer|
       LibLLVM.get_params(@function, buffer.as(LibLLVM::ValueRef*))
diff --git a/src/named_tuple.cr b/src/named_tuple.cr
index 7cceb568a260..4ea9df02fd20 100644
--- a/src/named_tuple.cr
+++ b/src/named_tuple.cr
@@ -588,12 +588,25 @@ struct NamedTuple
   #
   # NOTE: `to_a` on an empty named tuple produces an `Array(Tuple(Symbol, NoReturn))`
   def to_a
+    to_a(&.itself)
+  end
+
+  # Returns an `Array` with the results of running *block* against tuples with key and values belonging
+  # to this `NamedTuple`.
+  #
+  # ```
+  # tuple = {first_name: "foo", last_name: "bar"}
+  # tuple.to_a(&.last.capitalize) # => ["Foo", "Bar"]
+  # ```
+  #
+  # NOTE: `to_a` on an empty named tuple produces an `Array(Tuple(Symbol, NoReturn))`
+  def to_a(&)
     {% if T.size == 0 %}
       [] of {Symbol, NoReturn}
     {% else %}
       [
         {% for key in T %}
-          { {{key.symbolize}}, self[{{key.symbolize}}] },
+          yield({ {{key.symbolize}}, self[{{key.symbolize}}] }),
         {% end %}
       ]
     {% end %}
diff --git a/src/set.cr b/src/set.cr
index 091352302c7d..40425e9aa032 100644
--- a/src/set.cr
+++ b/src/set.cr
@@ -382,6 +382,19 @@ struct Set(T)
     @hash.keys
   end
 
+  # Returns an `Array` with the results of running *block* against each element of the collection.
+  #
+  # ```
+  # Set{1, 2, 3, 4, 5}.to_a { |i| i // 2 } # => [0, 1, 2]
+  # ```
+  def to_a(& : T -> U) : Array(U) forall U
+    array = Array(U).new(size)
+    @hash.each_key do |key|
+      array << key
+    end
+    array
+  end
+
   # Alias of `#to_s`.
   def inspect(io : IO) : Nil
     to_s(io)
diff --git a/src/tuple.cr b/src/tuple.cr
index d67578271363..2f9cde352e4f 100644
--- a/src/tuple.cr
+++ b/src/tuple.cr
@@ -539,10 +539,28 @@ struct Tuple
     to_s
   end
 
-  def to_a
+  # Returns an `Array` with all the elements in the tuple.
+  #
+  # ```
+  # {1, 2, 3, 4, 5}.to_a # => [1, 2, 3, 4, 5]
+  # ```
+  def to_a : Array(Union(*T))
+    {% if compare_versions(Crystal::VERSION, "1.1.0") < 0 %}
+      to_a(&.itself.as(Union(*T)))
+    {% else %}
+      to_a(&.itself)
+    {% end %}
+  end
+
+  # Returns an `Array` with the results of running *block* against each element of the tuple.
+  #
+  # ```
+  # {1, 2, 3, 4, 5}).to_a { |i| i * 2 } # => [2, 4, 6, 8, 10]
+  # ```
+  def to_a(& : Union(*T) -> _)
     Array(Union(*T)).build(size) do |buffer|
       {% for i in 0...T.size %}
-        buffer[{{i}}] = self[{{i}}]
+        buffer[{{i}}] = yield self[{{i}}]
       {% end %}
       size
     end

From d1863053d82fa3a570fdf72eaccbc2d8d676876b Mon Sep 17 00:00:00 2001
From: syeopite <70992037+syeopite@users.noreply.github.com>
Date: Sat, 30 Dec 2023 12:58:43 +0000
Subject: [PATCH 013/105] Add docs and explicit type restriction for indent
 parameter of JSON.build (#14140)

---
 src/json/builder.cr | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/json/builder.cr b/src/json/builder.cr
index 9bc074f7c6ef..c1dc2c39c8e8 100644
--- a/src/json/builder.cr
+++ b/src/json/builder.cr
@@ -430,7 +430,10 @@ module JSON
   # end
   # string # => %<{"name":"foo","values":[1,2,3]}>
   # ```
-  def self.build(indent = nil, &)
+  #
+  # Accepts an indent parameter which can either be an `Int` (number of spaces to indent)
+  # or a `String`, which will prefix each level with the string a corresponding amount of times.
+  def self.build(indent : String | Int | Nil = nil, &)
     String.build do |str|
       build(str, indent) do |json|
         yield json
@@ -439,7 +442,7 @@ module JSON
   end
 
   # Writes JSON into the given `IO`. A `JSON::Builder` is yielded to the block.
-  def self.build(io : IO, indent = nil, &) : Nil
+  def self.build(io : IO, indent : String | Int | Nil = nil, &) : Nil
     builder = JSON::Builder.new(io)
     builder.indent = indent if indent
     builder.document do

From 6e1c631fe24062c5288423b87c79752c07ae3b5b Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 30 Dec 2023 20:59:03 +0800
Subject: [PATCH 014/105] Do not use `pointerof(Path)` in the standard library
 (#14144)

---
 src/crystal/system/win32/path.cr | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/crystal/system/win32/path.cr b/src/crystal/system/win32/path.cr
index a5e60db82576..06f9346a2bae 100644
--- a/src/crystal/system/win32/path.cr
+++ b/src/crystal/system/win32/path.cr
@@ -6,12 +6,16 @@ module Crystal::System::Path
   def self.home : String
     if home_path = ENV["USERPROFILE"]?.presence
       home_path
-    elsif LibC.SHGetKnownFolderPath(pointerof(LibC::FOLDERID_Profile), 0, nil, out path_ptr) == 0
-      home_path, _ = String.from_utf16(path_ptr)
-      LibC.CoTaskMemFree(path_ptr)
-      home_path
     else
-      raise RuntimeError.from_winerror("SHGetKnownFolderPath")
+      # TODO: interpreter doesn't implement pointerof(Path)` yet
+      folderid = LibC::FOLDERID_Profile
+      if LibC.SHGetKnownFolderPath(pointerof(folderid), 0, nil, out path_ptr) == 0
+        home_path, _ = String.from_utf16(path_ptr)
+        LibC.CoTaskMemFree(path_ptr)
+        home_path
+      else
+        raise RuntimeError.from_winerror("SHGetKnownFolderPath")
+      end
     end
   end
 end

From 24d2c57ea2f61e51dfa6093e24ce13ec9636949c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Sat, 30 Dec 2023 13:59:47 +0100
Subject: [PATCH 015/105] Update distribution-scripts (#14136)

---
 .circleci/config.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 957f3979b110..39ae49d81ee3 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -8,7 +8,7 @@ parameters:
   distribution-scripts-version:
     description: "Git ref for version of https://github.com/crystal-lang/distribution-scripts/"
     type: string
-    default: "e15cbd3b6b3e1bac1b16905f1b1a15ba6ae4e554"
+    default: "535aedb8b09d77caaa1583700f371cd04343b7e8"
   previous_crystal_base_url:
     description: "Prefix for URLs to Crystal bootstrap compiler"
     type: string

From f39413637e4ae805f6ce6b95474deec243589a87 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sun, 31 Dec 2023 12:08:03 +0100
Subject: [PATCH 016/105] Update GH Actions to v4 (#14120)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 .github/workflows/aarch64.yml            | 12 ++++++------
 .github/workflows/interpreter.yml        |  4 ++--
 .github/workflows/win.yml                |  6 +++---
 .github/workflows/win_build_portable.yml |  2 +-
 4 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/.github/workflows/aarch64.yml b/.github/workflows/aarch64.yml
index 2671fe5d61d6..da252904fa37 100644
--- a/.github/workflows/aarch64.yml
+++ b/.github/workflows/aarch64.yml
@@ -18,7 +18,7 @@ jobs:
         with:
           args: make crystal
       - name: Upload Crystal executable
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: crystal-aarch64-musl
           path: |
@@ -32,7 +32,7 @@ jobs:
       - name: Download Crystal source
         uses: actions/checkout@v4
       - name: Download Crystal executable
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: crystal-aarch64-musl
       - name: Mark downloaded compiler as executable
@@ -49,7 +49,7 @@ jobs:
       - name: Download Crystal source
         uses: actions/checkout@v4
       - name: Download Crystal executable
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: crystal-aarch64-musl
       - name: Mark downloaded compiler as executable
@@ -69,7 +69,7 @@ jobs:
         with:
           args: make crystal
       - name: Upload Crystal executable
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: crystal-aarch64-gnu
           path: |
@@ -83,7 +83,7 @@ jobs:
       - name: Download Crystal source
         uses: actions/checkout@v4
       - name: Download Crystal executable
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: crystal-aarch64-gnu
       - name: Mark downloaded compiler as executable
@@ -100,7 +100,7 @@ jobs:
       - name: Download Crystal source
         uses: actions/checkout@v4
       - name: Download Crystal executable
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: crystal-aarch64-gnu
       - name: Mark downloaded compiler as executable
diff --git a/.github/workflows/interpreter.yml b/.github/workflows/interpreter.yml
index a034a9f5b410..2cd37d4b6579 100644
--- a/.github/workflows/interpreter.yml
+++ b/.github/workflows/interpreter.yml
@@ -33,7 +33,7 @@ jobs:
         run: make interpreter=1 release=1
 
       - name: Upload compiler artifact
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: crystal-interpreter
           path: |
@@ -52,7 +52,7 @@ jobs:
       - uses: actions/checkout@v4
 
       - name: Download compiler artifact
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: crystal-interpreter
           path: .build/
diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml
index 90ed0e0c980d..da66d568835a 100644
--- a/.github/workflows/win.yml
+++ b/.github/workflows/win.yml
@@ -252,7 +252,7 @@ jobs:
         uses: actions/checkout@v4
 
       - name: Download Crystal executable
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: crystal
           path: build
@@ -303,7 +303,7 @@ jobs:
         uses: actions/checkout@v4
 
       - name: Download Crystal executable
-        uses: actions/download-artifact@v3
+        uses: actions/download-artifact@v4
         with:
           name: crystal-release
           path: etc/win-ci/portable
@@ -329,7 +329,7 @@ jobs:
           iscc.exe crystal.iss
 
       - name: Upload Crystal installer
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: crystal-installer
           path: etc/win-ci/Output/crystal-setup.exe
diff --git a/.github/workflows/win_build_portable.yml b/.github/workflows/win_build_portable.yml
index 21d849c2dcf0..6222aaee3055 100644
--- a/.github/workflows/win_build_portable.yml
+++ b/.github/workflows/win_build_portable.yml
@@ -144,7 +144,7 @@ jobs:
           cp README.md crystal/
 
       - name: Upload Crystal binaries
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: ${{ inputs.release && 'crystal-release' || 'crystal' }}
           path: crystal

From 6d177399d437bc6cbafa9305dd69a22a8e74e559 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sun, 31 Dec 2023 19:08:24 +0800
Subject: [PATCH 017/105] Fix interpreter specs on Windows (#14145)

---
 spec/compiler/interpreter/lib_spec.cr       | 24 +++++++++++++++++----
 spec/compiler/interpreter/spec_helper.cr    |  1 +
 src/compiler/crystal/interpreter/context.cr |  5 +++++
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/spec/compiler/interpreter/lib_spec.cr b/spec/compiler/interpreter/lib_spec.cr
index 98e1da7fd294..2c1798645645 100644
--- a/spec/compiler/interpreter/lib_spec.cr
+++ b/spec/compiler/interpreter/lib_spec.cr
@@ -2,6 +2,22 @@
 require "./spec_helper"
 require "../loader/spec_helper"
 
+private def ldflags
+  {% if flag?(:win32) %}
+    "/LIBPATH:#{SPEC_CRYSTAL_LOADER_LIB_PATH} sum.lib"
+  {% else %}
+    "-L#{SPEC_CRYSTAL_LOADER_LIB_PATH} -lsum"
+  {% end %}
+end
+
+private def ldflags_with_backtick
+  {% if flag?(:win32) %}
+    "/LIBPATH:#{SPEC_CRYSTAL_LOADER_LIB_PATH} `powershell.exe -C Write-Host -NoNewline sum.lib`"
+  {% else %}
+    "-L#{SPEC_CRYSTAL_LOADER_LIB_PATH} -l`echo sum`"
+  {% end %}
+end
+
 describe Crystal::Repl::Interpreter do
   context "variadic calls" do
     before_all do
@@ -11,7 +27,7 @@ describe Crystal::Repl::Interpreter do
 
     it "promotes float" do
       interpret(<<-CRYSTAL).should eq 3.5
-        @[Link(ldflags: "-L#{SPEC_CRYSTAL_LOADER_LIB_PATH} -lsum")]
+        @[Link(ldflags: #{ldflags.inspect})]
         lib LibSum
           fun sum_float(count : Int32, ...) : Float32
         end
@@ -22,7 +38,7 @@ describe Crystal::Repl::Interpreter do
 
     it "promotes int" do
       interpret(<<-CRYSTAL).should eq 5
-        @[Link(ldflags: "-L#{SPEC_CRYSTAL_LOADER_LIB_PATH} -lsum")]
+        @[Link(ldflags: #{ldflags.inspect})]
         lib LibSum
           fun sum_int(count : Int32, ...) : Int32
         end
@@ -33,7 +49,7 @@ describe Crystal::Repl::Interpreter do
 
     it "promotes enum" do
       interpret(<<-CRYSTAL).should eq 5
-        @[Link(ldflags: "-L#{SPEC_CRYSTAL_LOADER_LIB_PATH} -lsum")]
+        @[Link(ldflags: #{ldflags.inspect})]
         lib LibSum
           fun sum_int(count : Int32, ...) : Int32
         end
@@ -63,7 +79,7 @@ describe Crystal::Repl::Interpreter do
 
     it "expands ldflags" do
       interpret(<<-CRYSTAL).should eq 4
-        @[Link(ldflags: "-L#{SPEC_CRYSTAL_LOADER_LIB_PATH} -l`echo sum`")]
+        @[Link(ldflags: #{ldflags_with_backtick.inspect})]
         lib LibSum
           fun simple_sum_int(a : Int32, b : Int32) : Int32
         end
diff --git a/spec/compiler/interpreter/spec_helper.cr b/spec/compiler/interpreter/spec_helper.cr
index c3b0dcaca8cd..e6aeb240674c 100644
--- a/spec/compiler/interpreter/spec_helper.cr
+++ b/spec/compiler/interpreter/spec_helper.cr
@@ -5,6 +5,7 @@ require "compiler/crystal/interpreter/*"
 def interpret(code, *, prelude = "primitives", file = __FILE__, line = __LINE__)
   if prelude == "primitives"
     context, value = interpret_with_context(code)
+    context.loader?.try &.close_all
     value.value
   else
     interpret_in_separate_process(code, prelude, file: file, line: line)
diff --git a/src/compiler/crystal/interpreter/context.cr b/src/compiler/crystal/interpreter/context.cr
index f4a4444e105c..94456b4cec0e 100644
--- a/src/compiler/crystal/interpreter/context.cr
+++ b/src/compiler/crystal/interpreter/context.cr
@@ -46,6 +46,9 @@ class Crystal::Repl::Context
 
   def initialize(@program : Program)
     @program.flags << "interpreted"
+    {% if flag?(:win32) %}
+      @program.flags << "preview_dll"
+    {% end %}
 
     @gc_references = [] of Void*
 
@@ -392,6 +395,8 @@ class Crystal::Repl::Context
     @id_to_type[id]
   end
 
+  getter? loader : Loader?
+
   getter(loader : Loader) {
     lib_flags = program.lib_flags
     # Execute and expand `subcommands`.

From 866d51d42bdd25839b0c0010fb96948fd795c2d9 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sun, 31 Dec 2023 19:08:33 +0800
Subject: [PATCH 018/105] Support `-dynamic.lib` in Windows interpreter
 (#14143)

---
 spec/compiler/loader/msvc_spec.cr   | 26 ++++++++++++++++++++++++++
 spec/compiler/loader/spec_helper.cr |  4 ++--
 src/compiler/crystal/loader/msvc.cr | 11 ++++++++---
 3 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/spec/compiler/loader/msvc_spec.cr b/spec/compiler/loader/msvc_spec.cr
index fedb21c352c4..5893d29aee02 100644
--- a/spec/compiler/loader/msvc_spec.cr
+++ b/spec/compiler/loader/msvc_spec.cr
@@ -125,4 +125,30 @@ describe Crystal::Loader do
       end
     end
   end
+
+  describe "lib suffix" do
+    before_all do
+      FileUtils.mkdir_p(SPEC_CRYSTAL_LOADER_LIB_PATH)
+    end
+
+    after_all do
+      FileUtils.rm_rf(SPEC_CRYSTAL_LOADER_LIB_PATH)
+    end
+
+    it "respects -dynamic" do
+      build_c_dynlib(compiler_datapath("loader", "foo.c"), lib_name: "foo-dynamic")
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+      loader.load_library?("foo").should be_true
+    ensure
+      loader.close_all if loader
+    end
+
+    it "ignores -static" do
+      build_c_dynlib(compiler_datapath("loader", "foo.c"), lib_name: "bar-static")
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+      loader.load_library?("bar").should be_false
+    ensure
+      loader.close_all if loader
+    end
+  end
 end
diff --git a/spec/compiler/loader/spec_helper.cr b/spec/compiler/loader/spec_helper.cr
index 282af7871f81..0db69dc19752 100644
--- a/spec/compiler/loader/spec_helper.cr
+++ b/spec/compiler/loader/spec_helper.cr
@@ -2,8 +2,8 @@ require "spec"
 
 SPEC_CRYSTAL_LOADER_LIB_PATH = File.join(SPEC_TEMPFILE_PATH, "loader")
 
-def build_c_dynlib(c_filename, target_dir = SPEC_CRYSTAL_LOADER_LIB_PATH)
-  o_filename = File.join(target_dir, Crystal::Loader.library_filename(File.basename(c_filename, ".c")))
+def build_c_dynlib(c_filename, *, lib_name = nil, target_dir = SPEC_CRYSTAL_LOADER_LIB_PATH)
+  o_filename = File.join(target_dir, Crystal::Loader.library_filename(lib_name || File.basename(c_filename, ".c")))
 
   {% if flag?(:msvc) %}
     o_basename = o_filename.rchop(".lib")
diff --git a/src/compiler/crystal/loader/msvc.cr b/src/compiler/crystal/loader/msvc.cr
index bf0b5c74a36f..d4b899db0e87 100644
--- a/src/compiler/crystal/loader/msvc.cr
+++ b/src/compiler/crystal/loader/msvc.cr
@@ -60,7 +60,7 @@ class Crystal::Loader
     result
   end
 
-  private def self.search_library(libname, search_paths, extra_suffix)
+  protected def self.search_library(libname, search_paths, extra_suffix)
     if ::Path::SEPARATORS.any? { |separator| libname.includes?(separator) }
       libname = File.expand_path(libname)
       library_path = library_filename(libname)
@@ -106,7 +106,7 @@ class Crystal::Loader
   end
 
   def self.library_filename(libname : String) : String
-    "#{libname}.lib"
+    "#{libname.rchop(".lib")}.lib"
   end
 
   def find_symbol?(name : String) : Handle?
@@ -149,8 +149,13 @@ class Crystal::Loader
     load_library?(libname) || raise LoadError.from_winerror "cannot find #{Loader.library_filename(libname)}"
   end
 
+  def load_library?(libname : String) : Bool
+    library_path = Loader.search_library(libname, @search_paths, "-dynamic")
+    !library_path.nil? && load_file?(library_path)
+  end
+
   private def open_library(path : String)
-    # TODO: respect Crystal::LIBRARY_RPATH (#13490)
+    # TODO: respect Crystal::LIBRARY_RPATH (#13490), or `@[Link(dll:)]`'s search order
     LibC.LoadLibraryExW(System.to_wstr(path), nil, 0)
   end
 

From 4b5ef59994ed776e46fdfc23e16f1aa885632f67 Mon Sep 17 00:00:00 2001
From: George Dietrich <george@dietrich.app>
Date: Mon, 1 Jan 2024 09:53:39 -0500
Subject: [PATCH 019/105] Add reference to book how merging macro expansion and
 call docs (#14139)

---
 src/compiler/crystal/macros.cr | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr
index 983af69ae4b7..90c802bad25e 100644
--- a/src/compiler/crystal/macros.cr
+++ b/src/compiler/crystal/macros.cr
@@ -442,6 +442,8 @@ module Crystal::Macros
     # Returns a `MacroId` that contains the documentation comments attached to this node, or an empty `MacroId` if there are none.
     # Each line is prefixed with a `#` character to allow the output to be used directly within another node's documentation comment.
     #
+    # A common use case is combining this method with the `@caller` macro instance variable in order to allow [merging macro expansion and call comments](https://crystal-lang.org/reference/syntax_and_semantics/macros/index.html#merging-expansion-and-call-comments).
+    #
     # WARNING: The return value will be empty when executed outside of the `crystal docs` command.
     def doc_comment : MacroId
     end

From 6bfc90dfaf5a3f36926b0c4d139691216fd843cf Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Mon, 1 Jan 2024 22:53:46 +0800
Subject: [PATCH 020/105] Support absolute paths in
 `CRYSTAL_INTERPRETER_LOADER_INFO` (#14147)

---
 src/compiler/crystal/interpreter/context.cr | 12 ++++--------
 src/compiler/crystal/loader/msvc.cr         | 16 +++++++++++++++-
 src/compiler/crystal/loader/unix.cr         |  1 +
 3 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/compiler/crystal/interpreter/context.cr b/src/compiler/crystal/interpreter/context.cr
index 94456b4cec0e..d597810b36de 100644
--- a/src/compiler/crystal/interpreter/context.cr
+++ b/src/compiler/crystal/interpreter/context.cr
@@ -410,13 +410,6 @@ class Crystal::Repl::Context
     args.delete("-lgc")
 
     Crystal::Loader.parse(args).tap do |loader|
-      if ENV["CRYSTAL_INTERPRETER_LOADER_INFO"]?.presence
-        STDERR.puts "Crystal::Loader loaded libraries:"
-        loader.loaded_libraries.each do |path|
-          STDERR.puts "      #{path}"
-        end
-      end
-
       # FIXME: Part 2: This is a workaround for initial integration of the interpreter:
       # We append a handle to the current executable (i.e. the compiler program)
       # to the loader's handle list. This gives the loader access to all the symbols in the compiler program,
@@ -426,7 +419,10 @@ class Crystal::Repl::Context
       loader.load_current_program_handle
 
       if ENV["CRYSTAL_INTERPRETER_LOADER_INFO"]?.presence
-        STDERR.puts "      current program handle"
+        STDERR.puts "Crystal::Loader loaded libraries:"
+        loader.loaded_libraries.each do |path|
+          STDERR.puts "      #{path}"
+        end
       end
     end
   }
diff --git a/src/compiler/crystal/loader/msvc.cr b/src/compiler/crystal/loader/msvc.cr
index d4b899db0e87..e9fdc9af5bbd 100644
--- a/src/compiler/crystal/loader/msvc.cr
+++ b/src/compiler/crystal/loader/msvc.cr
@@ -139,7 +139,7 @@ class Crystal::Loader
       return false unless handle
 
       @handles << handle
-      @loaded_libraries << dll
+      @loaded_libraries << (module_filename(handle) || dll)
     end
 
     true
@@ -162,6 +162,7 @@ class Crystal::Loader
   def load_current_program_handle
     if LibC.GetModuleHandleExW(0, nil, out hmodule) != 0
       @handles << hmodule
+      @loaded_libraries << (Process.executable_path || "current program handle")
     end
   end
 
@@ -172,6 +173,19 @@ class Crystal::Loader
     @handles.clear
   end
 
+  private def module_filename(handle)
+    Crystal::System.retry_wstr_buffer do |buffer, small_buf|
+      len = LibC.GetModuleFileNameW(handle, buffer, buffer.size)
+      if 0 < len < buffer.size
+        break String.from_utf16(buffer[0, len])
+      elsif small_buf && len == buffer.size
+        next 32767 # big enough. 32767 is the maximum total path length of UNC path.
+      else
+        break nil
+      end
+    end
+  end
+
   # Returns a list of directories used as the default search paths.
   #
   # For MSVC this is simply the contents of the `LIB` environment variable,
diff --git a/src/compiler/crystal/loader/unix.cr b/src/compiler/crystal/loader/unix.cr
index 4c202231d7e6..39fef6e0c318 100644
--- a/src/compiler/crystal/loader/unix.cr
+++ b/src/compiler/crystal/loader/unix.cr
@@ -120,6 +120,7 @@ class Crystal::Loader
   def load_current_program_handle
     if program_handle = LibC.dlopen(nil, LibC::RTLD_LAZY | LibC::RTLD_GLOBAL)
       @handles << program_handle
+      @loaded_libraries << (Process.executable_path || "current program handle")
     end
   end
 

From f3de7b43714e8ff771fcf838ed6accc27c21da55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Mon, 1 Jan 2024 20:52:06 +0100
Subject: [PATCH 021/105] Merge `samples/.gitignore` into `.gitignore` (#14134)

---
 .gitignore         | 1 +
 Makefile           | 1 -
 Makefile.win       | 1 -
 samples/.gitignore | 1 -
 4 files changed, 1 insertion(+), 3 deletions(-)
 delete mode 100644 samples/.gitignore

diff --git a/.gitignore b/.gitignore
index 5d74450c533f..987e8a649620 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 
 # Build artifacts
 /.build/
+/samples/.build/
 /docs/
 /src/llvm/ext/llvm_ext.o
 /src/llvm/ext/llvm_ext.obj
diff --git a/Makefile b/Makefile
index 7e8070d16921..4682c7aebec9 100644
--- a/Makefile
+++ b/Makefile
@@ -182,7 +182,6 @@ install_docs: docs ## Install docs at DESTDIR
 
 	cp -av docs "$(DATADIR)/docs"
 	cp -av samples "$(DATADIR)/examples"
-	rm -rf "$(DATADIR)/examples/.gitignore"
 
 .PHONY: uninstall_docs
 uninstall_docs: ## Uninstall docs from DESTDIR
diff --git a/Makefile.win b/Makefile.win
index e2b18741657e..da1d9fc8328a 100644
--- a/Makefile.win
+++ b/Makefile.win
@@ -171,7 +171,6 @@ install_docs: docs ## Install docs at prefix
 	$(call MKDIR,"$(DATADIR)")
 	$(call INSTALLDIR,docs,"$(DATADIR)\docs")
 	$(call INSTALLDIR,samples,"$(DATADIR)\examples")
-	$(call RM,"$(DATADIR)\examples\.gitignore")
 
 .PHONY: uninstall_docs
 uninstall_docs: ## Uninstall docs from prefix
diff --git a/samples/.gitignore b/samples/.gitignore
deleted file mode 100644
index 0e03e15f2420..000000000000
--- a/samples/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/.build/

From d15435dc822be0b18a7ff2bf823a564d9ef5cc13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Mon, 1 Jan 2024 20:52:13 +0100
Subject: [PATCH 022/105] Fix `make clean` to remove zipped manpages (#14135)

---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 4682c7aebec9..2a7f9d43869f 100644
--- a/Makefile
+++ b/Makefile
@@ -229,6 +229,7 @@ man/%.gz: man/%
 .PHONY: clean
 clean: clean_crystal ## Clean up built directories and files
 	rm -rf $(LLVM_EXT_OBJ)
+	rm -rf man/*.gz
 
 .PHONY: clean_crystal
 clean_crystal: ## Clean up crystal built files

From 316422fb800826994c4623edb837f57b74f7a361 Mon Sep 17 00:00:00 2001
From: "Brian J. Cardiff" <bcardiff@gmail.com>
Date: Tue, 2 Jan 2024 10:34:25 -0300
Subject: [PATCH 023/105] Add Crystal::Repl#parse_and_interpret (#14138)

* Add Crystal::Repl#parse_and_interpret

* Use single EvalResult type

* skip if without_interpreter
---
 spec/compiler/crystal/tools/repl_spec.cr | 20 ++++++++++++++++++++
 src/compiler/crystal/interpreter/repl.cr | 24 +++++++++++++++++-------
 2 files changed, 37 insertions(+), 7 deletions(-)
 create mode 100644 spec/compiler/crystal/tools/repl_spec.cr

diff --git a/spec/compiler/crystal/tools/repl_spec.cr b/spec/compiler/crystal/tools/repl_spec.cr
new file mode 100644
index 000000000000..3a1e1275ef12
--- /dev/null
+++ b/spec/compiler/crystal/tools/repl_spec.cr
@@ -0,0 +1,20 @@
+{% skip_file if flag?(:without_interpreter) %}
+
+require "../../../spec_helper"
+
+private def success_value(result : Crystal::Repl::EvalResult) : Crystal::Repl::Value
+  result.warnings.infos.should be_empty
+  result.value.should_not be_nil
+end
+
+describe Crystal::Repl do
+  it "can parse and evaluate snippets" do
+    repl = Crystal::Repl.new
+    repl.prelude = "primitives"
+    repl.load_prelude
+
+    success_value(repl.parse_and_interpret("1 + 2")).value.should eq(3)
+    success_value(repl.parse_and_interpret("def foo; 1 + 2; end")).value.should eq(nil)
+    success_value(repl.parse_and_interpret("foo")).value.should eq(3)
+  end
+end
diff --git a/src/compiler/crystal/interpreter/repl.cr b/src/compiler/crystal/interpreter/repl.cr
index 93b3a6cef65c..2c009a89e87d 100644
--- a/src/compiler/crystal/interpreter/repl.cr
+++ b/src/compiler/crystal/interpreter/repl.cr
@@ -22,15 +22,13 @@ class Crystal::Repl
       when "exit"
         break
       when .presence
-        parser = new_parser(expression)
-        parser.warnings.report(STDOUT)
+        result = parse_and_interpret(expression)
+        result.warnings.report(STDOUT)
 
-        node = parser.parse
-        next unless node
+        next unless result.value
 
-        value = interpret(node)
         print " => "
-        puts SyntaxHighlighter::Colorize.highlight!(value.to_s)
+        puts SyntaxHighlighter::Colorize.highlight!(result.value.to_s)
       end
     rescue ex : EscapingException
       print "Unhandled exception: "
@@ -44,6 +42,18 @@ class Crystal::Repl
     end
   end
 
+  record EvalResult, value : Value?, warnings : WarningCollection
+
+  def parse_and_interpret(expression : String) : EvalResult
+    parser = new_parser(expression)
+
+    node = parser.parse
+    return EvalResult.new(value: nil, warnings: parser.warnings) unless node
+
+    value = interpret(node)
+    return EvalResult.new(value: value, warnings: parser.warnings)
+  end
+
   def run_file(filename, argv)
     @interpreter.argv = argv
 
@@ -68,7 +78,7 @@ class Crystal::Repl
     interpret(exps)
   end
 
-  private def load_prelude
+  def load_prelude
     node = parse_prelude
 
     interpret_and_exit_on_error(node)

From 8be53a45193465b0aef87d1623eb9de736daa53f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 3 Jan 2024 11:07:39 +0100
Subject: [PATCH 024/105] Revert "Add compile time string interpolation for
 char/num/bool constants" (#14155)

---
 .../normalize/string_interpolation_spec.cr    | 39 -------------
 .../crystal/semantic/cleanup_transformer.cr   | 55 +++++++++++--------
 2 files changed, 31 insertions(+), 63 deletions(-)

diff --git a/spec/compiler/normalize/string_interpolation_spec.cr b/spec/compiler/normalize/string_interpolation_spec.cr
index 1347792170b0..f92e6c2a200f 100644
--- a/spec/compiler/normalize/string_interpolation_spec.cr
+++ b/spec/compiler/normalize/string_interpolation_spec.cr
@@ -52,43 +52,4 @@ describe "Normalize: string interpolation" do
     string = node.should be_a(StringLiteral)
     string.value.should eq("hello world")
   end
-
-  it "replaces char constant" do
-    result = semantic(%(
-      def String.interpolation(*args); ""; end
-
-      OBJ = 'l'
-
-      "hello wor\#{OBJ}d"
-    ))
-    node = result.node.as(Expressions).last
-    string = node.should be_a(StringLiteral)
-    string.value.should eq("hello world")
-  end
-
-  it "replaces number constant" do
-    result = semantic(%(
-      def String.interpolation(*args); ""; end
-
-      OBJ = 9_f32
-
-      "nine as a float: \#{OBJ}"
-    ))
-    node = result.node.as(Expressions).last
-    string = node.should be_a(StringLiteral)
-    string.value.should eq("nine as a float: 9.0")
-  end
-
-  it "replaces boolean constant" do
-    result = semantic(%(
-      def String.interpolation(*args); ""; end
-
-      OBJ = false
-
-      "boolean false: \#{OBJ}"
-    ))
-    node = result.node.as(Expressions).last
-    string = node.should be_a(StringLiteral)
-    string.value.should eq("boolean false: false")
-  end
 end
diff --git a/src/compiler/crystal/semantic/cleanup_transformer.cr b/src/compiler/crystal/semantic/cleanup_transformer.cr
index ad1b570f0cbd..bc3084429ed3 100644
--- a/src/compiler/crystal/semantic/cleanup_transformer.cr
+++ b/src/compiler/crystal/semantic/cleanup_transformer.cr
@@ -256,28 +256,35 @@ module Crystal
     end
 
     def transform(node : StringInterpolation)
-      string = node.expressions.join do |exp|
-        if !(transformed_piece = solve_string_interpolation_expression(exp)).nil?
-          # Valid piece, continue joining
-          next transformed_piece
-        elsif expanded = node.expanded
-          # Invalid piece, transform expansion and exit early
-          return expanded.transform(self)
-        else
-          # No expansion, return self
-          return node
-        end
+      # See if we can solve all the pieces to string literals.
+      # If that's the case, we can replace the entire interpolation
+      # with a single string literal.
+      pieces = node.expressions.dup
+      solve_string_interpolation_expressions(pieces)
+
+      if pieces.all?(StringLiteral)
+        string = pieces.join(&.as(StringLiteral).value)
+        string_literal = StringLiteral.new(string).at(node)
+        string_literal.type = @program.string
+        return string_literal
+      end
+
+      if expanded = node.expanded
+        return expanded.transform(self)
       end
-      string_literal = StringLiteral.new(string).at(node)
-      string_literal.type = @program.string
-      string_literal
+      node
     end
 
-    # Returns the solved piece for string interpolation, if it can find one.
-    # For example, this returns a String when given a StringLiteral.
-    private def solve_string_interpolation_expression(piece : ASTNode) : String | Char | Number::Primitive | Bool | Nil
-      # Check for ExpandableNode happens first in case any nodes below are
-      # updated to be ExpandableNodes themselves.
+    private def solve_string_interpolation_expressions(pieces : Array(ASTNode))
+      pieces.each_with_index do |piece, i|
+        replacement = solve_string_interpolation_expression(piece)
+        next unless replacement
+
+        pieces[i] = replacement
+      end
+    end
+
+    private def solve_string_interpolation_expression(piece : ASTNode) : StringLiteral?
       if piece.is_a?(ExpandableNode)
         if expanded = piece.expanded
           return solve_string_interpolation_expression(expanded)
@@ -287,13 +294,13 @@ module Crystal
       case piece
       when Path
         if target_const = piece.target_const
-          solve_string_interpolation_expression(target_const.value)
+          return solve_string_interpolation_expression(target_const.value)
         end
-      when StringLiteral then piece.value
-      when CharLiteral   then piece.value
-      when NumberLiteral then piece.to_number
-      when BoolLiteral   then piece.value
+      when StringLiteral
+        return piece
       end
+
+      nil
     end
 
     def transform(node : ExpandableNode)

From 382041cc25b025f74938b131ac0960012faeb60f Mon Sep 17 00:00:00 2001
From: Julien Portalier <julien@portalier.com>
Date: Wed, 3 Jan 2024 12:54:57 +0100
Subject: [PATCH 025/105] Fix: segfault with next boehm gc (after v8.2.4)
 (#14130)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Johannes Müller <straightshoota@gmail.com>
---
 src/gc/boehm.cr | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/src/gc/boehm.cr b/src/gc/boehm.cr
index 6c1ff5020cbf..8278f33b8e94 100644
--- a/src/gc/boehm.cr
+++ b/src/gc/boehm.cr
@@ -22,13 +22,17 @@
 {% if flag?(:freebsd) || flag?(:dragonfly) %}
   @[Link("gc-threaded")]
 {% else %}
-  @[Link("gc")]
+  @[Link("gc", pkg_config: "bdw-gc")]
 {% end %}
 
 {% if compare_versions(Crystal::VERSION, "1.11.0-dev") >= 0 %}
   @[Link(dll: "gc.dll")]
 {% end %}
 lib LibGC
+  {% unless flag?(:win32) %}
+    VERSION = {{ `pkg-config bdw-gc --silence-errors --modversion || printf "0.0.0"`.chomp.stringify }}
+  {% end %}
+
   alias Int = LibC::Int
   alias SizeT = LibC::SizeT
   {% if flag?(:win32) && flag?(:bits64) %}
@@ -96,7 +100,7 @@ lib LibGC
 
   fun push_all_eager = GC_push_all_eager(bottom : Void*, top : Void*)
 
-  {% if flag?(:preview_mt) || flag?(:win32) %}
+  {% if flag?(:preview_mt) || flag?(:win32) || compare_versions(VERSION, "8.2.0") >= 0 %}
     fun get_my_stackbottom = GC_get_my_stackbottom(sb : StackBase*) : ThreadHandle
     fun set_stackbottom = GC_set_stackbottom(th : ThreadHandle, sb : StackBase*) : ThreadHandle
   {% else %}
@@ -277,10 +281,11 @@ module GC
 
   # :nodoc:
   def self.current_thread_stack_bottom
-    {% if flag?(:preview_mt) || flag?(:win32) %}
+    {% if LibGC.has_method?(:get_my_stackbottom) %}
       th = LibGC.get_my_stackbottom(out sb)
       {th, sb.mem_base}
     {% else %}
+      # support for legacy gc releases
       {Pointer(Void).null, LibGC.stackbottom}
     {% end %}
   end
@@ -292,10 +297,11 @@ module GC
       sb.mem_base = stack_bottom
       LibGC.set_stackbottom(thread_handle, pointerof(sb))
     end
-  {% elsif flag?(:win32) %}
+  {% elsif LibGC.has_method?(:set_stackbottom) %}
     # this is necessary because Boehm GC does _not_ use `GC_stackbottom` on
-    # Windows when pushing all threads' stacks; instead `GC_set_stackbottom`
-    # must be used to associate the new bottom with the running thread
+    # Windows when pushing all threads' stacks; it also started crashing on
+    # Linux with libgc after v8.2.4; instead `GC_set_stackbottom` must be used
+    # to associate the new bottom with the running thread
     def self.set_stackbottom(stack_bottom : Void*)
       sb = LibGC::StackBase.new
       sb.mem_base = stack_bottom
@@ -303,6 +309,7 @@ module GC
       LibGC.set_stackbottom(nil, pointerof(sb))
     end
   {% else %}
+    # support for legacy gc releases
     def self.set_stackbottom(stack_bottom : Void*)
       LibGC.stackbottom = stack_bottom
     end

From 5e13683544b0a06aa41a41b5f6d22fd56b8d7bcf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 3 Jan 2024 12:55:21 +0100
Subject: [PATCH 026/105] Fix compiler error message for broken source file
 (#14157)

---
 src/compiler/crystal/command.cr | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr
index 69b4ab2d221c..97bf46feb663 100644
--- a/src/compiler/crystal/command.cr
+++ b/src/compiler/crystal/command.cr
@@ -627,6 +627,8 @@ class Crystal::Command
       filename = File.expand_path(filename)
       Compiler::Source.new(filename, File.read(filename))
     end
+  rescue exc : IO::Error
+    error exc
   end
 
   private def setup_simple_compiler_options(compiler, opts)

From 07c09cfae7fbe81bf9b6012de4b074c25c5bb686 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 3 Jan 2024 19:44:52 +0100
Subject: [PATCH 027/105] Add optimization levels to manpage (#14162)

---
 man/crystal.1 | 49 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 46 insertions(+), 3 deletions(-)

diff --git a/man/crystal.1 b/man/crystal.1
index 5f08ce29d07e..508b2ab44cb9 100644
--- a/man/crystal.1
+++ b/man/crystal.1
@@ -140,8 +140,14 @@ Don't do code generation, just parse the file.
 Specify filename of output.
 .It Fl -prelude
 Specify prelude to use. The default one initializes the garbage collector. You can also use --prelude=empty to use no preludes. This can be useful for checking code generation for a specific source code file.
+.It Fl O Ar LEVEL
+Optimization mode: 0 (default), 1, 2, 3. See
+.Sy OPTIMIZATIONS
+for details.
 .It Fl -release
-Turn on optimizations for the generated code, which are disabled by default.
+Compile in release mode. Equivalent to
+.Fl O3
+.Fl -single-module
 .It Fl -error-trace
 Show full stack trace. Disabled by default, as the full trace usually makes error messages less readable and not always deliver relevant information.
 .It Fl s, -stats
@@ -152,6 +158,9 @@ Print statistics about the progress for the current build.
 Print statistics about the execution time.
 .It Fl -single-module
 Generate a single LLVM module.
+By default, one LLVM module is created for each type in a program.
+.Fl -release
+implies this option.
 .It Fl -threads Ar NUM
 Maximum number of threads to use for code generation. The default is 8 threads.
 .It Fl -target Ar TRIPLE
@@ -265,8 +274,14 @@ Generate the output without any symbolic debug symbols.
 Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with --target-triple or the hosts default, if none is given.
 .It Fl -error-trace
 Show full error trace.
+.It Fl O Ar LEVEL
+Optimization mode: 0 (default), 1, 2, 3. See
+.Sy OPTIMIZATIONS
+for details.
 .It Fl -release
-Turn on optimizations for the generated code, which are disabled by default.
+Compile in release mode. Equivalent to
+.Fl O3
+.Fl -single-module
 .It Fl s, -stats
 Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process.
 .It Fl p, -progress
@@ -326,8 +341,14 @@ Generate the output without any symbolic debug symbols.
 Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with --target-triple or the hosts default, if none is given.
 .It Fl -error-trace
 Show full error trace.
+.It Fl O Ar LEVEL
+Optimization mode: 0 (default), 1, 2, 3. See
+.Sy OPTIMIZATIONS
+for details.
 .It Fl -release
-Turn on optimizations for the generated code, which are disabled by default.
+Compile in release mode. Equivalent to
+.Fl O3
+.Fl -single-module
 .It Fl s, -stats
 Print statistics about the different compiler stages for the current build. Output time and used memory for each compiler process.
 .It Fl p, -progress
@@ -410,6 +431,28 @@ Show help. Option --help or -h can also be added to each command for command-spe
 Show version.
 .El
 .
+.Sh OPTIMIZATIONS
+.Bl -tag -width "12345678" -compact
+.Pp
+The optimization level specifies the codegen effort for producing optimal code.
+It's a trade-off between compilation performance (decreasing per optimization level) and runtime performance (increasing per optimization level).
+.Pp
+Production builds should usually have the highest optimization level.
+Best results are achieved with
+.Fl -release
+ which also implies
+.Fl -single-module
+.Pp
+.It
+.It Fl O0
+No optimization (default)
+.It Fl O1
+Low optimization
+.It Fl O2
+Middle optimization
+.It Fl O3
+High optimization
+.
 .Sh ENVIRONMENT VARIABLES
 .Bl -tag -width "12345678" -compact
 .Pp

From 2afc7c1cda5295950e045bf00c665552eff3196c Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Thu, 4 Jan 2024 18:06:46 +0800
Subject: [PATCH 028/105] Fix codegen error when discarding `is_a?` or
 `responds_to?`'s result (#14148)

---
 spec/compiler/codegen/is_a_spec.cr        | 10 ++++++++++
 spec/compiler/codegen/responds_to_spec.cr | 12 ++++++++++++
 src/compiler/crystal/codegen/codegen.cr   | 11 +++++++----
 3 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/spec/compiler/codegen/is_a_spec.cr b/spec/compiler/codegen/is_a_spec.cr
index 97d72378be42..86ed570afe20 100644
--- a/spec/compiler/codegen/is_a_spec.cr
+++ b/spec/compiler/codegen/is_a_spec.cr
@@ -45,6 +45,16 @@ describe "Codegen: is_a?" do
     run("1.is_a?(Object)").to_b.should be_true
   end
 
+  it "doesn't error if result is discarded (#14113)" do
+    run(<<-CRYSTAL).to_i.should eq(1)
+      class Foo
+      end
+
+      (Foo.new || "").is_a?(Foo)
+      1
+      CRYSTAL
+  end
+
   it "evaluate method on filtered type" do
     run("a = 1; a = 'a'; if a.is_a?(Char); a.ord; else; 0; end").to_i.chr.should eq('a')
   end
diff --git a/spec/compiler/codegen/responds_to_spec.cr b/spec/compiler/codegen/responds_to_spec.cr
index e10f024f3682..0384c3e0d838 100644
--- a/spec/compiler/codegen/responds_to_spec.cr
+++ b/spec/compiler/codegen/responds_to_spec.cr
@@ -51,6 +51,18 @@ describe "Codegen: responds_to?" do
       )).to_b.should be_false
   end
 
+  it "doesn't error if result is discarded (#14113)" do
+    run(<<-CRYSTAL).to_i.should eq(1)
+      class Foo
+        def foo
+        end
+      end
+
+      (Foo.new || "").responds_to?(:foo)
+      1
+      CRYSTAL
+  end
+
   it "works with virtual type" do
     run(%(
       class Foo
diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr
index f5c35db9d65a..651afa44ca27 100644
--- a/src/compiler/crystal/codegen/codegen.cr
+++ b/src/compiler/crystal/codegen/codegen.cr
@@ -1471,12 +1471,15 @@ module Crystal
 
     def codegen_type_filter(node, &)
       accept node.obj
-      obj_type = node.obj.type
 
-      type_id = type_id @last, obj_type
-      filtered_type = yield(obj_type).not_nil!
+      if @needs_value
+        obj_type = node.obj.type
+
+        type_id = type_id @last, obj_type
+        filtered_type = yield(obj_type).not_nil!
 
-      @last = match_type_id obj_type, filtered_type, type_id
+        @last = match_type_id obj_type, filtered_type, type_id
+      end
 
       false
     end

From e1fefe19d6296152a45d1edfc99c669fa74e05df Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 4 Jan 2024 11:06:54 +0100
Subject: [PATCH 029/105] Add `unreachable` options to manpage (#14164)

---
 man/crystal.1 | 46 +++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/man/crystal.1 b/man/crystal.1
index 508b2ab44cb9..bfdb364d932b 100644
--- a/man/crystal.1
+++ b/man/crystal.1
@@ -411,9 +411,49 @@ to specify the cursor position. The format for the cursor position is file:line:
 .It Cm types
 Show type of main variables of file.
 .It Cm unreachable
-Show methods that are never called. The output is a list of lines with columns
-separated by tab. The first column is the location of the def, the second column
-its reference name and the third column is the length in lines.
+Show methods that are never called. The text output is a list of lines with columns
+separated by tab.
+
+.Pp
+Output fields:
+
+.Bl -tag -width "1234567890" -compact
+.Pp
+.It Cm count
+sum of all calls to this method (only with
+.Fl -tallies
+ option; otherwise skipped)
+.It Cm location
+pathname, line and column, all separated by colon
+.It Cm name
+.It Cm lines
+length of the def in lines
+.It Cm annotations
+.El
+
+.Pp
+Options:
+.Bl -tag -width "12345678" -compact
+.Pp
+.It Fl D Ar FLAG, Fl -define= Ar FLAG
+Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with --target-triple or the hosts default, if none is given.
+.It Fl f Ar FORMAT, Fl -format= Ar FORMAT
+Output format 'text' (default), 'json', or 'csv'.
+.It Fl -tallies
+Print reachable methods and their call counts as well.
+.It Fl -check
+Exit with error if there is any unreachable code.
+.It Fl i Ar PATH, Fl -include= Ar PATH
+Include path in output.
+.It Fl e Ar PATH, Fl -exclude= Ar PATH
+Exclude path in output (default:
+.Sy lib
+).
+.It Fl -error-trace
+Show full error trace.
+.It Fl -prelude
+Specify prelude to use. The default one initializes the garbage collector. You can also use --prelude=empty to use no preludes. This can be useful for checking code generation for a specific source code file.
+.El
 .El
 .Pp
 .It

From cb333fed295e929a26979b2336e2326c26520290 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 4 Jan 2024 11:07:04 +0100
Subject: [PATCH 030/105] Configure Renovate Bot to add label
 `topic:infrastructure/ci` on PRs (#14166)

---
 .github/renovate.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.github/renovate.json b/.github/renovate.json
index 4e18234dc0ec..39932ec1f648 100644
--- a/.github/renovate.json
+++ b/.github/renovate.json
@@ -12,5 +12,6 @@
       "matchManagers": ["github-actions"],
       "schedule": ["after 5am and before 8am on Wednesday"]
     }
-  ]
+  ],
+  "labels": ["topic:infrastructure/ci"]
 }

From 194ffb2b1db671052320e5221ed5cad462c49069 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 4 Jan 2024 13:45:54 +0100
Subject: [PATCH 031/105] Update GH Actions (#14165)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 .github/workflows/win.yml                | 14 +++++++-------
 .github/workflows/win_build_portable.yml |  2 +-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml
index da66d568835a..c80dcfce8fb6 100644
--- a/.github/workflows/win.yml
+++ b/.github/workflows/win.yml
@@ -18,7 +18,7 @@ jobs:
           git config --global core.autocrlf false
 
       - name: Enable Developer Command Prompt
-        uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
+        uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
 
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -77,7 +77,7 @@ jobs:
           key: win-openssl-libs-3.1.0-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc
       - name: Set up NASM
         if: steps.cache-openssl.outputs.cache-hit != 'true'
-        uses: ilammy/setup-nasm@321e6ed62a1fc77024a3bd853deb33645e8b22c4 # v1.4.0
+        uses: ilammy/setup-nasm@13cbeb366c45c4379d3478cdcbadd8295feb5028 # v1.5.1
       - name: Build OpenSSL
         if: steps.cache-openssl.outputs.cache-hit != 'true'
         run: .\etc\win-ci\build-openssl.ps1 -BuildTree deps\openssl -Version 3.1.0
@@ -90,7 +90,7 @@ jobs:
           git config --global core.autocrlf false
 
       - name: Enable Developer Command Prompt
-        uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
+        uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
 
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -159,7 +159,7 @@ jobs:
           key: win-openssl-dlls-3.1.0-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc
       - name: Set up NASM
         if: steps.cache-openssl-dlls.outputs.cache-hit != 'true'
-        uses: ilammy/setup-nasm@321e6ed62a1fc77024a3bd853deb33645e8b22c4 # v1.4.0
+        uses: ilammy/setup-nasm@13cbeb366c45c4379d3478cdcbadd8295feb5028 # v1.5.1
       - name: Build OpenSSL
         if: steps.cache-openssl-dlls.outputs.cache-hit != 'true'
         run: .\etc\win-ci\build-openssl.ps1 -BuildTree deps\openssl -Version 3.1.0 -Dynamic
@@ -168,7 +168,7 @@ jobs:
     runs-on: windows-2022
     steps:
       - name: Enable Developer Command Prompt
-        uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
+        uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
 
       - name: Cache LLVM
         id: cache-llvm-libs
@@ -212,7 +212,7 @@ jobs:
           git config --global core.autocrlf false
 
       - name: Enable Developer Command Prompt
-        uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
+        uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
 
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -246,7 +246,7 @@ jobs:
           git config --global core.autocrlf false
 
       - name: Enable Developer Command Prompt
-        uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
+        uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
 
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/win_build_portable.yml b/.github/workflows/win_build_portable.yml
index 6222aaee3055..960606628a9e 100644
--- a/.github/workflows/win_build_portable.yml
+++ b/.github/workflows/win_build_portable.yml
@@ -19,7 +19,7 @@ jobs:
           git config --global core.autocrlf false
 
       - name: Enable Developer Command Prompt
-        uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
+        uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
 
       - name: Install Crystal
         uses: crystal-lang/install-crystal@v1

From f435981237c527701d1c7c68027a30339ecd40db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 4 Jan 2024 13:46:11 +0100
Subject: [PATCH 032/105] Fix formatting in manpage (#14163)

---
 man/crystal.1 | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/man/crystal.1 b/man/crystal.1
index bfdb364d932b..3a2a3d4a1b2a 100644
--- a/man/crystal.1
+++ b/man/crystal.1
@@ -130,7 +130,7 @@ Specify a specific CPU to generate code for. This will pass a -mcpu flag to LLVM
 Passing --mcpu native will pass the host CPU name to tune performance for the host.
 .It Fl -mattr Ar CPU
 Override or control specific attributes of the target, such as whether SIMD operations are enabled or not. The default set of attributes is set by the current CPU. This will pass a -mattr flag to LLVM, and is only intended to be used for cross-compilation. For a list of available attributes, invoke "llvm-as < /dev/null | llc -march=xyz -mattr=help".
-.It Fl -mcmodel default|kernel|small|medium|large
+.It Fl -mcmodel Ar default|kernel|small|medium|large
 Specifies a specific code model to generate code for. This will pass a --code-model flag to LLVM.
 .It Fl -no-color
 Disable colored output.
@@ -407,7 +407,7 @@ flag.
 .It Cm implementations
 Show implementations for a given call. Use
 .Fl -cursor
-to specify the cursor position. The format for the cursor position is file:line:column.
+ to specify the cursor position. The format for the cursor position is file:line:column.
 .It Cm types
 Show type of main variables of file.
 .It Cm unreachable
@@ -493,7 +493,7 @@ Middle optimization
 .It Fl O3
 High optimization
 .
-.Sh ENVIRONMENT VARIABLES
+.Sh ENVIRONMENT\ VARIABLES
 .Bl -tag -width "12345678" -compact
 .Pp
 .It

From 3e05a2af1782c9951d2133d6c1951fa23c1f4ef0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 4 Jan 2024 13:46:23 +0100
Subject: [PATCH 033/105] Embed logo image into repository and upgrade to SVG
 (#14137)

---
 Makefile                               |   1 +
 README.md                              |   2 +-
 doc/assets/crystal-born-and-raised.svg | 248 +++++++++++++++++++++++++
 3 files changed, 250 insertions(+), 1 deletion(-)
 create mode 100644 doc/assets/crystal-born-and-raised.svg

diff --git a/Makefile b/Makefile
index 2a7f9d43869f..461ee56bd5e5 100644
--- a/Makefile
+++ b/Makefile
@@ -127,6 +127,7 @@ samples: ## Build example programs
 docs: ## Generate standard library documentation
 	$(call check_llvm_config)
 	./bin/crystal docs src/docs_main.cr $(DOCS_OPTIONS) --project-name=Crystal --project-version=$(CRYSTAL_VERSION) --source-refname=$(CRYSTAL_CONFIG_BUILD_COMMIT)
+	cp -av doc/ docs/
 
 .PHONY: crystal
 crystal: $(O)/crystal ## Build the compiler
diff --git a/README.md b/README.md
index 67bf031ed038..70577b822fdc 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
 
 ---
 
-[![Crystal - Born and raised at Manas](https://cloud.githubusercontent.com/assets/209371/13291809/022e2360-daf8-11e5-8be7-d02c1c8b38fb.png)](https://manas.tech/)
+[![Crystal - Born and raised at Manas](doc/assets/crystal-born-and-raised.svg)](https://manas.tech/)
 
 Crystal is a programming language with the following goals:
 
diff --git a/doc/assets/crystal-born-and-raised.svg b/doc/assets/crystal-born-and-raised.svg
new file mode 100644
index 000000000000..98e85d9b46b2
--- /dev/null
+++ b/doc/assets/crystal-born-and-raised.svg
@@ -0,0 +1,248 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="640" viewBox="-120 -30 710 260">
+<defs>
+  <style>
+  .crystal {
+    fill: #020202;
+  }
+  @media(prefers-color-scheme: dark) {
+    .crystal {
+      fill: #FDFDFD;
+    }
+  }
+  </style>
+</defs>
+<g fill="#787878">
+  <path d="M8.5482,186.8324v-21.2803h6.7861c1.3071,0,2.4331,0.1289,3.3784,0.3867
+    c0.9453,0.2568,1.7227,0.623,2.3315,1.0986c0.6089,0.4746,1.0591,1.0566,1.3516,1.7451c0.292,0.6875,0.438,1.4619,0.438,2.3232
+    c0,0.5254-0.0815,1.0303-0.2451,1.5146c-0.1631,0.4854-0.4106,0.9355-0.7427,1.3516c-0.3315,0.416-0.7476,0.7871-1.2471,1.1143
+    c-0.5,0.3262-1.0869,0.5938-1.7598,0.8018c1.5542,0.3066,2.7271,0.8662,3.5195,1.6777c0.792,0.8125,1.188,1.8809,1.188,3.208
+    c0,0.9004-0.166,1.7227-0.4976,2.4648c-0.332,0.7422-0.8169,1.3809-1.4556,1.916c-0.6382,0.5342-1.4204,0.9482-2.3462,1.2393
+    c-0.9258,0.293-1.9824,0.4385-3.1704,0.4385H8.5482z M11.4291,175.0863h3.8018c0.8115,0,1.5146-0.0898,2.1084-0.2676
+    c0.5942-0.1777,1.0864-0.4258,1.4775-0.7422c0.3911-0.3174,0.6807-0.7002,0.8687-1.1514c0.188-0.4502,0.2822-0.9424,0.2822-1.4775
+    c0-1.2471-0.3765-2.1631-1.1284-2.7471c-0.7524-0.584-1.9209-0.876-3.5049-0.876h-3.9053V175.0863z M11.4291,177.1351v7.4102
+    h4.6035c0.8218,0,1.5269-0.0938,2.1162-0.2822c0.5889-0.1875,1.0737-0.4531,1.4551-0.7939
+    c0.3809-0.3418,0.6611-0.748,0.8389-1.2178c0.1782-0.4707,0.2676-0.9873,0.2676-1.5518c0-1.0996-0.3887-1.9678-1.1655-2.6064
+    c-0.7773-0.6387-1.9531-0.958-3.5273-0.958H11.4291z"/>
+  <path d="M33.4364,171.5521c1.0986,0,2.0908,0.1826,2.9771,0.5488s1.6387,0.8867,2.2573,1.5596
+    s1.0938,1.4873,1.4258,2.4424c0.3315,0.9561,0.4971,2.0225,0.4971,3.2002c0,1.1885-0.1655,2.2578-0.4971,3.208
+    c-0.332,0.9502-0.8071,1.7627-1.4258,2.4355s-1.3711,1.1904-2.2573,1.5518s-1.8784,0.542-2.9771,0.542
+    c-1.0991,0-2.0918-0.1807-2.9775-0.542c-0.8862-0.3613-1.6411-0.8789-2.2646-1.5518c-0.624-0.6729-1.104-1.4854-1.4404-2.4355
+    c-0.3369-0.9502-0.5049-2.0195-0.5049-3.208c0-1.1777,0.168-2.2441,0.5049-3.2002c0.3364-0.9551,0.8164-1.7695,1.4404-2.4424
+    c0.6235-0.6729,1.3784-1.1934,2.2646-1.5596C31.3446,171.7348,32.3373,171.5521,33.4364,171.5521z M33.4364,184.976
+    c1.4849,0,2.5933-0.4971,3.3262-1.4922c0.7324-0.9951,1.0991-2.3838,1.0991-4.165c0-1.792-0.3667-3.1885-1.0991-4.1885
+    c-0.7329-0.999-1.8413-1.499-3.3262-1.499c-0.7529,0-1.4062,0.1279-1.9604,0.3857c-0.5547,0.2578-1.0171,0.6289-1.3887,1.1133
+    c-0.3711,0.4854-0.6484,1.082-0.8315,1.79s-0.2744,1.5068-0.2744,2.3984c0,0.8906,0.0913,1.6875,0.2744,2.3906
+    s0.4604,1.2939,0.8315,1.7744c0.3716,0.4805,0.834,0.8486,1.3887,1.1064C32.0302,184.848,32.6835,184.976,33.4364,184.976z"/>
+  <path d="M43.8607,186.8324v-15.043h1.5146c0.2871,0,0.4854,0.0547,0.5942,0.1631
+    c0.1089,0.1094,0.1831,0.2969,0.2227,0.5645l0.1782,2.3467c0.5146-1.0498,1.1509-1.8691,1.9082-2.458s1.646-0.8838,2.6655-0.8838
+    c0.416,0,0.792,0.0469,1.1289,0.1416c0.3364,0.0938,0.6479,0.2246,0.9355,0.3936l-0.3418,1.9746
+    c-0.0693,0.248-0.2227,0.3711-0.4604,0.3711c-0.1387,0-0.3516-0.0469-0.6382-0.1406c-0.2876-0.0938-0.6885-0.1416-1.2031-0.1416
+    c-0.9209,0-1.6904,0.2676-2.3091,0.8018c-0.6187,0.5352-1.1362,1.3125-1.5518,2.332v9.5781H43.8607z"/>
+  <path d="M55.83,186.8324v-15.043h1.5742c0.376,0,0.6138,0.1836,0.7129,0.5498l0.208,1.6328
+    c0.6533-0.7227,1.3833-1.3066,2.1904-1.752c0.8066-0.4453,1.7397-0.668,2.7988-0.668c0.8218,0,1.5469,0.1357,2.1758,0.4082
+    c0.6284,0.2725,1.1533,0.6582,1.5742,1.1582c0.4204,0.5,0.7397,1.1016,0.9575,1.8037c0.2178,0.7031,0.3267,1.4805,0.3267,2.332
+    v9.5781h-2.6431v-9.5781c0-1.1387-0.2598-2.0225-0.7798-2.6504c-0.5195-0.6289-1.314-0.9434-2.3833-0.9434
+    c-0.7822,0-1.5122,0.1885-2.1904,0.5645s-1.3047,0.8857-1.8784,1.5293v11.0781H55.83z"/>
+  <path d="M89.1234,186.8324h-1.1729c-0.2578,0-0.4653-0.0391-0.624-0.1191c-0.1582-0.0791-0.2622-0.2471-0.3115-0.5049
+    l-0.2969-1.3955c-0.3965,0.3564-0.7822,0.6758-1.1587,0.958c-0.376,0.2822-0.772,0.5195-1.188,0.7129
+    c-0.4155,0.1924-0.8589,0.3389-1.3291,0.4375s-0.9927,0.1484-1.5664,0.1484c-0.5845,0-1.1313-0.082-1.6411-0.2451
+    c-0.5098-0.1641-0.9526-0.4102-1.3291-0.7383c-0.3765-0.3271-0.6758-0.7422-0.8984-1.2441s-0.334-1.0947-0.334-1.7803
+    c0-0.5957,0.1636-1.1699,0.4902-1.7217c0.3267-0.5508,0.8535-1.04,1.5815-1.4678c0.7275-0.4268,1.6802-0.7773,2.8584-1.0498
+    c1.1782-0.2734,2.6187-0.4102,4.3213-0.4102v-1.1807c0-1.1758-0.25-2.0645-0.75-2.667s-1.2397-0.9043-2.2197-0.9043
+    c-0.644,0-1.186,0.082-1.6265,0.2451s-0.8218,0.3467-1.1431,0.5488c-0.3218,0.2031-0.5991,0.3867-0.832,0.5498
+    c-0.2324,0.1631-0.4629,0.2451-0.6904,0.2451c-0.1782,0-0.334-0.0469-0.4678-0.1406c-0.1333-0.0947-0.2402-0.2109-0.3193-0.3496
+    l-0.4751-0.8467c0.8315-0.8018,1.7275-1.4004,2.688-1.7969c0.96-0.3955,2.0244-0.5938,3.1929-0.5938
+    c0.8413,0,1.5889,0.1387,2.2422,0.416s1.2026,0.6631,1.6484,1.1582c0.4453,0.4951,0.7817,1.0938,1.0098,1.7969
+    c0.2275,0.7031,0.3413,1.4756,0.3413,2.3164V186.8324z M82.2631,185.2142c0.4648,0,0.8906-0.0469,1.2769-0.1416
+    c0.3862-0.0938,0.75-0.2275,1.0918-0.4014c0.3413-0.1729,0.668-0.3828,0.98-0.6309c0.3115-0.2471,0.6162-0.5293,0.9131-0.8467
+    v-3.1035c-1.2178,0-2.2524,0.0771-3.1035,0.2314c-0.8516,0.1553-1.5444,0.3564-2.0791,0.6055s-0.9233,0.543-1.1655,0.8809
+    c-0.2427,0.3389-0.3638,0.7168-0.3638,1.1357c0,0.3984,0.064,0.7412,0.1929,1.0303c0.1284,0.2891,0.3018,0.5254,0.5195,0.71
+    c0.2178,0.1836,0.4756,0.3184,0.7725,0.4033C81.5946,185.1713,81.9164,185.2142,82.2631,185.2142z"/>
+  <path d="M93.1327,186.8324v-15.043h1.5742c0.376,0,0.6138,0.1836,0.7129,0.5498l0.208,1.6328
+    c0.6533-0.7227,1.3833-1.3066,2.1904-1.752c0.8066-0.4453,1.7397-0.668,2.7988-0.668c0.8218,0,1.5469,0.1357,2.1758,0.4082
+    c0.6284,0.2725,1.1533,0.6582,1.5742,1.1582c0.4204,0.5,0.7397,1.1016,0.9575,1.8037c0.2178,0.7031,0.3267,1.4805,0.3267,2.332
+    v9.5781h-2.6431v-9.5781c0-1.1387-0.2598-2.0225-0.7798-2.6504c-0.5195-0.6289-1.314-0.9434-2.3833-0.9434
+    c-0.7822,0-1.5122,0.1885-2.1904,0.5645s-1.3047,0.8857-1.8784,1.5293v11.0781H93.1327z"/>
+  <path d="M120.2343,186.8324c-0.3765,0-0.6143-0.1826-0.7129-0.5498l-0.2378-1.8262
+    c-0.6436,0.7822-1.3784,1.4082-2.2051,1.8789c-0.8267,0.4697-1.7744,0.7051-2.8438,0.7051c-0.8613,0-1.6436-0.166-2.3462-0.498
+    c-0.7031-0.3311-1.3022-0.8184-1.7969-1.4619c-0.4951-0.6436-0.8765-1.4453-1.1436-2.4062
+    c-0.2676-0.96-0.4009-2.0635-0.4009-3.3115c0-1.1084,0.1484-2.1406,0.4453-3.0957c0.2969-0.9561,0.7251-1.7842,1.2847-2.4873
+    c0.5591-0.7031,1.2397-1.2549,2.042-1.6562c0.8018-0.4014,1.7124-0.6016,2.7324-0.6016c0.9204,0,1.7075,0.1562,2.3608,0.4678
+    c0.6533,0.3125,1.2373,0.75,1.7524,1.3145v-8.3457h2.6431v21.874H120.2343z M115.1107,184.9017
+    c0.8613,0,1.6162-0.1982,2.2646-0.5938s1.2451-0.9551,1.7896-1.6777v-7.2773c-0.4854-0.6533-1.0171-1.1104-1.5967-1.373
+    c-0.5791-0.2627-1.2202-0.3936-1.9229-0.3936c-1.4058,0-2.4849,0.5-3.2373,1.5s-1.1284,2.4258-1.1284,4.2764
+    c0,0.9805,0.084,1.8193,0.2524,2.5176c0.168,0.6973,0.4155,1.2715,0.7422,1.7227c0.3267,0.4502,0.728,0.7793,1.2031,0.9873
+    S114.497,184.9017,115.1107,184.9017z"/>
+  <path d="M131.9799,186.8324v-15.043h1.5146c0.2871,0,0.4854,0.0547,0.5942,0.1631
+    c0.1089,0.1094,0.1831,0.2969,0.2227,0.5645l0.1782,2.3467c0.5146-1.0498,1.1509-1.8691,1.9082-2.458s1.646-0.8838,2.6655-0.8838
+    c0.416,0,0.792,0.0469,1.1289,0.1416c0.3364,0.0938,0.6479,0.2246,0.9355,0.3936l-0.3418,1.9746
+    c-0.0693,0.248-0.2227,0.3711-0.4604,0.3711c-0.1387,0-0.3516-0.0469-0.6382-0.1406c-0.2876-0.0938-0.6885-0.1416-1.2031-0.1416
+    c-0.9209,0-1.6904,0.2676-2.3091,0.8018c-0.6187,0.5352-1.1362,1.3125-1.5518,2.332v9.5781H131.9799z"/>
+  <path d="M154.433,186.8324h-1.1729c-0.2578,0-0.4653-0.0391-0.624-0.1191c-0.1582-0.0791-0.2622-0.2471-0.3115-0.5049
+    l-0.2969-1.3955c-0.3965,0.3564-0.7822,0.6758-1.1587,0.958c-0.376,0.2822-0.772,0.5195-1.188,0.7129
+    c-0.4155,0.1924-0.8589,0.3389-1.3291,0.4375s-0.9927,0.1484-1.5664,0.1484c-0.5845,0-1.1313-0.082-1.6411-0.2451
+    c-0.5098-0.1641-0.9526-0.4102-1.3291-0.7383c-0.3765-0.3271-0.6758-0.7422-0.8984-1.2441s-0.334-1.0947-0.334-1.7803
+    c0-0.5957,0.1636-1.1699,0.4902-1.7217c0.3267-0.5508,0.8535-1.04,1.5815-1.4678c0.7275-0.4268,1.6802-0.7773,2.8584-1.0498
+    c1.1782-0.2734,2.6187-0.4102,4.3213-0.4102v-1.1807c0-1.1758-0.25-2.0645-0.75-2.667s-1.2397-0.9043-2.2197-0.9043
+    c-0.644,0-1.186,0.082-1.6265,0.2451s-0.8218,0.3467-1.1431,0.5488c-0.3218,0.2031-0.5991,0.3867-0.832,0.5498
+    c-0.2324,0.1631-0.4629,0.2451-0.6904,0.2451c-0.1782,0-0.334-0.0469-0.4678-0.1406c-0.1333-0.0947-0.2402-0.2109-0.3193-0.3496
+    l-0.4751-0.8467c0.8315-0.8018,1.7275-1.4004,2.688-1.7969c0.96-0.3955,2.0244-0.5938,3.1929-0.5938
+    c0.8413,0,1.5889,0.1387,2.2422,0.416s1.2026,0.6631,1.6484,1.1582c0.4453,0.4951,0.7817,1.0938,1.0098,1.7969
+    c0.2275,0.7031,0.3413,1.4756,0.3413,2.3164V186.8324z M147.5727,185.2142c0.4648,0,0.8906-0.0469,1.2769-0.1416
+    c0.3862-0.0938,0.75-0.2275,1.0918-0.4014c0.3413-0.1729,0.668-0.3828,0.98-0.6309c0.3115-0.2471,0.6162-0.5293,0.9131-0.8467
+    v-3.1035c-1.2178,0-2.2524,0.0771-3.1035,0.2314c-0.8516,0.1553-1.5444,0.3564-2.0791,0.6055s-0.9233,0.543-1.1655,0.8809
+    c-0.2427,0.3389-0.3638,0.7168-0.3638,1.1357c0,0.3984,0.064,0.7412,0.1929,1.0303c0.1284,0.2891,0.3018,0.5254,0.5195,0.71
+    c0.2178,0.1836,0.4756,0.3184,0.7725,0.4033C146.9042,185.1713,147.226,185.2142,147.5727,185.2142z"/>
+  <path d="M161.977,167.0668c0,0.2578-0.0522,0.498-0.1562,0.7207s-0.2427,0.4209-0.4155,0.5938
+    c-0.1733,0.1738-0.374,0.3096-0.6016,0.4082c-0.228,0.0996-0.4702,0.1484-0.7275,0.1484c-0.2578,0-0.4976-0.0488-0.7202-0.1484
+    c-0.2231-0.0986-0.4209-0.2344-0.5942-0.4082c-0.1733-0.1729-0.3096-0.3711-0.4082-0.5938
+    c-0.0991-0.2227-0.1484-0.4629-0.1484-0.7207c0-0.2568,0.0493-0.502,0.1484-0.7344c0.0986-0.2334,0.2349-0.4355,0.4082-0.6094
+    c0.1733-0.1729,0.3711-0.3096,0.5942-0.4082c0.2227-0.0986,0.4624-0.1484,0.7202-0.1484c0.2573,0,0.4995,0.0498,0.7275,0.1484
+    c0.2275,0.0986,0.4282,0.2354,0.6016,0.4082c0.1729,0.1738,0.3115,0.376,0.4155,0.6094
+    C161.9247,166.5648,161.977,166.81,161.977,167.0668z M161.3827,171.7894v15.043h-2.6431v-15.043H161.3827z"/>
+  <path d="M174.6586,174.2689c-0.1191,0.2178-0.3022,0.3271-0.5498,0.3271c-0.1484,0-0.3169-0.0547-0.5049-0.1631
+    c-0.188-0.1094-0.418-0.2305-0.6904-0.3643s-0.5967-0.2568-0.9727-0.3711c-0.3765-0.1133-0.8218-0.1709-1.3364-0.1709
+    c-0.4453,0-0.8467,0.0576-1.2026,0.1709c-0.3564,0.1143-0.6611,0.2695-0.9136,0.4678s-0.4453,0.4287-0.5791,0.6904
+    c-0.1338,0.2627-0.2002,0.5469-0.2002,0.8535c0,0.3867,0.1113,0.708,0.334,0.9658s0.5171,0.4805,0.8833,0.668
+    c0.3662,0.1885,0.7822,0.3545,1.2476,0.498s0.9429,0.2969,1.4331,0.46c0.4897,0.1631,0.9673,0.3438,1.4331,0.542
+    c0.4648,0.1982,0.8809,0.4453,1.2471,0.7422s0.6611,0.6611,0.8838,1.0918s0.334,0.9482,0.334,1.5518
+    c0,0.6934-0.124,1.334-0.3711,1.9229c-0.2476,0.5898-0.6138,1.0996-1.0991,1.5303c-0.4849,0.4297-1.0791,0.7695-1.7817,1.0166
+    c-0.7031,0.2471-1.5146,0.3711-2.4355,0.3711c-1.0493,0-2-0.1709-2.8511-0.5117c-0.8516-0.3418-1.5742-0.7803-2.168-1.3145
+    l0.6235-1.0098c0.0791-0.1289,0.1729-0.2275,0.2822-0.2969c0.1089-0.0693,0.2524-0.1045,0.4307-0.1045s0.3662,0.0693,0.564,0.208
+    c0.1982,0.1387,0.4385,0.292,0.7202,0.4609c0.2822,0.168,0.624,0.3213,1.0249,0.46s0.9033,0.208,1.5073,0.208
+    c0.5146,0,0.9653-0.0674,1.3511-0.2002c0.3862-0.1338,0.708-0.3145,0.9653-0.542c0.2573-0.2285,0.4478-0.4902,0.5718-0.7871
+    c0.1235-0.2979,0.1855-0.6143,0.1855-0.9512c0-0.415-0.1113-0.7588-0.334-1.0312s-0.5176-0.5049-0.8838-0.6982
+    s-0.7847-0.3613-1.2544-0.5049c-0.4707-0.1436-0.9507-0.2949-1.4404-0.4531c-0.4902-0.1582-0.9707-0.3389-1.4409-0.542
+    s-0.8887-0.458-1.2544-0.7646c-0.3667-0.3066-0.6611-0.6855-0.8838-1.1357c-0.2227-0.4512-0.334-0.998-0.334-1.6416
+    c0-0.5742,0.1187-1.126,0.3564-1.6553c0.2373-0.5293,0.584-0.9951,1.0396-1.3965c0.4551-0.4004,1.0146-0.7197,1.6777-0.957
+    c0.6631-0.2383,1.4204-0.3564,2.272-0.3564c0.9902,0,1.8789,0.1553,2.6655,0.4678c0.7871,0.3115,1.4678,0.7402,2.042,1.2842
+    L174.6586,174.2689z"/>
+  <path d="M184.89,171.5521c0.9009,0,1.7324,0.1504,2.4946,0.4521c0.7622,0.3027,1.4204,0.7383,1.9751,1.3076
+    c0.5542,0.5693,0.9878,1.2715,1.2993,2.1084c0.312,0.8369,0.4678,1.7891,0.4678,2.8584c0,0.416-0.0444,0.6934-0.1338,0.832
+    c-0.0889,0.1387-0.2573,0.208-0.5049,0.208h-10.0088c0.02,0.9502,0.1484,1.7764,0.3862,2.4795s0.5645,1.29,0.98,1.7598
+    c0.416,0.4707,0.9106,0.8223,1.4849,1.0547s1.2178,0.3486,1.9307,0.3486c0.6631,0,1.2349-0.0762,1.7153-0.2305
+    c0.48-0.1533,0.8931-0.3193,1.2397-0.4971c0.3467-0.1787,0.6362-0.3438,0.8687-0.498c0.2329-0.1533,0.4331-0.2295,0.6016-0.2295
+    c0.2178,0,0.3862,0.084,0.5049,0.252l0.7427,0.9658c-0.3267,0.3955-0.7178,0.7402-1.1733,1.0322s-0.9429,0.5322-1.4624,0.7197
+    c-0.52,0.1885-1.0571,0.3291-1.6113,0.4229c-0.5547,0.0947-1.104,0.1416-1.6484,0.1416c-1.0396,0-1.9976-0.1758-2.8735-0.5273
+    s-1.6333-0.8662-2.272-1.5439c-0.6387-0.6787-1.1362-1.5176-1.4927-2.5176c-0.356-1-0.5342-2.1484-0.5342-3.4453
+    c0-1.0488,0.1606-2.0293,0.4824-2.9404c0.3218-0.9102,0.7847-1.7002,1.3887-2.3682c0.6035-0.668,1.3413-1.1934,2.2124-1.5742
+    S183.8007,171.5521,184.89,171.5521z M184.9491,173.4975c-1.2769,0-2.2817,0.3682-3.0142,1.1064
+    c-0.7329,0.7373-1.188,1.7588-1.3662,3.0664h8.1821c0-0.6143-0.084-1.1758-0.2524-1.6855s-0.4155-0.9502-0.7427-1.3223
+    c-0.3267-0.3711-0.7251-0.6582-1.1953-0.8613C186.0902,173.599,185.5531,173.4975,184.9491,173.4975z"/>
+  <path d="M205.0854,186.8324c-0.3765,0-0.6143-0.1826-0.7129-0.5498l-0.2378-1.8262
+    c-0.6436,0.7822-1.3784,1.4082-2.2051,1.8789c-0.8267,0.4697-1.7744,0.7051-2.8438,0.7051c-0.8613,0-1.6436-0.166-2.3462-0.498
+    c-0.7031-0.3311-1.3022-0.8184-1.7969-1.4619c-0.4951-0.6436-0.8765-1.4453-1.1436-2.4062
+    c-0.2676-0.96-0.4009-2.0635-0.4009-3.3115c0-1.1084,0.1484-2.1406,0.4453-3.0957c0.2969-0.9561,0.7251-1.7842,1.2847-2.4873
+    c0.5591-0.7031,1.2397-1.2549,2.042-1.6562c0.8018-0.4014,1.7124-0.6016,2.7324-0.6016c0.9204,0,1.7075,0.1562,2.3608,0.4678
+    c0.6533,0.3125,1.2373,0.75,1.7524,1.3145v-8.3457h2.6431v21.874H205.0854z M199.9618,184.9017
+    c0.8613,0,1.6162-0.1982,2.2646-0.5938s1.2451-0.9551,1.7896-1.6777v-7.2773c-0.4854-0.6533-1.0171-1.1104-1.5967-1.373
+    c-0.5791-0.2627-1.2202-0.3936-1.9229-0.3936c-1.4058,0-2.4849,0.5-3.2373,1.5s-1.1284,2.4258-1.1284,4.2764
+    c0,0.9805,0.084,1.8193,0.2524,2.5176c0.168,0.6973,0.4155,1.2715,0.7422,1.7227c0.3267,0.4502,0.728,0.7793,1.2031,0.9873
+    S199.3481,184.9017,199.9618,184.9017z"/>
+  <path d="M227.8803,186.8324h-1.1738c-0.2578,0-0.4648-0.0391-0.623-0.1191c-0.1602-0.0791-0.2637-0.2471-0.3125-0.5049
+    l-0.2969-1.3955c-0.3965,0.3564-0.7832,0.6758-1.1582,0.958c-0.377,0.2822-0.7734,0.5195-1.1875,0.7129
+    c-0.416,0.1924-0.8594,0.3389-1.3301,0.4375s-0.9922,0.1484-1.5664,0.1484c-0.584,0-1.1309-0.082-1.6406-0.2451
+    c-0.5098-0.1641-0.9531-0.4102-1.3301-0.7383c-0.375-0.3271-0.6758-0.7422-0.8984-1.2441s-0.334-1.0947-0.334-1.7803
+    c0-0.5957,0.1641-1.1699,0.4902-1.7217c0.3262-0.5508,0.8535-1.04,1.582-1.4678c0.7266-0.4268,1.6797-0.7773,2.8594-1.0498
+    c1.1777-0.2734,2.6172-0.4102,4.3203-0.4102v-1.1807c0-1.1758-0.25-2.0645-0.75-2.667s-1.2402-0.9043-2.2207-0.9043
+    c-0.6426,0-1.1855,0.082-1.625,0.2451c-0.4414,0.1631-0.8223,0.3467-1.1445,0.5488c-0.3203,0.2031-0.5977,0.3867-0.8301,0.5498
+    c-0.2344,0.1631-0.4629,0.2451-0.6914,0.2451c-0.1777,0-0.334-0.0469-0.4668-0.1406c-0.1348-0.0947-0.2402-0.2109-0.3203-0.3496
+    l-0.4746-0.8467c0.832-0.8018,1.7266-1.4004,2.6875-1.7969c0.9609-0.3955,2.0254-0.5938,3.1934-0.5938
+    c0.8398,0,1.5879,0.1387,2.2422,0.416c0.6523,0.2773,1.2031,0.6631,1.6484,1.1582s0.7812,1.0938,1.0098,1.7969
+    c0.2266,0.7031,0.3418,1.4756,0.3418,2.3164V186.8324z M221.019,185.2142c0.4648,0,0.8906-0.0469,1.2773-0.1416
+    c0.3848-0.0938,0.75-0.2275,1.0918-0.4014c0.3418-0.1729,0.668-0.3828,0.9785-0.6309c0.3125-0.2471,0.6172-0.5293,0.9141-0.8467
+    v-3.1035c-1.2168,0-2.252,0.0771-3.1035,0.2314c-0.8516,0.1553-1.5449,0.3564-2.0781,0.6055
+    c-0.5352,0.249-0.9238,0.543-1.166,0.8809c-0.2441,0.3389-0.3652,0.7168-0.3652,1.1357c0,0.3984,0.0645,0.7412,0.1934,1.0303
+    s0.3027,0.5254,0.5195,0.71c0.2188,0.1836,0.4766,0.3184,0.7734,0.4033C220.351,185.1713,220.6713,185.2142,221.019,185.2142z"/>
+  <path d="M236.4472,187.0697c-1.187,0-2.1001-0.3311-2.7388-0.9951c-0.6387-0.6631-0.958-1.6182-0.958-2.8652v-9.207
+    h-1.8115c-0.1582,0-0.292-0.0469-0.4014-0.1416c-0.1084-0.0938-0.1631-0.2393-0.1631-0.4375v-1.0547l2.4648-0.3115l0.6094-4.6484
+    c0.0195-0.1484,0.084-0.2695,0.1924-0.3643c0.1094-0.0938,0.248-0.1406,0.416-0.1406h1.3369v5.1826h4.3062v1.916h-4.3062v9.0283
+    c0,0.6338,0.1533,1.1045,0.46,1.4111c0.3062,0.3066,0.7026,0.46,1.188,0.46c0.2764,0,0.5166-0.0371,0.7197-0.1113
+    s0.3789-0.1562,0.5273-0.2451s0.2744-0.1709,0.3789-0.2451c0.1035-0.0742,0.1953-0.1113,0.2744-0.1113
+    c0.1387,0,0.2627,0.085,0.3711,0.2529l0.7725,1.2617c-0.4551,0.4258-1.0049,0.7598-1.6484,1.0029
+    C237.7939,186.9486,237.1308,187.0697,236.4472,187.0697z"/>
+</g>
+<path fill="#787878" d="M293.0266,185.993h-2.6754v-6.6887l0,0c0-2.1738-1.7558-4.0132-4.0132-4.0132
+  c-2.1738,0-4.0132,1.7558-4.0132,3.9296v1.3377h-2.6754v-1.3377l0,0l0,0l0,0c0-2.1738-1.7558-4.0132-4.0132-4.0132
+  c-2.1738,0-4.0132,1.7558-4.0132,4.0132l0,0v1.3377h-2.6754v-13.1265h2.6754v6.6887c1.0869-0.8361,2.5083-1.3377,4.0132-1.3377
+  c2.1738,0,4.0968,1.0033,5.351,2.6755c1.2541-1.5886,3.1771-2.6755,5.3509-2.6755c3.6788,0,6.6887,3.0099,6.6887,6.6887l0,0V185.993
+  z M293.0266,170.0238h-6.6887l0,0c-1.8394,0-3.4279-0.7525-4.6821-1.923l1.923-1.923c0.7525,0.6689,1.6722,1.0869,2.7591,1.0869
+  h6.6887V170.0238z M281.0706,156.73c11.0363,0,19.9824,8.9461,19.9824,19.9824s-8.9461,19.9824-19.9824,19.9824
+  s-19.9824-8.9461-19.9824-19.9824S270.0343,156.73,281.0706,156.73 M281.0706,154.0546c-12.4576,0-22.6579,10.1166-22.6579,22.6579
+  c0,12.4576,10.1166,22.6579,22.6579,22.6579c12.4576,0,22.6579-10.1166,22.6579-22.6579
+  C303.7285,164.2548,293.5283,154.0546,281.0706,154.0546L281.0706,154.0546z M326.2192,171.7795l0.0836,1.6722
+  c1.0033-1.2541,2.5083-1.923,4.4312-1.923c1.923,0,3.5116,0.7525,4.264,2.4246c1.0033-1.4213,2.5919-2.4246,4.7657-2.4246
+  c3.1771,0,5.0165,1.6722,5.0165,5.4345v9.8658h-2.5919v-9.8658c0-2.5083-1.2541-3.2607-3.1771-3.2607
+  c-2.0902,0-3.2607,1.4213-3.5115,3.1771v9.9494h-2.5919v-9.8658c0-2.341-1.2541-3.2607-3.1771-3.2607
+  c-1.8394,0-2.9263,0.8361-3.4279,2.1738v10.9527h-2.5919v-15.0495H326.2192z M357.9904,186.829
+  c-0.1672-0.3344-0.2508-1.0033-0.3344-1.5885c-1.0033,1.0033-2.4246,1.8394-4.264,1.8394c-3.0935,0-5.1001-1.923-5.1001-4.4312
+  c0-3.2607,2.5919-4.9329,6.7723-4.9329h2.5919v-1.1705c0-1.7558-1.0869-2.9263-3.1771-2.9263c-1.923,0-3.2607,1.0869-3.2607,2.341
+  h-2.5919c0-2.1738,2.341-4.4312,5.9362-4.4312c3.2607,0,5.6018,1.6722,5.6018,5.0165v7.0231c0,1.0033,0.1672,2.2574,0.5016,3.0935
+  v0.2508h-2.6755V186.829z M357.5723,182.6486v-3.0935h-2.1738c-2.9263,0-4.5985,0.9197-4.5985,2.7591
+  c0,1.4213,1.0033,2.5919,2.8427,2.5919C355.5657,184.8224,357.0707,183.7355,357.5723,182.6486z M366.602,171.7795l0.0836,1.923
+  c1.0869-1.3377,2.5919-2.1738,4.5148-2.1738c2.9263,0,4.7657,1.5049,4.7657,5.4345v9.8658h-2.5919v-9.8658
+  c0-2.341-1.0869-3.2607-3.0099-3.2607c-1.6722,0-2.9263,1.0033-3.6788,2.4246v10.7019h-2.5919v-15.0495H366.602z M389.1763,186.829
+  c-0.1672-0.3344-0.2508-1.0033-0.3344-1.5885c-1.0033,1.0033-2.4247,1.8394-4.264,1.8394c-3.0935,0-5.1001-1.923-5.1001-4.4312
+  c0-3.2607,2.5919-4.9329,6.7723-4.9329h2.5919v-1.1705c0-1.7558-1.0869-2.9263-3.1771-2.9263c-1.923,0-3.2607,1.0869-3.2607,2.341
+  h-2.5919c0-2.1738,2.341-4.4312,5.9362-4.4312c3.2607,0,5.6017,1.6722,5.6017,5.0165v7.0231c0,1.0033,0.1672,2.2574,0.5016,3.0935
+  v0.2508h-2.6755V186.829z M388.7582,182.6486v-3.0935h-2.1738c-2.9263,0-4.5984,0.9197-4.5984,2.7591
+  c0,1.4213,1.0033,2.5919,2.8427,2.5919C386.7516,184.8224,388.173,183.7355,388.7582,182.6486z M400.6306,180.224
+  c-3.3443-0.6689-5.4345-1.8394-5.4345-4.3476c0-2.341,2.1738-4.4312,5.5182-4.4312c3.5952,0,5.769,2.0902,5.769,4.6821h-2.5919
+  c0-1.2541-1.0869-2.5919-3.1771-2.5919c-2.1738,0-3.0099,1.0869-3.0099,2.1738c0,1.1705,0.5853,1.6722,3.5115,2.341
+  c3.6788,0.8361,5.351,2.0902,5.351,4.5148c0,2.5919-2.2574,4.4312-5.769,4.4312c-4.0132,0-6.187-2.4246-6.187-4.9329h2.5919
+  c0.0836,2.0902,2.0066,2.8427,3.5952,2.8427c2.0902,0,3.2607-0.9197,3.2607-2.1738
+  C404.0586,181.7289,403.5569,180.8929,400.6306,180.224z M411.6669,183.9028c1.0869,0,1.5885,0.6689,1.5885,1.5886
+  c0,0.8361-0.5852,1.5049-1.5885,1.5049s-1.5886-0.6689-1.5886-1.5049C410.0784,184.5716,410.58,183.9028,411.6669,183.9028z
+   M420.9474,168.1844v3.5952h2.8427v2.0066h-2.8427v9.2805c0,1.5886,0.8361,1.8394,1.6722,1.8394
+  c0.418,0,0.9197-0.0836,1.2541-0.1672v2.0902c-0.418,0.0836-1.0033,0.2508-2.0066,0.2508c-1.923,0-3.5116-1.0033-3.5116-4.0132
+  v-9.2805h-2.7591v-2.0066h2.7591v-3.5952H420.9474z M426.1312,179.8059v-0.5853c0-4.9329,3.1771-7.692,6.6051-7.692
+  c4.264,0,6.187,3.1771,6.187,7.3575v1.1705H428.723c0.0836,2.7591,1.7558,4.9329,4.4312,4.9329
+  c1.8394,0,3.0099-0.8361,3.9296-2.0066l1.5886,1.2541c-0.9197,1.505-2.6755,2.9263-5.6854,2.9263
+  C428.8066,187.0799,426.1312,184.07,426.1312,179.8059z M428.8066,177.9666h7.5247v-0.1672
+  c-0.0836-2.0066-1.0033-4.0968-3.5952-4.0968C430.646,173.6189,429.1411,175.1239,428.8066,177.9666z M451.3809,182.0634h2.4247
+  c-0.1672,2.6755-2.7591,5.0165-5.9362,5.0165c-4.5148,0-6.6887-3.4279-6.6887-7.5247v-0.5853c0-4.0132,2.1738-7.5247,6.6887-7.5247
+  c3.5116,0,5.8526,2.341,6.0198,5.4346h-2.4247c-0.1672-1.8394-1.5049-3.3443-3.5952-3.3443c-3.1771,0-4.0968,2.7591-4.0968,5.3509
+  v0.5853c0,2.6755,0.9197,5.4345,4.0968,5.4345C449.7087,184.9897,451.2137,183.7355,451.3809,182.0634z M459.2401,173.6189
+  c1.0869-1.3377,2.5919-2.0902,4.4312-2.0902c2.9263,0,4.7657,1.5049,4.7657,5.4345v9.8658h-2.5919v-9.8658
+  c0-2.341-1.0869-3.2607-3.0099-3.2607c-1.6722,0-2.9263,1.0033-3.6788,2.4246v10.7019h-2.5919v-21.3201h2.5919v8.11H459.2401z"/>
+<g class="crystal">
+  <path d="M166.9483,90.4383c-4.744,0-7.8521-1.4723-9.6516-4.2532
+    c-1.6359-2.9445-2.6174-8.1793-2.6174-15.8678s0.8179-13.0869,2.6174-15.8678c1.7994-2.9445,4.9076-4.2532,9.6516-4.2532
+    c5.3983,0,10.4695,0.1636,15.2135,0.4908l0.9815-7.8521c-4.5804-1.1451-9.9787-1.7994-16.195-1.7994
+    c-8.5065,0-14.3956,2.1266-17.8309,6.5434c-3.4353,4.4168-5.2347,11.9418-5.2347,22.5748s1.6358,18.3216,5.2347,22.5749
+    c3.4353,4.4168,9.3244,6.5434,17.8309,6.5434c7.0342,0,12.7597-0.6544,17.3401-2.1266l-0.9815-7.6885
+    C179.3808,90.1111,173.8189,90.4383,166.9483,90.4383z"/>
+  <path d="M227.3114,75.0612c-1.4723-1.3087-2.9445-2.2902-4.5804-2.6174v-0.4908
+    c3.7625-0.4908,6.5434-1.963,8.1793-4.2532c1.6358-2.2902,2.4538-5.7255,2.4538-9.9787c0-6.2163-1.4723-10.6331-4.4168-12.9233
+    c-2.9445-2.2902-8.0157-3.5989-15.2135-3.5989c-8.8336,0-15.7043,0.1636-20.6118,0.6543v56.4371h10.1423V75.7156h10.1423
+    c3.2717,0,5.5619,1.6359,6.5434,5.0712l4.5804,17.5037h10.9603l-5.0712-17.6673
+    C229.7652,78.333,228.7837,76.3699,227.3114,75.0612z M213.4066,67.3727h-10.1423V49.7054h10.1423
+    c3.5989,0,6.2163,0.6543,7.5249,1.7994c1.3087,1.1451,1.963,3.4353,1.963,7.0342c0,3.4353-0.6543,5.7255-1.963,7.0342
+    C219.6229,66.7184,217.1691,67.3727,213.4066,67.3727z"/>
+  <polygon points="378.3012,42.0169 333.3151,42.0169 333.3151,50.687 350.4916,50.687 350.4916,98.454
+    360.7975,98.454 360.7975,50.687 378.3012,50.687 		"/>
+  <path d="M406.2743,42.0169h-9.9787c-1.963,0-3.1081,0.9815-3.7625,2.781L375.6838,98.454h10.4695
+    l4.5804-16.0314h20.939l4.5804,16.0314h10.4695l-17.0129-53.6562C409.5461,42.8348,408.2374,42.0169,406.2743,42.0169z
+      M393.3511,74.0797l5.5619-19.4667l1.3087-4.744h2.1266c0,0.3272,0.4907,1.963,1.3087,4.744l5.7255,19.4667H393.3511z"/>
+  <path d="M468.1098,89.9476h-19.6303c-1.7995,0-3.1081-0.3272-3.7625-0.9815
+    c-0.6543-0.6543-1.1451-1.963-1.1451-3.5989V42.0169h-10.3059v44.8225c0,7.8521,4.2532,11.7782,12.7597,11.7782
+    c9.6516,0,17.0129-0.3272,22.4113-0.6543L468.1098,89.9476z"/>
+  <path d="M263.9547,63.9374c-0.3272,0.8179-1.1451,3.1081-2.2902,6.8706h-0.6544
+    c-1.1451-3.5989-1.963-5.8891-2.2902-6.8706L248.414,42.0169h-10.7967l18.4852,37.2976v19.3031h10.3059V79.3145l18.4852-37.2976
+    h-10.6331L263.9547,63.9374z"/>
+  <path d="M316.3022,67.2091l-10.7967-3.4353c-2.4538-0.8179-4.0896-1.6359-4.9076-2.6174
+    c-0.9815-0.9815-1.3087-2.6174-1.3087-4.9076c0-2.781,0.6543-4.5804,1.963-5.3983c1.3087-0.6543,3.7625-1.1451,7.525-1.1451
+    c4.9076,0,10.6331,0.1636,16.8493,0.3272l0.6544-7.1978c-4.9076-1.3087-10.7967-1.963-17.6673-1.963
+    c-7.1978,0-12.2689,0.9815-15.0499,2.9445c-2.9445,1.963-4.2532,6.0527-4.2532,12.2689c0,4.2532,0.8179,7.8521,2.6174,10.4695
+    c1.7994,2.6174,4.5804,4.5804,8.67,5.8891l11.451,3.5989c2.2902,0.6543,3.926,1.4723,4.744,2.4538
+    c0.8179,0.9815,1.3087,2.6174,1.3087,5.0712c0,2.781-0.6543,4.744-1.7994,5.5619c-1.3087,0.8179-3.7625,1.3087-7.525,1.3087
+    c-2.4538,0-8.3429-0.1636-17.8308-0.3272l-0.6543,7.5249c6.0527,1.1451,12.1053,1.7994,18.3216,1.7994
+    c7.525,0,12.7597-1.1451,15.5406-3.2717c2.9445-2.1266,4.4168-6.3799,4.4168-12.5961c0-4.2532-0.8179-7.8521-2.6174-10.4695
+    C323.6635,70.4808,320.719,68.5178,316.3022,67.2091z"/>
+  <path d="M114.2736,72.2803l-40.8965,40.7329c-0.1636,0.1636-0.3272,0.1636-0.6544,0.1636
+    L16.9401,98.2905c-0.1636,0-0.3272-0.1636-0.4908-0.4908L1.563,42.1805c0-0.1636,0-0.4908,0.1636-0.6543L42.623,0.7933
+    c0.1636-0.1636,0.3272-0.1636,0.6543-0.1636l55.7828,15.0499c0.1636,0,0.3272,0.1636,0.4908,0.4908l14.8863,55.6192
+    C114.6008,71.9531,114.4372,72.1167,114.2736,72.2803z M59.636,27.9485L4.8347,42.6713c-0.1636,0-0.1636,0.1636,0,0.3272
+    L44.9132,83.077c0.1636,0.1636,0.1636,0,0.3272,0l14.7227-54.6377C59.7995,27.9485,59.636,27.9485,59.636,27.9485z"/>
+</g>
+</svg>

From e3200d9eb8814e92849503e646325b09647cfe9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 4 Jan 2024 13:46:33 +0100
Subject: [PATCH 034/105] Improvements for `github-changelog` script (#14160)

---
 scripts/github-changelog.cr | 47 ++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/scripts/github-changelog.cr b/scripts/github-changelog.cr
index b46adb9c656b..c660a01cd8ca 100755
--- a/scripts/github-changelog.cr
+++ b/scripts/github-changelog.cr
@@ -110,10 +110,13 @@ record PullRequest,
     if labels.includes?("breaking-change")
       io << "**[breaking]** "
     end
+    if experimental?
+      io << "**[experimental]** "
+    end
     if deprecated?
       io << "**[deprecation]** "
     end
-    io << title.sub(/^#{type}: /i, "") << " ("
+    io << title.sub(/^\[?(?:#{type}|#{sub_topic})(?::|\]:?) /i, "") << " ("
     io << "[#" << number << "](" << permalink << ")"
     if author = self.author
       io << ", thanks @" << author
@@ -152,9 +155,26 @@ record PullRequest,
   end
 
   def topic
-    labels.find { |label|
-      label.starts_with?("topic:") && label != "topic:multithreading"
-    }.try(&.lchop("topic:").split(/:|\//))
+    topics.fetch(0) do
+      STDERR.puts "Missing topic for ##{number}"
+      nil
+    end
+  end
+
+  def topics
+    topics = labels.compact_map { |label|
+      label.lchop?("topic:").try(&.split(/:|\//))
+    }
+    topics.reject! &.[0].==("multithreading")
+
+    topics.sort_by! { |parts|
+      topic_priority = case parts[0]
+                       when "tools" then 2
+                       when "lang"  then 1
+                       else              0
+                       end
+      {-topic_priority, parts[0]}
+    }
   end
 
   def deprecated?
@@ -165,6 +185,10 @@ record PullRequest,
     labels.includes?("kind:breaking")
   end
 
+  def experimental?
+    labels.includes?("experimental")
+  end
+
   def feature?
     labels.includes?("kind:feature")
   end
@@ -173,6 +197,10 @@ record PullRequest,
     labels.includes?("kind:bug")
   end
 
+  def chore?
+    labels.includes?("kind:chore")
+  end
+
   def refactor?
     labels.includes?("kind:refactor")
   end
@@ -196,9 +224,10 @@ record PullRequest,
   def type
     case
     when feature?     then "feature"
-    when fix?         then "fix"
     when docs?        then "docs"
     when specs?       then "specs"
+    when fix?         then "fix"
+    when chore?       then "chore"
     when performance? then "performance"
     when refactor?    then "refactor"
     else                   nil
@@ -242,16 +271,22 @@ SECTION_TITLES = {
   "breaking"    => "Breaking changes",
   "feature"     => "Features",
   "fix"         => "Bugfixes",
+  "chore"       => "Chores",
   "performance" => "Performance",
   "refactor"    => "Refactor",
   "docs"        => "Documentation",
   "specs"       => "Specs",
   "infra"       => "Infrastructure",
-  ""            => "Chores",
+  ""            => "other",
 }
 
 TOPIC_ORDER = %w[lang stdlib compiler tools other]
 
+puts "## [#{milestone}] (#{Time.local.to_s("%F")})"
+puts
+puts "[#{milestone}]: https://github.com/crystal-lang/crystal/releases/#{milestone}"
+puts
+
 SECTION_TITLES.each do |id, title|
   prs = sections[id]? || next
   puts "### #{title}"

From b8a24e7d94bd35999d0bf4eff0aac368f6be7bcb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 5 Jan 2024 12:02:17 +0100
Subject: [PATCH 035/105] Fix `String::Buffer` and `IO::Memory` capacity to
 grow beyond 1GB (#13989)

---
 spec/std/io/memory_spec.cr      | 33 ++++++++++++++++++++++++++++
 spec/std/string_builder_spec.cr | 39 +++++++++++++++++++++++++++++++++
 src/io/memory.cr                | 34 +++++++++++++++++++---------
 src/string/builder.cr           | 38 ++++++++++++++++++++++----------
 4 files changed, 122 insertions(+), 22 deletions(-)

diff --git a/spec/std/io/memory_spec.cr b/spec/std/io/memory_spec.cr
index 37ff01e3421d..7d51c09483ed 100644
--- a/spec/std/io/memory_spec.cr
+++ b/spec/std/io/memory_spec.cr
@@ -18,6 +18,17 @@ describe IO::Memory do
     io.gets_to_end.should eq(s)
   end
 
+  it "write raises EOFError" do
+    io = IO::Memory.new
+    initial_capacity = io.@capacity
+    expect_raises(IO::EOFError) do
+      io.write Slice.new(Pointer(UInt8).null, Int32::MAX)
+    end
+    # nothing get's written
+    io.bytesize.should eq 0
+    io.@capacity.should eq initial_capacity
+  end
+
   it "reads byte" do
     io = IO::Memory.new("abc")
     io.read_byte.should eq('a'.ord)
@@ -494,4 +505,26 @@ describe IO::Memory do
       end
     end
   {% end %}
+
+  it "allocates for > 1 GB", tags: %w[slow] do
+    io = IO::Memory.new
+    mbstring = "a" * 1024 * 1024
+    1024.times { io << mbstring }
+
+    io.bytesize.should eq(1 << 30)
+    io.@capacity.should eq 1 << 30
+
+    io << mbstring
+
+    io.bytesize.should eq (1 << 30) + (1 << 20)
+    io.@capacity.should eq Int32::MAX
+
+    1022.times { io << mbstring }
+
+    io.write mbstring.to_slice[0..-4]
+    io << "a"
+    expect_raises(IO::EOFError) do
+      io << "a"
+    end
+  end
 end
diff --git a/spec/std/string_builder_spec.cr b/spec/std/string_builder_spec.cr
index 2b5f62c6c03c..250a4b0239f2 100644
--- a/spec/std/string_builder_spec.cr
+++ b/spec/std/string_builder_spec.cr
@@ -40,4 +40,43 @@ describe String::Builder do
       str.chomp!(44).to_s.should eq("a,b,c")
     end
   end
+
+  it "raises EOFError" do
+    builder = String::Builder.new
+    initial_capacity = builder.capacity
+    expect_raises(IO::EOFError) do
+      builder.write Slice.new(Pointer(UInt8).null, Int32::MAX)
+    end
+    # nothing get's written
+    builder.bytesize.should eq 0
+    builder.capacity.should eq initial_capacity
+  end
+
+  # FIXME(wasm32): https://github.com/crystal-lang/crystal/issues/14057
+  {% if flag?(:wasm32) %}
+    pending "allocation for > 1 GB"
+  {% else %}
+    it "allocates for > 1 GB", tags: %w[slow] do
+      String::Builder.build do |str|
+        mbstring = "a" * 1024 * 1024
+        1023.times { str << mbstring }
+
+        str.bytesize.should eq (1 << 30) - (1 << 20)
+        str.capacity.should eq 1 << 30
+
+        str << mbstring
+
+        str.bytesize.should eq 1 << 30
+        str.capacity.should eq Int32::MAX
+
+        1023.times { str << mbstring }
+
+        str.write mbstring.to_slice[0..(-4 - String::HEADER_SIZE)]
+        str << "a"
+        expect_raises(IO::EOFError) do
+          str << "a"
+        end
+      end
+    end
+  {% end %}
 end
diff --git a/src/io/memory.cr b/src/io/memory.cr
index d0b925df1d70..bd486f0cbdc2 100644
--- a/src/io/memory.cr
+++ b/src/io/memory.cr
@@ -90,11 +90,7 @@ class IO::Memory < IO
 
     return if count == 0
 
-    new_bytesize = @pos + count
-    if new_bytesize > @capacity
-      check_resizeable
-      resize_to_capacity(Math.pw2ceil(new_bytesize))
-    end
+    increase_capacity_by(count)
 
     slice.copy_to(@buffer + @pos, count)
 
@@ -112,11 +108,7 @@ class IO::Memory < IO
     check_writeable
     check_open
 
-    new_bytesize = @pos + 1
-    if new_bytesize > @capacity
-      check_resizeable
-      resize_to_capacity(Math.pw2ceil(new_bytesize))
-    end
+    increase_capacity_by(1)
 
     (@buffer + @pos).value = byte
 
@@ -458,6 +450,28 @@ class IO::Memory < IO
     end
   end
 
+  private def increase_capacity_by(count)
+    raise IO::EOFError.new if count >= Int32::MAX - bytesize
+
+    new_bytesize = @pos + count
+    return if new_bytesize <= @capacity
+
+    check_resizeable
+
+    new_capacity = calculate_new_capacity(new_bytesize)
+    resize_to_capacity(new_capacity)
+  end
+
+  private def calculate_new_capacity(new_bytesize : Int32)
+    # If the new bytesize is bigger than 1 << 30, the next power of two would
+    # be 1 << 31, which is out of range for Int32.
+    # So we limit the capacity to Int32::MAX in order to be able to use the
+    # range (1 << 30) < new_bytesize < Int32::MAX
+    return Int32::MAX if new_bytesize > 1 << 30
+
+    Math.pw2ceil(new_bytesize)
+  end
+
   private def resize_to_capacity(capacity)
     @capacity = capacity
     @buffer = GC.realloc(@buffer, @capacity)
diff --git a/src/string/builder.cr b/src/string/builder.cr
index 0fb77f4ca41b..a06644b831d1 100644
--- a/src/string/builder.cr
+++ b/src/string/builder.cr
@@ -41,21 +41,14 @@ class String::Builder < IO
     return if slice.empty?
 
     count = slice.size
-    new_bytesize = real_bytesize + count
-    if new_bytesize > @capacity
-      resize_to_capacity(Math.pw2ceil(new_bytesize))
-    end
 
+    increase_capacity_by count
     slice.copy_to(@buffer + real_bytesize, count)
     @bytesize += count
   end
 
   def write_byte(byte : UInt8) : Nil
-    new_bytesize = real_bytesize + 1
-    if new_bytesize > @capacity
-      resize_to_capacity(Math.pw2ceil(new_bytesize))
-    end
-
+    increase_capacity_by 1
     @buffer[real_bytesize] = byte
 
     @bytesize += 1
@@ -108,17 +101,18 @@ class String::Builder < IO
     raise "Can only invoke 'to_s' once on String::Builder" if @finished
     @finished = true
 
-    write_byte 0_u8
+    real_bytesize = real_bytesize()
+    @buffer[real_bytesize] = 0_u8
+    real_bytesize += 1
 
     # Try to reclaim some memory if capacity is bigger than what we need
-    real_bytesize = real_bytesize()
     if @capacity > real_bytesize
       resize_to_capacity(real_bytesize)
     end
 
     String.set_crystal_type_id(@buffer)
     str = @buffer.as(String)
-    str.initialize_header((bytesize - 1).to_i)
+    str.initialize_header(bytesize)
     str
   end
 
@@ -126,6 +120,26 @@ class String::Builder < IO
     @bytesize + String::HEADER_SIZE
   end
 
+  private def increase_capacity_by(count)
+    raise IO::EOFError.new if count >= Int32::MAX - real_bytesize
+
+    new_bytesize = real_bytesize + count
+    return if new_bytesize <= @capacity
+
+    new_capacity = calculate_new_capacity(new_bytesize)
+    resize_to_capacity(new_capacity)
+  end
+
+  private def calculate_new_capacity(new_bytesize)
+    # If the new bytesize is bigger than 1 << 30, the next power of two would
+    # be 1 << 31, which is out of range for Int32.
+    # So we limit the capacity to Int32::MAX in order to be able to use the
+    # range (1 << 30) < new_bytesize < Int32::MAX
+    return Int32::MAX if new_bytesize > 1 << 30
+
+    Math.pw2ceil(new_bytesize)
+  end
+
   private def resize_to_capacity(capacity)
     @capacity = capacity
     @buffer = GC.realloc(@buffer, @capacity)

From 7df0b2e9d0b1c735ebc9d30e903fa037f297538c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Sat, 6 Jan 2024 23:03:39 +0100
Subject: [PATCH 036/105] Fix OpenSSL error handling for EOF (support for
 OpenSSL 3.2) (#14169)

Co-authored-by: Beta Ziliani <beta@manas.tech>
---
 spec/std/openssl/ssl/socket_spec.cr |  8 +++++++-
 src/openssl.cr                      | 11 +++++------
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/spec/std/openssl/ssl/socket_spec.cr b/spec/std/openssl/ssl/socket_spec.cr
index ccf1046b6949..bbc5b11e4b9b 100644
--- a/spec/std/openssl/ssl/socket_spec.cr
+++ b/spec/std/openssl/ssl/socket_spec.cr
@@ -160,20 +160,26 @@ describe OpenSSL::SSL::Socket do
     server_context, client_context = ssl_context_pair
     server_context.disable_session_resume_tickets # avoid Broken pipe
 
-    server_finished_reading = Channel(String).new
+    server_finished_reading = Channel(String | Exception).new
     spawn do
       OpenSSL::SSL::Server.open(tcp_server, server_context, sync_close: true) do |server|
         server_socket = server.accept
         received = server_socket.gets_to_end # interprets underlying socket close as a graceful EOF
         server_finished_reading.send(received)
       end
+    rescue exc
+      server_finished_reading.send exc
     end
+
     socket = TCPSocket.new(tcp_server.local_address.address, tcp_server.local_address.port)
     socket_ssl = OpenSSL::SSL::Socket::Client.new(socket, client_context, hostname: "example.com", sync_close: true)
     socket_ssl.print "hello"
     socket_ssl.flush # needed today see #5375
     socket.close     # close underlying socket without gracefully shutting down SSL at all
     server_received = server_finished_reading.receive
+    if server_received.is_a?(Exception)
+      raise server_received
+    end
     server_received.should eq("hello")
   end
 end
diff --git a/src/openssl.cr b/src/openssl.cr
index 802c9a05e7d3..f34ee169b4cc 100644
--- a/src/openssl.cr
+++ b/src/openssl.cr
@@ -89,15 +89,14 @@ module OpenSSL
         when .syscall?
           @code, message = fetch_error_details
           if @code == 0
-            case return_code
-            when 0
+            errno = {% if flag?(:win32) %} WinError.wsa_value {% else %} Errno.value {% end %}
+            success = {% if flag?(:win32) %} errno.error_success? {% else %} errno.none? {% end %}
+            if success
               message = "Unexpected EOF"
               @underlying_eof = true
-            when -1
-              cause = RuntimeError.from_errno(func || "OpenSSL")
-              message = "I/O error"
             else
-              message = "Unknown error"
+              cause = RuntimeError.from_os_error(func || "OpenSSL", os_error: errno)
+              message = "I/O error"
             end
           end
         when .ssl?

From 2140607a289133926ce5edf8215252d0464fdf20 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Mon, 8 Jan 2024 12:34:08 +0100
Subject: [PATCH 037/105] Fix `options` parameter for `String#split`, `#scan`
 (#14183)

---
 spec/std/string_spec.cr | 5 +++++
 src/string.cr           | 2 --
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/spec/std/string_spec.cr b/spec/std/string_spec.cr
index 0d60b3ac2466..ebebcd2c6561 100644
--- a/spec/std/string_spec.cr
+++ b/spec/std/string_spec.cr
@@ -1416,6 +1416,7 @@ describe "String" do
       it { "=".split(/\=/, 2).should eq(["", ""]) }
       it { "=".split(/\=/, 2, remove_empty: true).should eq([] of String) }
       it { ",".split(/(?:(x)|(,))/).should eq(["", ",", ""]) }
+      it { "ba".split(/a/, options: :anchored).should eq ["ba"] }
 
       it "keeps groups" do
         s = "split on the word on okay?"
@@ -2322,6 +2323,10 @@ describe "String" do
     it "does with number and string" do
       "1ab4".scan(/\d+/).map(&.[0]).should eq(["1", "4"])
     end
+
+    it "options parameter" do
+      "ba".scan(/a/, options: :anchored).map(&.[0]).should eq [] of String
+    end
   end
 
   it "has match" do
diff --git a/src/string.cr b/src/string.cr
index 98b7ec3884fd..4004f0d34929 100644
--- a/src/string.cr
+++ b/src/string.cr
@@ -4198,7 +4198,6 @@ class String
     count = 0
     match_offset = slice_offset = 0
 
-    options = Regex::MatchOptions::None
     while match = separator.match_at_byte_index(self, match_offset, options: options)
       index = match.byte_begin(0)
       match_bytesize = match.byte_end(0) - index
@@ -4744,7 +4743,6 @@ class String
   def scan(pattern : Regex, *, options : Regex::MatchOptions = Regex::MatchOptions::None, &) : self
     byte_offset = 0
 
-    options = Regex::MatchOptions::None
     while match = pattern.match_at_byte_index(self, byte_offset, options: options)
       index = match.byte_begin(0)
       $~ = match

From 95d04fab447c48d7cb94f5937e52f6556e3ff858 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Mon, 8 Jan 2024 21:05:33 +0100
Subject: [PATCH 038/105] Changelog for 1.11.0 (#14158)

---
 CHANGELOG.md | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/VERSION  |   2 +-
 2 files changed, 257 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d2c17878c9d..1bedb4a96a97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,261 @@
 # Changelog
 
+## [1.11.0] (2024-01-08)
+
+[1.11.0]: https://github.com/crystal-lang/crystal/releases/1.11.0
+
+### Features
+
+#### lang
+
+- **[breaking]** Support `alignof` and `instance_alignof` ([#14087](https://github.com/crystal-lang/crystal/pull/14087), thanks @HertzDevil)
+- *(annotations)* Support `dll` parameter in `@[Link]` ([#14131](https://github.com/crystal-lang/crystal/pull/14131), thanks @HertzDevil)
+- *(macros)* Expose macro `Call` context via new `@caller` macro ivar ([#14048](https://github.com/crystal-lang/crystal/pull/14048), thanks @Blacksmoke16)
+
+#### stdlib
+
+- *(collection)* Add `Enumerable#present?` ([#13866](https://github.com/crystal-lang/crystal/pull/13866), thanks @straight-shoota)
+- *(collection)* Add `Enumerable#each_step` and `Iterable#each_step` ([#13610](https://github.com/crystal-lang/crystal/pull/13610), thanks @baseballlover723)
+- *(collection)* Add `Enumerable(T)#to_set(& : T -> U) : Set(U) forall U` ([#12654](https://github.com/crystal-lang/crystal/pull/12654), thanks @caspiano)
+- *(collection)* Add `Enumerable(T)#to_a(& : T -> U) forall U` ([#12653](https://github.com/crystal-lang/crystal/pull/12653), thanks @caspiano)
+- *(files)* Add `IO::Error#target` ([#13865](https://github.com/crystal-lang/crystal/pull/13865), thanks @straight-shoota)
+- *(llvm)* Add `LLVM::OperandBundleDef#dispose` ([#14095](https://github.com/crystal-lang/crystal/pull/14095), thanks @HertzDevil)
+- *(llvm)* Windows: Use local configuration for LLVM when linking dynamically ([#14101](https://github.com/crystal-lang/crystal/pull/14101), thanks @HertzDevil)
+- *(macros)* Add `CharLiteral#ord` ([#13910](https://github.com/crystal-lang/crystal/pull/13910), thanks @refi64)
+- *(macros)* Add macro methods for `MacroIf` and `MacroFor` nodes ([#13902](https://github.com/crystal-lang/crystal/pull/13902), thanks @sbsoftware)
+- *(macros)* Expose doc comments on `ASTNode` when generating docs ([#14050](https://github.com/crystal-lang/crystal/pull/14050), thanks @Blacksmoke16)
+- *(macros)* Add macro methods for `ModuleDef` ([#14063](https://github.com/crystal-lang/crystal/pull/14063), thanks @HertzDevil)
+- *(macros)* Add macro methods for `Include` and `Extend` ([#14064](https://github.com/crystal-lang/crystal/pull/14064), thanks @HertzDevil)
+- *(macros)* Add macro methods for `ClassDef`, `EnumDef`, `AnnotationDef` ([#14072](https://github.com/crystal-lang/crystal/pull/14072), thanks @HertzDevil)
+- *(numeric)* Implement `BigRational`'s rounding modes ([#13871](https://github.com/crystal-lang/crystal/pull/13871), thanks @HertzDevil)
+- *(numeric)* Support full exponent range in `BigFloat#**(BigInt)` ([#13881](https://github.com/crystal-lang/crystal/pull/13881), thanks @HertzDevil)
+- *(numeric)* Add `Math.fma` ([#13934](https://github.com/crystal-lang/crystal/pull/13934), thanks @HertzDevil)
+- *(numeric)* Add `Number#integer?` ([#13936](https://github.com/crystal-lang/crystal/pull/13936), thanks @HertzDevil)
+- *(numeric)* Publish `Int::Primitive#abs_unsigned` and `#neg_signed` ([#13938](https://github.com/crystal-lang/crystal/pull/13938), thanks @HertzDevil)
+- *(numeric)* Add `Int::Primitive#to_signed`, `#to_signed!`, `#to_unsigned`, `#to_unsigned!` ([#13960](https://github.com/crystal-lang/crystal/pull/13960), thanks @HertzDevil)
+- *(numeric)* Support `BigFloat#**` for all `Int::Primitive` arguments ([#13971](https://github.com/crystal-lang/crystal/pull/13971), thanks @HertzDevil)
+- *(numeric)* Add `Float32::MIN_SUBNORMAL` and `Float64::MIN_SUBNORMAL` ([#13961](https://github.com/crystal-lang/crystal/pull/13961), thanks @HertzDevil)
+- *(numeric)* Add `Float::Primitive.parse_hexfloat`, `.parse_hexfloat?`, `#to_hexfloat` ([#14027](https://github.com/crystal-lang/crystal/pull/14027), thanks @HertzDevil)
+- *(numeric)* Implement `sprintf "%f"` in Crystal using Ryu Printf ([#14067](https://github.com/crystal-lang/crystal/pull/14067), thanks @HertzDevil)
+- *(numeric)* Implement `sprintf "%e"` in Crystal ([#14084](https://github.com/crystal-lang/crystal/pull/14084), thanks @HertzDevil)
+- *(numeric)* Implement `sprintf "%a"` in Crystal ([#14102](https://github.com/crystal-lang/crystal/pull/14102), thanks @HertzDevil)
+- *(numeric)* Implement `sprintf "%g"` in Crystal ([#14123](https://github.com/crystal-lang/crystal/pull/14123), thanks @HertzDevil)
+- *(runtime)* Add `Crystal::HOST_TRIPLE` and `TARGET_TRIPLE` ([#13823](https://github.com/crystal-lang/crystal/pull/13823), thanks @HertzDevil)
+- *(runtime)* **[experimental]** Add `Reference.pre_initialize` and `.unsafe_construct` ([#14108](https://github.com/crystal-lang/crystal/pull/14108), thanks @HertzDevil)
+- *(runtime)* **[experimental]** Add `ReferenceStorage` for manual allocation of references ([#14106](https://github.com/crystal-lang/crystal/pull/14106), thanks @HertzDevil)
+- *(serialization)* Fix `StaticArray#to_json` ([#14104](https://github.com/crystal-lang/crystal/pull/14104), thanks @Vendicated)
+- *(specs)* Add `crystal spec --dry-run` ([#13804](https://github.com/crystal-lang/crystal/pull/13804), thanks @nobodywasishere)
+- *(specs)* Add `crystal spec --list-tags` ([#13616](https://github.com/crystal-lang/crystal/pull/13616), thanks @baseballlover723)
+- *(system)* Respect Windows `Path` directory separators in `File.match?` ([#13912](https://github.com/crystal-lang/crystal/pull/13912), thanks @HertzDevil)
+- *(text)* Support Unicode 15.1.0 ([#13812](https://github.com/crystal-lang/crystal/pull/13812), thanks @HertzDevil)
+- *(text)* Add `UUID.v1`, `.v2`, `.v3`, `.v4`, `.v5` ([#13693](https://github.com/crystal-lang/crystal/pull/13693), thanks @threez)
+- *(text)* Add `String` and `Char` patterns to `StringScanner` ([#13806](https://github.com/crystal-lang/crystal/pull/13806), thanks @funny-falcon)
+- *(text)* Add `EOL`constant (End-Of-Line) ([#11303](https://github.com/crystal-lang/crystal/pull/11303), thanks @postmodern)
+- *(text)* Add `Char::Reader#current_char?`, `#next_char?`, `#previous_char?` ([#14012](https://github.com/crystal-lang/crystal/pull/14012), thanks @HertzDevil)
+- *(text)* Add `String#matches_full?` ([#13968](https://github.com/crystal-lang/crystal/pull/13968), thanks @straight-shoota)
+- *(text)* Change `Regex::MatchData#to_s` to return matched substring ([#14115](https://github.com/crystal-lang/crystal/pull/14115), thanks @Vendicated)
+
+#### compiler
+
+- *(codegen)* Add incremental optimization levels ([#13464](https://github.com/crystal-lang/crystal/pull/13464), thanks @kostya)
+- *(debugger)* Support debug information for 64-bit or unsigned enums ([#14081](https://github.com/crystal-lang/crystal/pull/14081), thanks @HertzDevil)
+- *(interpreter)* Support `instance_sizeof(T)` in the interpreter ([#14031](https://github.com/crystal-lang/crystal/pull/14031), thanks @HertzDevil)
+- *(interpreter)* Support `-dynamic.lib` in Windows interpreter ([#14143](https://github.com/crystal-lang/crystal/pull/14143), thanks @HertzDevil)
+- *(interpreter)* Support absolute paths in `CRYSTAL_INTERPRETER_LOADER_INFO` ([#14147](https://github.com/crystal-lang/crystal/pull/14147), thanks @HertzDevil)
+- *(interpreter)* Add `Crystal::Repl#parse_and_interpret` ([#14138](https://github.com/crystal-lang/crystal/pull/14138), thanks @bcardiff)
+- *(semantic)* Change short_reference for top-level methods to `::foo` ([#14071](https://github.com/crystal-lang/crystal/pull/14071), thanks @keshavbiswa)
+
+#### tools
+
+- *(docs-generator)* Expose inherited macros in generated API docs ([#13810](https://github.com/crystal-lang/crystal/pull/13810), thanks @Blacksmoke16)
+- *(docs-generator)* Order macros below class methods in generated docs ([#14024](https://github.com/crystal-lang/crystal/pull/14024), thanks @Blacksmoke16)
+- *(formatter)* Do not remove trailing comma from multi-line macro/def parameters (not yet enabled) ([#14075](https://github.com/crystal-lang/crystal/pull/14075), thanks @Blacksmoke16)
+- *(unreachable)* Add `--check` flag to `crystal tool unreachable` ([#13930](https://github.com/crystal-lang/crystal/pull/13930), thanks @straight-shoota)
+- *(unreachable)* Add annotations to output of `crystal tool unreachable` ([#13927](https://github.com/crystal-lang/crystal/pull/13927), thanks @straight-shoota)
+- *(unreachable)* Print relative paths in `crystal tool unreachable` ([#13929](https://github.com/crystal-lang/crystal/pull/13929), thanks @straight-shoota)
+- *(unreachable)* Add CSV output format to `crystal tool unreachable` ([#13926](https://github.com/crystal-lang/crystal/pull/13926), thanks @straight-shoota)
+- *(unreachable)* Add `--tallies` option to `crystal tool unreachable` ([#13969](https://github.com/crystal-lang/crystal/pull/13969), thanks @straight-shoota)
+
+### Bugfixes
+
+#### stdlib
+
+- Fix `Box(T?)` crashing on `nil` ([#13893](https://github.com/crystal-lang/crystal/pull/13893), thanks @HertzDevil)
+- Fix typos in src ([#14053](https://github.com/crystal-lang/crystal/pull/14053), thanks @kojix2)
+- *(collection)* Fix `Indexable#each_repeated_combination(n)` when `n > size` ([#14092](https://github.com/crystal-lang/crystal/pull/14092), thanks @HertzDevil)
+- *(concurrency)* Make `Process#wait` asynchronous on Windows ([#13908](https://github.com/crystal-lang/crystal/pull/13908), thanks @HertzDevil)
+- *(concurrency)* Fix math overflow after spawning `Int32::MAX + 1` fibers ([#14096](https://github.com/crystal-lang/crystal/pull/14096), thanks @ysbaddaden)
+- *(concurrency)* Fix `can't resume a running fiber` ([#14128](https://github.com/crystal-lang/crystal/pull/14128), thanks @ysbaddaden)
+- *(crypto)* Fix OpenSSL error handling for EOF (support for OpenSSL 3.2) ([#14169](https://github.com/crystal-lang/crystal/pull/14169), thanks @straight-shoota)
+- *(files)* Fix `Globber.constant_entry?` matching patterns ([#13955](https://github.com/crystal-lang/crystal/pull/13955), thanks @GeopJr)
+- *(files)* Fix `String::Buffer` and `IO::Memory` capacity to grow beyond 1GB ([#13989](https://github.com/crystal-lang/crystal/pull/13989), thanks @straight-shoota)
+- *(llvm)* Fix a typo ([#13914](https://github.com/crystal-lang/crystal/pull/13914), thanks @kojix2)
+- *(numeric)* Make `String#to_f(whitespace: false)` work with infinity and NaN ([#13875](https://github.com/crystal-lang/crystal/pull/13875), thanks @HertzDevil)
+- *(numeric)* Use `LibGMP::SI` and `UI` for size checks, not `Long` and `ULong` ([#13874](https://github.com/crystal-lang/crystal/pull/13874), thanks @HertzDevil)
+- *(numeric)* Fix integral part extraction in `Number#format` ([#14061](https://github.com/crystal-lang/crystal/pull/14061), thanks @HertzDevil)
+- *(numeric)* Fix out-of-bounds access in `Int128::MIN.to_s(base: 2)` ([#14119](https://github.com/crystal-lang/crystal/pull/14119), thanks @HertzDevil)
+- *(numeric)* Avoid double rounding in `Float#format` for nonnegative `decimal_place` ([#14129](https://github.com/crystal-lang/crystal/pull/14129), thanks @HertzDevil)
+- *(runtime)* Avoid `@[ThreadLocal]` on Android ([#14025](https://github.com/crystal-lang/crystal/pull/14025), thanks @HertzDevil)
+- *(runtime)* Never use string interpolation in `Crystal::System.print_error` ([#14114](https://github.com/crystal-lang/crystal/pull/14114), thanks @HertzDevil)
+- *(runtime)* Fix segfault with next boehm gc (after v8.2.4) ([#14130](https://github.com/crystal-lang/crystal/pull/14130), thanks @ysbaddaden)
+- *(specs)* Skip spec execution on error exit ([#13986](https://github.com/crystal-lang/crystal/pull/13986), thanks @straight-shoota)
+- *(system)* Fix `FileUtils.ln_sf` to override special file types ([#13896](https://github.com/crystal-lang/crystal/pull/13896), thanks @straight-shoota)
+- *(system)* Fix `Process.exists?` throwing errors on EPERM ([#13911](https://github.com/crystal-lang/crystal/pull/13911), thanks @refi64)
+- *(system)* Fix portable shell command arguments in `Process#prepare_args` ([#13942](https://github.com/crystal-lang/crystal/pull/13942), thanks @GeopJr)
+- *(system)* Windows: Do not close process handle in `Process#close` ([#13997](https://github.com/crystal-lang/crystal/pull/13997), thanks @HertzDevil)
+- *(system)* Windows: clear `Crystal::System::Process#@completion_key` after use ([#14068](https://github.com/crystal-lang/crystal/pull/14068), thanks @HertzDevil)
+- *(system)* Fix UTF-8 console input on Windows ([#13758](https://github.com/crystal-lang/crystal/pull/13758), thanks @erdian718)
+- *(text)* Fix invalid UTF-8 handling in `Char::Reader#previous_char` ([#14013](https://github.com/crystal-lang/crystal/pull/14013), thanks @HertzDevil)
+- *(text)* Fix `options` parameter for `String#split`, `#scan` ([#14183](https://github.com/crystal-lang/crystal/pull/14183), thanks @straight-shoota)
+- *(time)* Fix time span overflow on `Int#milliseconds` and `Int#microseconds` ([#14105](https://github.com/crystal-lang/crystal/pull/14105), thanks @bcardiff)
+
+#### compiler
+
+- *(cli)* Remove unnecessary file check for CLI arguments ([#13853](https://github.com/crystal-lang/crystal/pull/13853), thanks @straight-shoota)
+- *(cli)* Check for invalid integers in compiler's CLI ([#13959](https://github.com/crystal-lang/crystal/pull/13959), thanks @HertzDevil)
+- *(cli)* Fix compiler error message for invalid source file ([#14157](https://github.com/crystal-lang/crystal/pull/14157), thanks @straight-shoota)
+- *(codegen)* Fix a typo in compiler source ([#14054](https://github.com/crystal-lang/crystal/pull/14054), thanks @kojix2)
+- *(codegen)* Fix codegen error when discarding `is_a?` or `responds_to?`'s result ([#14148](https://github.com/crystal-lang/crystal/pull/14148), thanks @HertzDevil)
+- *(interpreter)* Fix element alignment of `Tuple` and `NamedTuple` casts ([#14040](https://github.com/crystal-lang/crystal/pull/14040), thanks @HertzDevil)
+- *(interpreter)* `Crystal::Loader`: Skip second linker member on Windows if absent ([#14111](https://github.com/crystal-lang/crystal/pull/14111), thanks @HertzDevil)
+- *(parser)* Support `%r` and `%x` when not followed by delimiter start ([#13933](https://github.com/crystal-lang/crystal/pull/13933), thanks @HertzDevil)
+- *(parser)* Fix location of global `Path` nodes in certain constructs ([#13932](https://github.com/crystal-lang/crystal/pull/13932), thanks @HertzDevil)
+- *(parser)* Fix `ToSVisitor` for expanded string interpolation in backticks ([#13943](https://github.com/crystal-lang/crystal/pull/13943), thanks @straight-shoota)
+- *(parser)* Fix location for "invalid trailing comma in call" errors ([#13964](https://github.com/crystal-lang/crystal/pull/13964), thanks @HertzDevil)
+- *(semantic)* Fix check for file type ([#13760](https://github.com/crystal-lang/crystal/pull/13760), thanks @straight-shoota)
+- *(semantic)* Fix private type definitions with namespaced `Path`s ([#13931](https://github.com/crystal-lang/crystal/pull/13931), thanks @HertzDevil)
+- *(semantic)* Fix missing param count in compilation error message ([#13985](https://github.com/crystal-lang/crystal/pull/13985), thanks @koffeinfrei)
+- *(semantic)* Fix `ReadInstanceVar` on typedefs ([#14044](https://github.com/crystal-lang/crystal/pull/14044), thanks @HertzDevil)
+- *(semantic)* Fix global `Path` lookup inside macro when def has free variables ([#14073](https://github.com/crystal-lang/crystal/pull/14073), thanks @HertzDevil)
+- *(semantic)* Add location information to implicit flag enum members ([#14127](https://github.com/crystal-lang/crystal/pull/14127), thanks @Blacksmoke16)
+
+#### tools
+
+- *(docs-generator)* Fix `crystal docs` check `File.exists?` for `shard.yml` ([#13937](https://github.com/crystal-lang/crystal/pull/13937), thanks @straight-shoota)
+- *(docs-generator)* Fix version sorting in API docs ([#13994](https://github.com/crystal-lang/crystal/pull/13994), thanks @m-o-e)
+- *(docs-generator)* Strip whitespace in doc comment before determining summary line ([#14049](https://github.com/crystal-lang/crystal/pull/14049), thanks @Blacksmoke16)
+- *(docs-generator)* Skip `Crystal::Macros` unless generating docs ([#13970](https://github.com/crystal-lang/crystal/pull/13970), thanks @straight-shoota)
+- *(init)* Fix tool init error message when target exists but not a dir ([#13869](https://github.com/crystal-lang/crystal/pull/13869), thanks @straight-shoota)
+- *(unreachable)* Fix infinite recursion of expanded nodes in `UnreachableVisitor` ([#13922](https://github.com/crystal-lang/crystal/pull/13922), thanks @straight-shoota)
+
+### Chores
+
+#### lang
+
+- *(macros)* **[deprecation]** Deprecate the splat operators in macro expressions ([#13939](https://github.com/crystal-lang/crystal/pull/13939), thanks @HertzDevil)
+
+#### stdlib
+
+- *(llvm)* **[deprecation]** Deprecate `LLVM.start_multithreaded` and `.stop_multithreaded` ([#13949](https://github.com/crystal-lang/crystal/pull/13949), thanks @HertzDevil)
+
+### Performance
+
+#### stdlib
+
+- *(concurrency)* Skip indirections in `Crystal::Scheduler` ([#14098](https://github.com/crystal-lang/crystal/pull/14098), thanks @ysbaddaden)
+- *(numeric)* Optimize `BigInt#&`, `#|`, `#^` with `Int::Primitive` arguments ([#14006](https://github.com/crystal-lang/crystal/pull/14006), thanks @HertzDevil)
+- *(numeric)* Optimize `BigInt#bit` ([#13980](https://github.com/crystal-lang/crystal/pull/13980), thanks @HertzDevil)
+- *(numeric)* Use `#trailing_zeros_count` in `Int#gcd` ([#14069](https://github.com/crystal-lang/crystal/pull/14069), thanks @HertzDevil)
+- *(serialization)* Optimize `JSON::Builder#string` with byte-based algorithm ([#13915](https://github.com/crystal-lang/crystal/pull/13915), thanks @straight-shoota)
+- *(serialization)* Improve performance of `JSON::Builder#string` with direct stringification ([#13950](https://github.com/crystal-lang/crystal/pull/13950), thanks @straight-shoota)
+- *(text)* Refactor `HTML.unescape` in native Crystal ([#13844](https://github.com/crystal-lang/crystal/pull/13844), thanks @straight-shoota)
+- *(text)* Refactor some uses of the blockless `String#split` ([#14001](https://github.com/crystal-lang/crystal/pull/14001), thanks @HertzDevil)
+
+### Refactor
+
+#### stdlib
+
+- *(concurrency)* Add `Crystal::System::Thread` ([#13814](https://github.com/crystal-lang/crystal/pull/13814), thanks @HertzDevil)
+- *(concurrency)* Move `Thread#set_current_thread` to `Fiber` ([#14099](https://github.com/crystal-lang/crystal/pull/14099), thanks @ysbaddaden)
+- *(files)* Use `IO.copy` in `IO#gets_to_end` ([#13990](https://github.com/crystal-lang/crystal/pull/13990), thanks @straight-shoota)
+- *(files)* Do not use `pointerof(Path)` in the standard library ([#14144](https://github.com/crystal-lang/crystal/pull/14144), thanks @HertzDevil)
+- *(llvm)* **[deprecation]** Remove `LLVMExtSetCurrentDebugLocation` from `llvm_ext.cc` for LLVM 9+ ([#13965](https://github.com/crystal-lang/crystal/pull/13965), thanks @HertzDevil)
+- *(llvm)* Replace some deprecated LLVM bindings ([#13953](https://github.com/crystal-lang/crystal/pull/13953), thanks @HertzDevil)
+- *(llvm)* Split `LibLLVM` by C headers ([#13948](https://github.com/crystal-lang/crystal/pull/13948), thanks @HertzDevil)
+- *(llvm)* Support `LLVMSetTargetMachineGlobalISel` from LLVM 18 ([#14079](https://github.com/crystal-lang/crystal/pull/14079), thanks @HertzDevil)
+- *(llvm)* Support the operand bundle API from LLVM 18 ([#14082](https://github.com/crystal-lang/crystal/pull/14082), thanks @HertzDevil)
+- *(numeric)* Simplify `String::Formatter` when Ryu Printf is available ([#14132](https://github.com/crystal-lang/crystal/pull/14132), thanks @HertzDevil)
+- *(runtime)* Implement most of `Crystal::System.print_error` in native Crystal ([#14116](https://github.com/crystal-lang/crystal/pull/14116), thanks @HertzDevil)
+- *(text)* Drop `Char::Reader#@end` ([#13920](https://github.com/crystal-lang/crystal/pull/13920), thanks @straight-shoota)
+- *(text)* Generate `src/html/entities.cr` automatically ([#13998](https://github.com/crystal-lang/crystal/pull/13998), thanks @HertzDevil)
+- *(time)* Refactor leap year to use `divisible_by?` ([#13982](https://github.com/crystal-lang/crystal/pull/13982), thanks @meatball133)
+
+#### compiler
+
+- Remove relative path to vendored shards `markd` and `reply` ([#13992](https://github.com/crystal-lang/crystal/pull/13992), thanks @nobodywasishere)
+- *(cli)* Generalize allowed values for compiler CLI `--format` option ([#13940](https://github.com/crystal-lang/crystal/pull/13940), thanks @straight-shoota)
+- *(parser)* Use `Char#to_i?` in lexer ([#13841](https://github.com/crystal-lang/crystal/pull/13841), thanks @straight-shoota)
+
+#### tools
+
+- *(unreachable)* Refactor `UnreachablePresenter` ([#13941](https://github.com/crystal-lang/crystal/pull/13941), thanks @straight-shoota)
+
+### Documentation
+
+#### lang
+
+- *(macros)* Add reference to book how merging macro expansion and call docs ([#14139](https://github.com/crystal-lang/crystal/pull/14139), thanks @Blacksmoke16)
+
+#### stdlib
+
+- *(collection)* Fix documentation of `Hash#put_if_absent` ([#13898](https://github.com/crystal-lang/crystal/pull/13898), thanks @ilmanzo)
+- *(collection)* Improve docs on initial/default values passed to `Array.new` and `Hash.new` ([#13962](https://github.com/crystal-lang/crystal/pull/13962), thanks @straight-shoota)
+- *(collection)* Improve docs for `Iterator` step-by-step iteration ([#13967](https://github.com/crystal-lang/crystal/pull/13967), thanks @straight-shoota)
+- *(macros)* Document `Crystal::Macros::MagicConstant` ([#14070](https://github.com/crystal-lang/crystal/pull/14070), thanks @HertzDevil)
+- *(serialization)* Add docs and explicit type restriction for indent parameter of `JSON.build` ([#14140](https://github.com/crystal-lang/crystal/pull/14140), thanks @syeopite)
+- *(text)* Add note about `Char::Reader`'s value semantics ([#14008](https://github.com/crystal-lang/crystal/pull/14008), thanks @HertzDevil)
+- *(text)* Fix documentation for `String#index!` ([#14038](https://github.com/crystal-lang/crystal/pull/14038), thanks @gettalong)
+
+#### compiler
+
+- *(cli)* Add optimization levels to manpage ([#14162](https://github.com/crystal-lang/crystal/pull/14162), thanks @straight-shoota)
+- *(cli)* Add `unreachable` options to manpage ([#14164](https://github.com/crystal-lang/crystal/pull/14164), thanks @straight-shoota)
+- *(cli)* Fix formatting in manpage ([#14163](https://github.com/crystal-lang/crystal/pull/14163), thanks @straight-shoota)
+
+### Specs
+
+#### stdlib
+
+- Add `pending_wasm32` ([#14086](https://github.com/crystal-lang/crystal/pull/14086), thanks @HertzDevil)
+- *(concurrency)* Workaround regular timeouts in `HTTP::Server` specs with MT ([#14097](https://github.com/crystal-lang/crystal/pull/14097), thanks @ysbaddaden)
+- *(files)* Fix `File::AccessDeniedError` expectations in `File` specs ([#14029](https://github.com/crystal-lang/crystal/pull/14029), thanks @HertzDevil)
+- *(text)* Refactor specs for `HTML.unescape` ([#13842](https://github.com/crystal-lang/crystal/pull/13842), thanks @straight-shoota)
+- *(text)* Fix spec for `String#encode` and `String.new` on DragonFlyBSD ([#13944](https://github.com/crystal-lang/crystal/pull/13944), thanks @GeopJr)
+
+#### compiler
+
+- *(codegen)* Remove `LLVMExtCreateMCJITCompilerForModule` from `llvm_ext.cc` ([#13966](https://github.com/crystal-lang/crystal/pull/13966), thanks @HertzDevil)
+- *(interpreter)* Disable `mkfifo` spec for interpreter ([#14051](https://github.com/crystal-lang/crystal/pull/14051), thanks @HertzDevil)
+- *(interpreter)* Fix interpreter specs on Windows ([#14145](https://github.com/crystal-lang/crystal/pull/14145), thanks @HertzDevil)
+
+#### tools
+
+- *(docs-generator)* Use `top_level_semantic` in doc spec instead of `semantic` ([#9352](https://github.com/crystal-lang/crystal/pull/9352), thanks @makenowjust)
+
+### Infrastructure
+
+- Changelog for 1.11.0 ([#14158](https://github.com/crystal-lang/crystal/pull/14158), thanks @straight-shoota)
+- Update previous Crystal release - 1.10.0 ([#13878](https://github.com/crystal-lang/crystal/pull/13878), thanks @straight-shoota)
+- Allow to specify git fork of distribution-scripts in CI ([#13976](https://github.com/crystal-lang/crystal/pull/13976), thanks @miry)
+- Extract `generate_data` to separate Makefile ([#14015](https://github.com/crystal-lang/crystal/pull/14015), thanks @straight-shoota)
+- Windows: Run specs in random order by default ([#14041](https://github.com/crystal-lang/crystal/pull/14041), thanks @HertzDevil)
+- Update shards 0.17.4 ([#14133](https://github.com/crystal-lang/crystal/pull/14133), thanks @straight-shoota)
+- Update distribution-scripts ([#14136](https://github.com/crystal-lang/crystal/pull/14136), thanks @straight-shoota)
+- Update GH Actions to v4 ([#14120](https://github.com/crystal-lang/crystal/pull/14120), thanks @renovate)
+- Embed logo image into repository and upgrade to SVG ([#14137](https://github.com/crystal-lang/crystal/pull/14137), thanks @straight-shoota)
+- Improvements for `github-changelog` script ([#14160](https://github.com/crystal-lang/crystal/pull/14160), thanks @straight-shoota)
+- Add `scripts/generate_llvm_version_info.cr` ([#14112](https://github.com/crystal-lang/crystal/pull/14112), thanks @HertzDevil)
+- Fix `make clean` to remove zipped manpages ([#14135](https://github.com/crystal-lang/crystal/pull/14135), thanks @straight-shoota)
+- Make `scripts/*.cr` all executable ([#13999](https://github.com/crystal-lang/crystal/pull/13999), thanks @HertzDevil)
+- Reformat changelog release headings ([#13663](https://github.com/crystal-lang/crystal/pull/13663), thanks @straight-shoota)
+- Merge `samples/.gitignore` into `.gitignore` ([#14134](https://github.com/crystal-lang/crystal/pull/14134), thanks @straight-shoota)
+- *(ci)* Update GH Actions ([#13801](https://github.com/crystal-lang/crystal/pull/13801), thanks @renovate)
+- *(ci)* Update LLVM patch version to LLVM 17.0.6 ([#14080](https://github.com/crystal-lang/crystal/pull/14080), thanks @straight-shoota)
+- *(ci)* Configure Renovate Bot to add label `topic:infrastructure/ci` on PRs ([#14166](https://github.com/crystal-lang/crystal/pull/14166), thanks @straight-shoota)
+- *(ci)* Update GH Actions ([#14165](https://github.com/crystal-lang/crystal/pull/14165), thanks @renovate)
+- *(ci)* Distribute LLVM DLLs on Windows CI ([#14110](https://github.com/crystal-lang/crystal/pull/14110), thanks @HertzDevil)
+- *(ci)* Use `CMAKE_MSVC_RUNTIME_LIBRARY` flag in win.yml ([#13900](https://github.com/crystal-lang/crystal/pull/13900), thanks @HertzDevil)
+
 ## [1.10.1] (2023-10-13)
 
 [1.10.1]: https://github.com/crystal-lang/crystal/releases/1.10.1
diff --git a/src/VERSION b/src/VERSION
index 1f724bf455d7..1cac385c6cb8 100644
--- a/src/VERSION
+++ b/src/VERSION
@@ -1 +1 @@
-1.11.0-dev
+1.11.0

From 0ee5483c04c95c9b055bc9d9a8c3b434b715db5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Tue, 9 Jan 2024 17:36:30 +0100
Subject: [PATCH 039/105] Update previous Crystal release 1.11.0 (#14189)

---
 .circleci/config.yml                     |  2 +-
 .github/workflows/interpreter.yml        |  6 +++---
 .github/workflows/linux.yml              |  2 +-
 .github/workflows/llvm.yml               |  2 +-
 .github/workflows/openssl.yml            |  6 +++---
 .github/workflows/regex-engine.yml       |  4 ++--
 .github/workflows/wasm32.yml             |  2 +-
 .github/workflows/win_build_portable.yml |  2 +-
 bin/ci                                   |  6 +++---
 shell.nix                                | 12 ++++++------
 src/VERSION                              |  2 +-
 11 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 39ae49d81ee3..9804bf22894c 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -12,7 +12,7 @@ parameters:
   previous_crystal_base_url:
     description: "Prefix for URLs to Crystal bootstrap compiler"
     type: string
-    default: "https://github.com/crystal-lang/crystal/releases/download/1.10.1/crystal-1.10.1-1"
+    default: "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1"
 
 defaults:
   environment: &env
diff --git a/.github/workflows/interpreter.yml b/.github/workflows/interpreter.yml
index 2cd37d4b6579..64ef777fa9d3 100644
--- a/.github/workflows/interpreter.yml
+++ b/.github/workflows/interpreter.yml
@@ -13,7 +13,7 @@ jobs:
   test-interpreter_spec:
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.10.1-build
+      image: crystallang/crystal:1.11.0-build
     name: "Test Interpreter"
     steps:
       - uses: actions/checkout@v4
@@ -24,7 +24,7 @@ jobs:
   build-interpreter:
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.10.1-build
+      image: crystallang/crystal:1.11.0-build
     name: Build interpreter
     steps:
       - uses: actions/checkout@v4
@@ -43,7 +43,7 @@ jobs:
     needs: build-interpreter
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.10.1-build
+      image: crystallang/crystal:1.11.0-build
     strategy:
       matrix:
         part: [0, 1, 2, 3]
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 9ef73a9fe23c..c501d1b0061c 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -19,7 +19,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1]
+        crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1, 1.11.0]
         flags: [""]
         include:
           # libffi is only available starting from the 1.2.2 build images
diff --git a/.github/workflows/llvm.yml b/.github/workflows/llvm.yml
index f361896768d8..e8e891cab665 100644
--- a/.github/workflows/llvm.yml
+++ b/.github/workflows/llvm.yml
@@ -56,7 +56,7 @@ jobs:
       - name: Install Crystal
         uses: crystal-lang/install-crystal@v1
         with:
-          crystal: "1.10.1"
+          crystal: "1.11.0"
 
       - name: Build libllvm_ext
         run: make -B deps
diff --git a/.github/workflows/openssl.yml b/.github/workflows/openssl.yml
index 07e2d7e94558..16dfe3b42e32 100644
--- a/.github/workflows/openssl.yml
+++ b/.github/workflows/openssl.yml
@@ -10,7 +10,7 @@ jobs:
   openssl3:
     runs-on: ubuntu-latest
     name: "OpenSSL 3.0"
-    container: crystallang/crystal:1.10.1-alpine
+    container: crystallang/crystal:1.11.0-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -27,7 +27,7 @@ jobs:
   openssl111:
     runs-on: ubuntu-latest
     name: "OpenSSL 1.1.1"
-    container: crystallang/crystal:1.10.1-alpine
+    container: crystallang/crystal:1.11.0-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -42,7 +42,7 @@ jobs:
   libressl34:
     runs-on: ubuntu-latest
     name: "LibreSSL 3.4"
-    container: crystallang/crystal:1.10.1-alpine
+    container: crystallang/crystal:1.11.0-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/regex-engine.yml b/.github/workflows/regex-engine.yml
index a7ad3afbbb65..ad6de969c5f5 100644
--- a/.github/workflows/regex-engine.yml
+++ b/.github/workflows/regex-engine.yml
@@ -10,7 +10,7 @@ jobs:
   pcre:
     runs-on: ubuntu-latest
     name: "PCRE"
-    container: crystallang/crystal:1.10.1-alpine
+    container: crystallang/crystal:1.11.0-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -25,7 +25,7 @@ jobs:
   pcre2:
     runs-on: ubuntu-latest
     name: "PCRE2"
-    container: crystallang/crystal:1.10.1-alpine
+    container: crystallang/crystal:1.11.0-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/wasm32.yml b/.github/workflows/wasm32.yml
index 0d4f32f4c044..eec64cc0bb39 100644
--- a/.github/workflows/wasm32.yml
+++ b/.github/workflows/wasm32.yml
@@ -12,7 +12,7 @@ env:
 jobs:
   wasm32-test:
     runs-on: ubuntu-latest
-    container: crystallang/crystal:1.10.1-build
+    container: crystallang/crystal:1.11.0-build
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/win_build_portable.yml b/.github/workflows/win_build_portable.yml
index 960606628a9e..6ea5568305b6 100644
--- a/.github/workflows/win_build_portable.yml
+++ b/.github/workflows/win_build_portable.yml
@@ -24,7 +24,7 @@ jobs:
       - name: Install Crystal
         uses: crystal-lang/install-crystal@v1
         with:
-          crystal: "1.10.1"
+          crystal: "1.11.0"
 
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/bin/ci b/bin/ci
index 8e9f7a5ddadf..d67c2d7f6c4e 100755
--- a/bin/ci
+++ b/bin/ci
@@ -135,8 +135,8 @@ format() {
 prepare_build() {
   on_linux verify_linux_environment
 
-  on_osx curl -L https://github.com/crystal-lang/crystal/releases/download/1.10.1/crystal-1.10.1-1-darwin-universal.tar.gz -o ~/crystal.tar.gz
-  on_osx 'pushd ~;gunzip -c ~/crystal.tar.gz | tar xopf -;mv crystal-1.10.1-1 crystal;popd'
+  on_osx curl -L https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-darwin-universal.tar.gz -o ~/crystal.tar.gz
+  on_osx 'pushd ~;gunzip -c ~/crystal.tar.gz | tar xopf -;mv crystal-1.11.0-1 crystal;popd'
 
   # These commands may take a few minutes to run due to the large size of the repositories.
   # This restriction has been made on GitHub's request because updating shallow
@@ -189,7 +189,7 @@ with_build_env() {
 
   on_linux verify_linux_environment
 
-  export DOCKER_TEST_PREFIX="${DOCKER_TEST_PREFIX:=crystallang/crystal:1.10.1}"
+  export DOCKER_TEST_PREFIX="${DOCKER_TEST_PREFIX:=crystallang/crystal:1.11.0}"
 
   case $ARCH in
     x86_64)
diff --git a/shell.nix b/shell.nix
index ab90080aca13..02db8fb637f7 100644
--- a/shell.nix
+++ b/shell.nix
@@ -52,18 +52,18 @@ let
   # Hashes obtained using `nix-prefetch-url --unpack <url>`
   latestCrystalBinary = genericBinary ({
     x86_64-darwin = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.10.1/crystal-1.10.1-1-darwin-universal.tar.gz";
-      sha256 = "sha256:08k8sixhnk9ld99nyrya11rkpp34zamsg3lk9h50ppbmzfixjyyc";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-darwin-universal.tar.gz";
+      sha256 = "sha256:0x3adik0rpfkgw8nszf6l52vr4m7fs7rwqf1r0m17x4kgq67daiz";
     };
 
     aarch64-darwin = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.10.1/crystal-1.10.1-1-darwin-universal.tar.gz";
-      sha256 = "sha256:08k8sixhnk9ld99nyrya11rkpp34zamsg3lk9h50ppbmzfixjyyc";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-darwin-universal.tar.gz";
+      sha256 = "sha256:0x3adik0rpfkgw8nszf6l52vr4m7fs7rwqf1r0m17x4kgq67daiz";
     };
 
     x86_64-linux = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.10.1/crystal-1.10.1-1-linux-x86_64.tar.gz";
-      sha256 = "sha256:02hzslzgv0xxsal3fkbcdrnrrnzf9lraamy36p36sjf8n14v45a2";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-linux-x86_64.tar.gz";
+      sha256 = "sha256:1npbn61mw6fchdlg64s7zd3k33711ifhs8n75skw8w30i4ryilhk";
     };
   }.${pkgs.stdenv.system});
 
diff --git a/src/VERSION b/src/VERSION
index 1cac385c6cb8..381cf02417c4 100644
--- a/src/VERSION
+++ b/src/VERSION
@@ -1 +1 @@
-1.11.0
+1.12.0-dev

From 0b57b6cc8e4f5003267549892d23d2af5ad6309b Mon Sep 17 00:00:00 2001
From: Stephen von Takach <steve@vontaka.ch>
Date: Wed, 10 Jan 2024 02:37:47 +1000
Subject: [PATCH 040/105] Add `Signal::trap_handler?` (#14126)

Co-authored-by: Quinton Miller <nicetas.c@gmail.com>
---
 spec/std/signal_spec.cr            | 22 ++++++++++++++++++++++
 src/crystal/system/signal.cr       |  3 +++
 src/crystal/system/unix/signal.cr  |  6 +++++-
 src/crystal/system/wasi/signal.cr  |  4 ++++
 src/crystal/system/win32/signal.cr |  4 ++++
 src/signal.cr                      | 18 ++++++++++++++++++
 6 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/spec/std/signal_spec.cr b/spec/std/signal_spec.cr
index e92b74a6370c..d1d3aa3f1643 100644
--- a/spec/std/signal_spec.cr
+++ b/spec/std/signal_spec.cr
@@ -29,6 +29,8 @@ describe "Signal" do
         sleep 0.1
       end
       ran.should be_true
+    ensure
+      Signal::USR1.reset
     end
 
     it "ignores a signal" do
@@ -36,6 +38,26 @@ describe "Signal" do
       Process.signal Signal::USR2, Process.pid
     end
 
+    it "allows chaining of signals" do
+      ran_first = false
+      ran_second = false
+
+      Signal::USR1.trap { ran_first = true }
+      existing = Signal::USR1.trap_handler?
+
+      Signal::USR1.trap do |signal|
+        existing.try &.call(signal)
+        ran_second = true
+      end
+
+      Process.signal Signal::USR1, Process.pid
+      sleep 0.1
+      ran_first.should be_true
+      ran_second.should be_true
+    ensure
+      Signal::USR1.reset
+    end
+
     it "CHLD.reset sets default Crystal child handler" do
       Signal::CHLD.reset
       child = Process.new("true", shell: true)
diff --git a/src/crystal/system/signal.cr b/src/crystal/system/signal.cr
index b5ba591b2ec5..a5e3eca885da 100644
--- a/src/crystal/system/signal.cr
+++ b/src/crystal/system/signal.cr
@@ -2,6 +2,9 @@ module Crystal::System::Signal
   # Sets the handler for this signal to the passed function.
   # def self.trap(signal, handler) : Nil
 
+  # Returns any existing handler set on the signal
+  # def self.trap_handler?(signal)
+
   # Resets the handler for this signal to the OS default.
   # def self.reset(signal) : Nil
 
diff --git a/src/crystal/system/unix/signal.cr b/src/crystal/system/unix/signal.cr
index c30a2b985af2..58b1180f56ef 100644
--- a/src/crystal/system/unix/signal.cr
+++ b/src/crystal/system/unix/signal.cr
@@ -15,7 +15,7 @@ module Crystal::System::Signal
   @@pipe = IO.pipe(read_blocking: false, write_blocking: true)
   @@handlers = {} of ::Signal => Handler
   @@sigset = Sigset.new
-  class_setter child_handler : Handler?
+  class_property child_handler : Handler?
   @@mutex = Mutex.new(:unchecked)
 
   def self.trap(signal, handler) : Nil
@@ -30,6 +30,10 @@ module Crystal::System::Signal
     end
   end
 
+  def self.trap_handler?(signal)
+    @@mutex.synchronize { @@handlers[signal]? }
+  end
+
   def self.reset(signal) : Nil
     set(signal, LibC::SIG_DFL)
   end
diff --git a/src/crystal/system/wasi/signal.cr b/src/crystal/system/wasi/signal.cr
index d66b9c22c5cd..35675ce14f34 100644
--- a/src/crystal/system/wasi/signal.cr
+++ b/src/crystal/system/wasi/signal.cr
@@ -3,6 +3,10 @@ module Crystal::System::Signal
     raise NotImplementedError.new("Crystal::System::Signal.trap")
   end
 
+  def self.trap_handler?(signal)
+    raise NotImplementedError.new("Crystal::System::Signal.trap_handler?")
+  end
+
   def self.reset(signal) : Nil
     raise NotImplementedError.new("Crystal::System::Signal.reset")
   end
diff --git a/src/crystal/system/win32/signal.cr b/src/crystal/system/win32/signal.cr
index 8f5541c7599b..d805ea4fd1ab 100644
--- a/src/crystal/system/win32/signal.cr
+++ b/src/crystal/system/win32/signal.cr
@@ -5,6 +5,10 @@ module Crystal::System::Signal
     raise NotImplementedError.new("Crystal::System::Signal.trap")
   end
 
+  def self.trap_handler?(signal)
+    raise NotImplementedError.new("Crystal::System::Signal.trap_handler?")
+  end
+
   def self.reset(signal) : Nil
     raise NotImplementedError.new("Crystal::System::Signal.reset")
   end
diff --git a/src/signal.cr b/src/signal.cr
index 60eba5b8e7f3..2e085b92311e 100644
--- a/src/signal.cr
+++ b/src/signal.cr
@@ -117,6 +117,24 @@ enum Signal : Int32
     Crystal::System::Signal.trap(self, handler)
   end
 
+  # Returns any existing handler for this signal
+  #
+  # ```
+  # Signal::USR1.trap { }
+  # prev_handler = Signal::USR1.trap_handler?
+  #
+  # Signal::USR1.trap do |signal|
+  #   prev_handler.try &.call(signal)
+  #   # ...
+  # end
+  # ```
+  def trap_handler?
+    {% if @type.has_constant?("CHLD") %}
+      return Crystal::System::Signal.child_handler if self == CHLD
+    {% end %}
+    Crystal::System::Signal.trap_handler?(self)
+  end
+
   # Resets the handler for this signal to the OS default.
   #
   # Note that trying to reset `CHLD` will actually set the default crystal

From dd5d2dd8b509ec514ad3c134aec1a4994a8415d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 10 Jan 2024 12:26:05 +0100
Subject: [PATCH 041/105] Bump VERSION to 1.11.1-dev (#14197)

---
 src/VERSION | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/VERSION b/src/VERSION
index 1cac385c6cb8..095b66727677 100644
--- a/src/VERSION
+++ b/src/VERSION
@@ -1 +1 @@
-1.11.0
+1.11.1-dev

From bd43c5f6a806ead05b3a00afbc539fd38a01ccba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 10 Jan 2024 14:29:21 +0100
Subject: [PATCH 042/105] Remove pkg-config name for libgc as workaround for
 interpreter loader (#14198)

---
 src/gc/boehm.cr | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/gc/boehm.cr b/src/gc/boehm.cr
index 8278f33b8e94..609f71189795 100644
--- a/src/gc/boehm.cr
+++ b/src/gc/boehm.cr
@@ -21,6 +21,12 @@
 
 {% if flag?(:freebsd) || flag?(:dragonfly) %}
   @[Link("gc-threaded")]
+{% elsif flag?(:interpreted) %}
+  # FIXME: We're not using the pkg-config name here because that would resolve the
+  # lib flags for libgc including `-lpthread` which the interpreter is not able
+  # to load on systems with modern libc where libpthread is only available as an
+  # (empty) static library.
+  @[Link("gc")]
 {% else %}
   @[Link("gc", pkg_config: "bdw-gc")]
 {% end %}

From 9d52e30d4cda5c77b8ad59c20859a02c3db3d2f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 10 Jan 2024 16:25:45 +0100
Subject: [PATCH 043/105] Revert "Add `ReferenceStorage` for manual allocation
 of references (#14106)" (#14207)

---
 .../semantic/reference_storage_spec.cr        | 40 --------------
 spec/primitives/reference_spec.cr             |  4 +-
 src/compiler/crystal/codegen/llvm_typer.cr    |  4 --
 src/compiler/crystal/program.cr               |  6 +--
 src/compiler/crystal/types.cr                 | 28 +---------
 src/prelude.cr                                |  1 -
 src/reference_storage.cr                      | 54 -------------------
 7 files changed, 5 insertions(+), 132 deletions(-)
 delete mode 100644 spec/compiler/semantic/reference_storage_spec.cr
 delete mode 100644 src/reference_storage.cr

diff --git a/spec/compiler/semantic/reference_storage_spec.cr b/spec/compiler/semantic/reference_storage_spec.cr
deleted file mode 100644
index 791fed054275..000000000000
--- a/spec/compiler/semantic/reference_storage_spec.cr
+++ /dev/null
@@ -1,40 +0,0 @@
-require "../../spec_helper"
-
-describe "Semantic: ReferenceStorage" do
-  it "errors if T is a struct type" do
-    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Foo (T must be a reference type)"
-      struct Foo
-        @x = 1
-      end
-
-      ReferenceStorage(Foo)
-      CRYSTAL
-  end
-
-  it "errors if T is a value type" do
-    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Int32 (T must be a reference type)"
-      ReferenceStorage(Int32)
-      CRYSTAL
-  end
-
-  it "errors if T is a union type" do
-    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Bar | Foo) (T must be a reference type)"
-      class Foo
-      end
-
-      class Bar
-      end
-
-      ReferenceStorage(Foo | Bar)
-      CRYSTAL
-  end
-
-  it "errors if T is a nilable type" do
-    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Foo | Nil) (T must be a reference type)"
-      class Foo
-      end
-
-      ReferenceStorage(Foo?)
-      CRYSTAL
-  end
-end
diff --git a/spec/primitives/reference_spec.cr b/spec/primitives/reference_spec.cr
index 52f179296ee8..b73553748b65 100644
--- a/spec/primitives/reference_spec.cr
+++ b/spec/primitives/reference_spec.cr
@@ -43,7 +43,9 @@ describe "Primitives: reference" do
     end
 
     it "works when address is on the stack" do
-      foo_buffer = uninitialized ReferenceStorage(Foo)
+      # suitably aligned, sufficient storage for type ID + i64 + ptr
+      # TODO: use `ReferenceStorage` instead
+      foo_buffer = uninitialized UInt64[3]
       foo = Foo.pre_initialize(pointerof(foo_buffer))
       pointerof(foo_buffer).as(typeof(Foo.crystal_instance_type_id)*).value.should eq(Foo.crystal_instance_type_id)
       foo.str.should eq("abc")
diff --git a/src/compiler/crystal/codegen/llvm_typer.cr b/src/compiler/crystal/codegen/llvm_typer.cr
index d72a25ecd3cb..d20fbd59fa9a 100644
--- a/src/compiler/crystal/codegen/llvm_typer.cr
+++ b/src/compiler/crystal/codegen/llvm_typer.cr
@@ -245,10 +245,6 @@ module Crystal
       llvm_type(type.remove_alias, wants_size)
     end
 
-    private def create_llvm_type(type : ReferenceStorageType, wants_size)
-      llvm_struct_type(type.reference_type, wants_size)
-    end
-
     private def create_llvm_type(type : NonGenericModuleType | GenericClassType, wants_size)
       # This can only be reached if the module or generic class don't have implementors
       @llvm_context.int1
diff --git a/src/compiler/crystal/program.cr b/src/compiler/crystal/program.cr
index 6d3d185774af..936fc6a0a270 100644
--- a/src/compiler/crystal/program.cr
+++ b/src/compiler/crystal/program.cr
@@ -197,10 +197,6 @@ module Crystal
       types["Struct"] = struct_t = @struct_t = NonGenericClassType.new self, self, "Struct", value
       abstract_value_type(struct_t)
 
-      types["ReferenceStorage"] = @reference_storage = reference_storage = GenericReferenceStorageType.new self, self, "ReferenceStorage", value, ["T"]
-      reference_storage.declare_instance_var("@type_id", int32)
-      reference_storage.can_be_stored = false
-
       types["Enumerable"] = @enumerable = GenericModuleType.new self, self, "Enumerable", ["T"]
       types["Indexable"] = @indexable = GenericModuleType.new self, self, "Indexable", ["T"]
 
@@ -497,7 +493,7 @@ module Crystal
 
     {% for name in %w(object no_return value number reference void nil bool char int int8 int16 int32 int64 int128
                      uint8 uint16 uint32 uint64 uint128 float float32 float64 string symbol pointer enumerable indexable
-                     array static_array reference_storage exception tuple named_tuple proc union enum range regex crystal
+                     array static_array exception tuple named_tuple proc union enum range regex crystal
                      packed_annotation thread_local_annotation no_inline_annotation
                      always_inline_annotation naked_annotation returns_twice_annotation
                      raises_annotation primitive_annotation call_convention_annotation
diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr
index 64bcdda9a3d9..ad9f3d391fa6 100644
--- a/src/compiler/crystal/types.cr
+++ b/src/compiler/crystal/types.cr
@@ -550,7 +550,7 @@ module Crystal
     def allows_instance_vars?
       case self
       when program.object, program.value, program.struct,
-           program.reference, program.class_type, program.reference_storage,
+           program.reference, program.class_type,
            program.number, program.int, program.float,
            program.tuple, program.named_tuple,
            program.pointer, program.static_array,
@@ -2642,32 +2642,6 @@ module Crystal
     end
   end
 
-  # The non-instantiated ReferenceStorage(T) type.
-  class GenericReferenceStorageType < GenericClassType
-    @struct = true
-
-    def new_generic_instance(program, generic_type, type_vars)
-      t = type_vars["T"].type
-
-      unless t.is_a?(TypeParameter) || (t.class? && !t.struct?)
-        raise TypeException.new "Can't instantiate ReferenceStorage(T) with T = #{t} (T must be a reference type)"
-      end
-
-      ReferenceStorageType.new program, t
-    end
-  end
-
-  class ReferenceStorageType < GenericClassInstanceType
-    getter reference_type : Type
-
-    def initialize(program, @reference_type)
-      t_var = Var.new("T", @reference_type)
-      t_var.bind_to t_var
-
-      super(program, program.reference_storage, program.struct, {"T" => t_var} of String => ASTNode)
-    end
-  end
-
   # A lib type, like `lib LibC`.
   class LibType < ModuleType
     getter link_annotations : Array(LinkAnnotation)?
diff --git a/src/prelude.cr b/src/prelude.cr
index f84bb86cb3c1..f06f5bc87015 100644
--- a/src/prelude.cr
+++ b/src/prelude.cr
@@ -65,7 +65,6 @@ require "raise"
 require "random"
 require "range"
 require "reference"
-require "reference_storage"
 require "regex"
 require "set"
 {% unless flag?(:wasm32) %}
diff --git a/src/reference_storage.cr b/src/reference_storage.cr
deleted file mode 100644
index 4f6e39a8cca0..000000000000
--- a/src/reference_storage.cr
+++ /dev/null
@@ -1,54 +0,0 @@
-# a `ReferenceStorage(T)` provides the minimum storage for the instance data of
-# an object of type `T`. The compiler guarantees that
-# `sizeof(ReferenceStorage(T)) == instance_sizeof(T)` and
-# `alignof(ReferenceStorage(T)) == instance_alignof(T)` always hold, which means
-# `Pointer(ReferenceStorage(T))` and `T` are binary-compatible.
-#
-# `T` must be a non-union reference type.
-#
-# WARNING: `ReferenceStorage` is only necessary for manual memory management,
-# such as creating instances of `T` with a non-default allocator. Therefore,
-# this type is unsafe and no public constructors are defined.
-#
-# WARNING: `ReferenceStorage` is unsuitable when instances of `T` require more
-# than `instance_sizeof(T)` bytes, such as `String` and `Log::Metadata`.
-@[Experimental("This type's API is still under development. Join the discussion about custom reference allocation at [#13481](https://github.com/crystal-lang/crystal/issues/13481).")]
-struct ReferenceStorage(T)
-  private def initialize
-  end
-
-  # Returns whether `self` and *other* are bytewise equal.
-  #
-  # NOTE: This does not call `T#==`, so it works even if `self` or *other* does
-  # not represent a valid instance of `T`. If validity is guaranteed, call
-  # `to_reference == other.to_reference` instead to use `T#==`.
-  def ==(other : ReferenceStorage(T)) : Bool
-    to_bytes == other.to_bytes
-  end
-
-  def ==(other) : Bool
-    false
-  end
-
-  def hash(hasher)
-    to_bytes.hash(hasher)
-  end
-
-  def to_s(io : IO) : Nil
-    io << "ReferenceStorage(#<" << T << ":0x"
-    pointerof(@type_id).address.to_s(io, 16)
-    io << ">)"
-  end
-
-  # Returns a `T` whose instance data refers to `self`.
-  #
-  # WARNING: The caller is responsible for ensuring that the instance data is
-  # correctly initialized and outlives the returned `T`.
-  def to_reference : T
-    pointerof(@type_id).as(T)
-  end
-
-  protected def to_bytes
-    Slice.new(pointerof(@type_id).as(UInt8*), instance_sizeof(T))
-  end
-end

From c3eb0eb62fe7a047516962497f6afabae3fd68a3 Mon Sep 17 00:00:00 2001
From: Julien Portalier <julien@portalier.com>
Date: Wed, 10 Jan 2024 23:25:37 +0100
Subject: [PATCH 044/105] Use per-scheduler stack pools (let's recycle)
 (#14100)

---
 src/crystal/scheduler.cr | 46 +++++++++++++++++++---------------------
 src/fiber.cr             | 18 ++++------------
 src/fiber/stack_pool.cr  | 16 +++++++++-----
 src/kernel.cr            | 12 +----------
 4 files changed, 38 insertions(+), 54 deletions(-)

diff --git a/src/crystal/scheduler.cr b/src/crystal/scheduler.cr
index ce06e3c60275..fa963595bf6d 100644
--- a/src/crystal/scheduler.cr
+++ b/src/crystal/scheduler.cr
@@ -2,6 +2,7 @@ require "crystal/system/event_loop"
 require "crystal/system/print_error"
 require "./fiber_channel"
 require "fiber"
+require "fiber/stack_pool"
 require "crystal/system/thread"
 
 # :nodoc:
@@ -13,6 +14,11 @@ require "crystal/system/thread"
 # protected and must never be called directly.
 class Crystal::Scheduler
   @event_loop = Crystal::EventLoop.create
+  @stack_pool = Fiber::StackPool.new
+
+  def self.stack_pool : Fiber::StackPool
+    Thread.current.scheduler.@stack_pool
+  end
 
   def self.event_loop
     Thread.current.scheduler.@event_loop
@@ -83,15 +89,8 @@ class Crystal::Scheduler
     {% end %}
   end
 
-  {% if flag?(:preview_mt) %}
-    def self.enqueue_free_stack(stack : Void*) : Nil
-      Thread.current.scheduler.enqueue_free_stack(stack)
-    end
-  {% end %}
-
   {% if flag?(:preview_mt) %}
     private getter(fiber_channel : Crystal::FiberChannel) { Crystal::FiberChannel.new }
-    @free_stacks = Deque(Void*).new
   {% end %}
 
   @main : Fiber
@@ -157,18 +156,6 @@ class Crystal::Scheduler
     exit 1
   end
 
-  {% if flag?(:preview_mt) %}
-    protected def enqueue_free_stack(stack)
-      @free_stacks.push stack
-    end
-
-    private def release_free_stacks
-      while stack = @free_stacks.shift?
-        Fiber.stack_pool.release stack
-      end
-    end
-  {% end %}
-
   protected def reschedule : Nil
     loop do
       if runnable = @lock.sync { @runnables.shift? }
@@ -178,10 +165,6 @@ class Crystal::Scheduler
         @event_loop.run_once
       end
     end
-
-    {% if flag?(:preview_mt) %}
-      release_free_stacks
-    {% end %}
   end
 
   protected def sleep(time : Time::Span) : Nil
@@ -207,6 +190,8 @@ class Crystal::Scheduler
     end
 
     def run_loop
+      spawn_stack_pool_collector
+
       fiber_channel = self.fiber_channel
       loop do
         @lock.lock
@@ -239,7 +224,7 @@ class Crystal::Scheduler
       @lock.unlock
     end
 
-    def self.init_workers
+    def self.init : Nil
       count = worker_count
       pending = Atomic(Int32).new(count - 1)
       @@workers = Array(Thread).new(count) do |i|
@@ -281,5 +266,18 @@ class Crystal::Scheduler
         4
       end
     end
+  {% else %}
+    def self.init : Nil
+      {% unless flag?(:interpreted) %}
+        Thread.current.scheduler.spawn_stack_pool_collector
+      {% end %}
+    end
   {% end %}
+
+  # Background loop to cleanup unused fiber stacks.
+  def spawn_stack_pool_collector
+    fiber = Fiber.new(name: "Stack pool collector", &->@stack_pool.collect_loop)
+    {% if flag?(:preview_mt) %} fiber.set_current_thread {% end %}
+    enqueue(fiber)
+  end
 end
diff --git a/src/fiber.cr b/src/fiber.cr
index aa2af7bf2229..c96184f3cf1f 100644
--- a/src/fiber.cr
+++ b/src/fiber.cr
@@ -1,6 +1,5 @@
 require "crystal/system/thread_linked_list"
 require "./fiber/context"
-require "./fiber/stack_pool"
 
 # :nodoc:
 @[NoInline]
@@ -47,9 +46,6 @@ class Fiber
   # :nodoc:
   protected class_getter(fibers) { Thread::LinkedList(Fiber).new }
 
-  # :nodoc:
-  class_getter stack_pool = StackPool.new
-
   @context : Context
   @stack : Void*
   @resume_event : Crystal::EventLoop::Event?
@@ -89,10 +85,9 @@ class Fiber
     @context = Context.new
     @stack, @stack_bottom =
       {% if flag?(:interpreted) %}
-        # For interpreted mode we don't need a new stack, the stack is held by the interpreter
         {Pointer(Void).null, Pointer(Void).null}
       {% else %}
-        Fiber.stack_pool.checkout
+        Crystal::Scheduler.stack_pool.checkout
       {% end %}
 
     fiber_main = ->(f : Fiber) { f.run }
@@ -153,14 +148,6 @@ class Fiber
     ex.inspect_with_backtrace(STDERR)
     STDERR.flush
   ensure
-    {% if flag?(:preview_mt) %}
-      Crystal::Scheduler.enqueue_free_stack @stack
-    {% elsif flag?(:interpreted) %}
-      # For interpreted mode we don't need a new stack, the stack is held by the interpreter
-    {% else %}
-      Fiber.stack_pool.release(@stack)
-    {% end %}
-
     # Remove the current fiber from the linked list
     Fiber.inactive(self)
 
@@ -170,6 +157,9 @@ class Fiber
     @timeout_select_action = nil
 
     @alive = false
+    {% unless flag?(:interpreted) %}
+      Crystal::Scheduler.stack_pool.release(@stack)
+    {% end %}
     Crystal::Scheduler.reschedule
   end
 
diff --git a/src/fiber/stack_pool.cr b/src/fiber/stack_pool.cr
index 54d03e4ffa5f..aebd82a0870f 100644
--- a/src/fiber/stack_pool.cr
+++ b/src/fiber/stack_pool.cr
@@ -7,14 +7,13 @@ class Fiber
 
     def initialize
       @deque = Deque(Void*).new
-      @mutex = Thread::Mutex.new
     end
 
     # Removes and frees at most *count* stacks from the top of the pool,
     # returning memory to the operating system.
     def collect(count = lazy_size // 2) : Nil
       count.times do
-        if stack = @mutex.synchronize { @deque.shift? }
+        if stack = @deque.shift?
           Crystal::System::Fiber.free_stack(stack, STACK_SIZE)
         else
           return
@@ -22,21 +21,28 @@ class Fiber
       end
     end
 
+    def collect_loop(every = 5.seconds) : Nil
+      loop do
+        sleep every
+        collect
+      end
+    end
+
     # Removes a stack from the bottom of the pool, or allocates a new one.
     def checkout : {Void*, Void*}
-      stack = @mutex.synchronize { @deque.pop? } || Crystal::System::Fiber.allocate_stack(STACK_SIZE)
+      stack = @deque.pop? || Crystal::System::Fiber.allocate_stack(STACK_SIZE)
       {stack, stack + STACK_SIZE}
     end
 
     # Appends a stack to the bottom of the pool.
     def release(stack) : Nil
-      @mutex.synchronize { @deque.push(stack) }
+      @deque.push(stack)
     end
 
     # Returns the approximated size of the pool. It may be equal or slightly
     # bigger or smaller than the actual size.
     def lazy_size : Int32
-      @mutex.synchronize { @deque.size }
+      @deque.size
     end
   end
 end
diff --git a/src/kernel.cr b/src/kernel.cr
index c3b3106ccae3..d3817ee11661 100644
--- a/src/kernel.cr
+++ b/src/kernel.cr
@@ -563,14 +563,6 @@ end
 {% end %}
 
 {% unless flag?(:interpreted) || flag?(:wasm32) %}
-  # Background loop to cleanup unused fiber stacks.
-  spawn(name: "Fiber Clean Loop") do
-    loop do
-      sleep 5
-      Fiber.stack_pool.collect
-    end
-  end
-
   {% if flag?(:win32) %}
     Crystal::System::Process.start_interrupt_loop
   {% else %}
@@ -586,7 +578,5 @@ end
   Exception::CallStack.load_debug_info if ENV["CRYSTAL_LOAD_DEBUG_INFO"]? == "1"
   Exception::CallStack.setup_crash_handler
 
-  {% if flag?(:preview_mt) %}
-    Crystal::Scheduler.init_workers
-  {% end %}
+  Crystal::Scheduler.init
 {% end %}

From b56c7d9db282e054401211e38b832cb3e2f79963 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Thu, 11 Jan 2024 06:25:48 +0800
Subject: [PATCH 045/105] Allow multiple parameters and blocks for operators
 ending in `=` (#14159)

---
 spec/compiler/parser/parser_spec.cr   | 8 +++++++-
 src/compiler/crystal/syntax/parser.cr | 4 ++--
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr
index 41fad5cc3a89..2fa1a5b4c4a7 100644
--- a/spec/compiler/parser/parser_spec.cr
+++ b/spec/compiler/parser/parser_spec.cr
@@ -290,10 +290,16 @@ module Crystal
     assert_syntax_error "def foo=(*args); end", "setter method 'foo=' cannot have more than one parameter"
     assert_syntax_error "def foo=(**kwargs); end", "setter method 'foo=' cannot have more than one parameter"
     assert_syntax_error "def foo=(&block); end", "setter method 'foo=' cannot have a block"
-    assert_syntax_error "def []=(&block); end", "setter method '[]=' cannot have a block"
     assert_syntax_error "f.[]= do |a| end", "setter method '[]=' cannot be called with a block"
     assert_syntax_error "f.[]= { |bar| }", "setter method '[]=' cannot be called with a block"
 
+    # #10397
+    %w(<= >= == != []= ===).each do |operator|
+      it_parses "def #{operator}(other, file = 1); end", Def.new(operator, ["other".arg, Arg.new("file", 1.int32)])
+      it_parses "def #{operator}(*args, **opts); end", Def.new(operator, ["args".arg], splat_index: 0, double_splat: "opts".arg)
+      it_parses "def #{operator}(*args, **opts, &); end", Def.new(operator, ["args".arg], splat_index: 0, double_splat: "opts".arg, block_arg: Arg.new(""), block_arity: 0)
+    end
+
     # #5895, #6042, #5997
     %w(
       begin nil true false yield with abstract
diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr
index 751608468cd5..f14399212e65 100644
--- a/src/compiler/crystal/syntax/parser.cr
+++ b/src/compiler/crystal/syntax/parser.cr
@@ -3658,8 +3658,8 @@ module Crystal
 
         end_location = token_end_location
 
-        if name.ends_with?('=')
-          if name != "[]=" && (params.size > 1 || found_splat || found_double_splat)
+        if Lexer.setter?(name)
+          if params.size > 1 || found_splat || found_double_splat
             raise "setter method '#{name}' cannot have more than one parameter"
           elsif found_block
             raise "setter method '#{name}' cannot have a block"

From 79b6e730135762420fcf12ca066202a93e9ecca6 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Thu, 11 Jan 2024 06:26:03 +0800
Subject: [PATCH 046/105] Always use `%p` for pointers in
 `Crystal::System.print_error` (#14186)

---
 src/crystal/system/unix/signal.cr     | 2 +-
 src/exception/call_stack/libunwind.cr | 2 +-
 src/exception/call_stack/stackwalk.cr | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/crystal/system/unix/signal.cr b/src/crystal/system/unix/signal.cr
index 58b1180f56ef..d0fdbf298391 100644
--- a/src/crystal/system/unix/signal.cr
+++ b/src/crystal/system/unix/signal.cr
@@ -153,7 +153,7 @@ module Crystal::System::Signal
     if is_stack_overflow
       Crystal::System.print_error "Stack overflow (e.g., infinite or very deep recursion)\n"
     else
-      Crystal::System.print_error "Invalid memory access (signal %d) at address 0x%lx\n", sig, addr
+      Crystal::System.print_error "Invalid memory access (signal %d) at address %p\n", sig, addr
     end
 
     Exception::CallStack.print_backtrace
diff --git a/src/exception/call_stack/libunwind.cr b/src/exception/call_stack/libunwind.cr
index 220db21b71f0..81943d99f376 100644
--- a/src/exception/call_stack/libunwind.cr
+++ b/src/exception/call_stack/libunwind.cr
@@ -102,7 +102,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[0x%llx] ", repeated_frame.ip.address.to_u64
+    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"
diff --git a/src/exception/call_stack/stackwalk.cr b/src/exception/call_stack/stackwalk.cr
index f49c87fae623..4879ed8bb95d 100644
--- a/src/exception/call_stack/stackwalk.cr
+++ b/src/exception/call_stack/stackwalk.cr
@@ -37,7 +37,7 @@ struct Exception::CallStack
       case exception_info.value.exceptionRecord.value.exceptionCode
       when LibC::EXCEPTION_ACCESS_VIOLATION
         addr = exception_info.value.exceptionRecord.value.exceptionInformation[1]
-        Crystal::System.print_error "Invalid memory access (C0000005) at address 0x%llx\n", addr
+        Crystal::System.print_error "Invalid memory access (C0000005) at address %p\n", Pointer(Void).new(addr)
         print_backtrace(exception_info)
         LibC._exit(1)
       when LibC::EXCEPTION_STACK_OVERFLOW
@@ -150,7 +150,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[0x%llx] ", repeated_frame.ip.address.to_u64
+    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"

From 83ce2bc9223c1add3a72ecdd85c693e673e87d81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 11 Jan 2024 16:46:26 +0100
Subject: [PATCH 047/105] Revert "Fix OpenSSL error handling for EOF (support
 for OpenSSL 3.2) (#14169)" (#14217)

Fix OpenSSL error handling for EOF (support for OpenSSL 3.2) (#14169)"
---
 src/openssl.cr | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/openssl.cr b/src/openssl.cr
index f34ee169b4cc..802c9a05e7d3 100644
--- a/src/openssl.cr
+++ b/src/openssl.cr
@@ -89,14 +89,15 @@ module OpenSSL
         when .syscall?
           @code, message = fetch_error_details
           if @code == 0
-            errno = {% if flag?(:win32) %} WinError.wsa_value {% else %} Errno.value {% end %}
-            success = {% if flag?(:win32) %} errno.error_success? {% else %} errno.none? {% end %}
-            if success
+            case return_code
+            when 0
               message = "Unexpected EOF"
               @underlying_eof = true
-            else
-              cause = RuntimeError.from_os_error(func || "OpenSSL", os_error: errno)
+            when -1
+              cause = RuntimeError.from_errno(func || "OpenSSL")
               message = "I/O error"
+            else
+              message = "Unknown error"
             end
           end
         when .ssl?

From 0aa30372c4aebfb681fe20483fcdd463cdb5cd57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 11 Jan 2024 21:15:37 +0100
Subject: [PATCH 048/105] Changelog for 1.11.1 (#14208)

---
 CHANGELOG.md | 20 ++++++++++++++++++++
 src/VERSION  |  2 +-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1bedb4a96a97..658d9f42f822 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,25 @@
 # Changelog
 
+## [1.11.1] (2024-01-11)
+
+[1.11.1]: https://github.com/crystal-lang/crystal/releases/1.11.1
+
+### Bugfixes
+
+#### stdlib
+
+- *(crypto)* Revert "Fix OpenSSL error handling for EOF (support for OpenSSL 3.2) (#14169)" ([#14217](https://github.com/crystal-lang/crystal/pull/14217), thanks @straight-shoota)
+
+#### compiler
+
+- *(interpreter)* Remove pkg-config name for libgc as workaround for interpreter loader ([#14198](https://github.com/crystal-lang/crystal/pull/14198), thanks @straight-shoota)
+- *(semantic)* Revert "Add `ReferenceStorage` for manual allocation of references (#14106)" ([#14207](https://github.com/crystal-lang/crystal/pull/14207), thanks @straight-shoota)
+
+### Infrastructure
+
+- Changelog for 1.11.1 ([#14208](https://github.com/crystal-lang/crystal/pull/14208), thanks @straight-shoota)
+- Bump VERSION to 1.11.1-dev ([#14197](https://github.com/crystal-lang/crystal/pull/14197), thanks @straight-shoota)
+
 ## [1.11.0] (2024-01-08)
 
 [1.11.0]: https://github.com/crystal-lang/crystal/releases/1.11.0
diff --git a/src/VERSION b/src/VERSION
index 095b66727677..720c7384c619 100644
--- a/src/VERSION
+++ b/src/VERSION
@@ -1 +1 @@
-1.11.1-dev
+1.11.1

From 7867cd8071a3816ecc3c0fdd4a7f4c02fbd6e8aa Mon Sep 17 00:00:00 2001
From: Jack <jack@kilmer.co>
Date: Fri, 12 Jan 2024 06:19:34 -0600
Subject: [PATCH 049/105] Enhance docs for `Int#downto` (#14176)

Co-authored-by: George Dietrich <george@dietrich.app>
---
 src/int.cr | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/int.cr b/src/int.cr
index 005d2c625c7b..b36ddba14e9e 100644
--- a/src/int.cr
+++ b/src/int.cr
@@ -567,6 +567,20 @@ struct Int
   end
 
   # Calls the given block with each integer value from self down to `to`.
+  #
+  # ```
+  # 3.downto(1) do |i|
+  #   puts i
+  # end
+  # ```
+  #
+  # Prints:
+  #
+  # ```text
+  # 3
+  # 2
+  # 1
+  # ```
   def downto(to, &block : self ->) : Nil
     return unless self >= to
     x = self

From 6bfcfe8e9910a10c383cc51b4c34bc049d1d661f Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Fri, 12 Jan 2024 20:19:48 +0800
Subject: [PATCH 050/105] Move most of spec runner's state into `Spec::CLI`
 (#14170)

---
 spec/compiler/interpreter/spec_helper.cr |  24 ++-
 spec/std/log/env_config_spec.cr          |   2 +-
 src/compiler/crystal/command/spec.cr     |   2 +-
 src/spec.cr                              |  74 +++----
 src/spec/cli.cr                          | 223 ++++++++++----------
 src/spec/context.cr                      |  38 ++--
 src/spec/dsl.cr                          | 249 ++++++++++++-----------
 src/spec/example.cr                      |  10 +-
 src/spec/formatter.cr                    |  28 ++-
 src/spec/methods.cr                      |  30 +--
 10 files changed, 353 insertions(+), 327 deletions(-)

diff --git a/spec/compiler/interpreter/spec_helper.cr b/spec/compiler/interpreter/spec_helper.cr
index e6aeb240674c..3c6f88ab1679 100644
--- a/spec/compiler/interpreter/spec_helper.cr
+++ b/spec/compiler/interpreter/spec_helper.cr
@@ -24,18 +24,20 @@ end
 # In a nutshell, `interpret_in_separate_process` below calls this same process with an extra option that causes
 # the interpretation of the code from stdin, reading the output from stdout. That string is used as the result of
 # the program being tested.
-def Spec.option_parser
-  option_parser = previous_def
-  option_parser.on("", "--interpret-code PRELUDE", "Execute interpreted code") do |prelude|
-    code = STDIN.gets_to_end
-
-    repl = Crystal::Repl.new
-    repl.prelude = prelude
-
-    print repl.run_code(code)
-    exit
+class Spec::CLI
+  def option_parser
+    option_parser = previous_def
+    option_parser.on("", "--interpret-code PRELUDE", "Execute interpreted code") do |prelude|
+      code = STDIN.gets_to_end
+
+      repl = Crystal::Repl.new
+      repl.prelude = prelude
+
+      print repl.run_code(code)
+      exit
+    end
+    option_parser
   end
-  option_parser
 end
 
 def interpret_in_separate_process(code, prelude, file = __FILE__, line = __LINE__)
diff --git a/spec/std/log/env_config_spec.cr b/spec/std/log/env_config_spec.cr
index 7bfdfb0f239a..5ddc2941b82a 100644
--- a/spec/std/log/env_config_spec.cr
+++ b/spec/std/log/env_config_spec.cr
@@ -10,7 +10,7 @@ end
 describe "Log.setup_from_env" do
   after_all do
     # Setup logging in specs (again) since these specs perform Log.setup
-    Spec.log_setup
+    Spec.cli.log_setup
   end
 
   describe "backend" do
diff --git a/src/compiler/crystal/command/spec.cr b/src/compiler/crystal/command/spec.cr
index ff8f47b11859..ce34b2ac4155 100644
--- a/src/compiler/crystal/command/spec.cr
+++ b/src/compiler/crystal/command/spec.cr
@@ -24,7 +24,7 @@ class Crystal::Command
         puts opts
         puts
 
-        runtime_options = Spec.option_parser
+        runtime_options = Spec::CLI.new.option_parser
         runtime_options.banner = "Runtime options (passed to spec runner):"
         puts runtime_options
         exit
diff --git a/src/spec.cr b/src/spec.cr
index e9cf5d448efd..c51ee8831de4 100644
--- a/src/spec.cr
+++ b/src/spec.cr
@@ -91,45 +91,51 @@ require "./spec/cli"
 # value can be used to rerun the specs in that same order by passing the seed
 # value to `--order`.
 module Spec
-end
+  # :nodoc:
+  class CLI
+    # :nodoc:
+    #
+    # Implement formatter configuration.
+    def configure_formatter(formatter, output_path = nil)
+      case formatter
+      when "junit"
+        junit_formatter = Spec::JUnitFormatter.file(Path.new(output_path.not_nil!))
+        add_formatter(junit_formatter)
+      when "verbose"
+        override_default_formatter(Spec::VerboseFormatter.new)
+      when "tap"
+        override_default_formatter(Spec::TAPFormatter.new)
+      end
+    end
 
-Colorize.on_tty_only!
+    def main(args)
+      Colorize.on_tty_only!
 
-# :nodoc:
-#
-# Implement formatter configuration.
-def Spec.configure_formatter(formatter, output_path = nil)
-  case formatter
-  when "junit"
-    junit_formatter = Spec::JUnitFormatter.file(Path.new(output_path.not_nil!))
-    Spec.add_formatter(junit_formatter)
-  when "verbose"
-    Spec.override_default_formatter(Spec::VerboseFormatter.new)
-  when "tap"
-    Spec.override_default_formatter(Spec::TAPFormatter.new)
-  end
-end
+      begin
+        option_parser.parse(args)
+      rescue e : OptionParser::InvalidOption
+        abort("Error: #{e.message}")
+      end
 
-begin
-  Spec.option_parser.parse(ARGV)
-rescue e : OptionParser::InvalidOption
-  abort("Error: #{e.message}")
-end
+      unless args.empty?
+        STDERR.puts "Error: unknown argument '#{args.first}'"
+        exit 1
+      end
 
-unless ARGV.empty?
-  STDERR.puts "Error: unknown argument '#{ARGV.first}'"
-  exit 1
-end
+      if ENV["SPEC_VERBOSE"]? == "1"
+        override_default_formatter(Spec::VerboseFormatter.new)
+      end
 
-if ENV["SPEC_VERBOSE"]? == "1"
-  Spec.override_default_formatter(Spec::VerboseFormatter.new)
-end
+      add_split_filter ENV["SPEC_SPLIT"]?
 
-Spec.add_split_filter ENV["SPEC_SPLIT"]?
+      {% unless flag?(:wasm32) %}
+        # TODO(wasm): Enable this once `Process.on_interrupt` is implemented
+        Process.on_interrupt { abort! }
+      {% end %}
 
-{% unless flag?(:wasm32) %}
-  # TODO(wasm): Enable this once `Process.on_interrupt` is implemented
-  Process.on_interrupt { Spec.abort! }
-{% end %}
+      run
+    end
+  end
+end
 
-Spec.run
+Spec.cli.main(ARGV)
diff --git a/src/spec/cli.cr b/src/spec/cli.cr
index e17f59206123..4f57c3d4adbb 100644
--- a/src/spec/cli.cr
+++ b/src/spec/cli.cr
@@ -1,139 +1,130 @@
 require "option_parser"
+require "colorize"
 
 # This file is included in the compiler to add usage instructions for the
 # spec runner on `crystal spec --help`.
 
 module Spec
   # :nodoc:
-  class_property pattern : Regex?
-
-  # :nodoc:
-  class_property line : Int32?
-
-  # :nodoc:
-  class_property slowest : Int32?
-
-  # :nodoc:
-  class_property? fail_fast = false
-
-  # :nodoc:
-  class_property? focus = false
-
-  # :nodoc:
-  class_property? dry_run = false
-
-  # :nodoc:
-  class_property? list_tags = false
-
-  # :nodoc:
-  def self.add_location(file, line)
-    locations = @@locations ||= {} of String => Array(Int32)
-    locations.put_if_absent(File.expand_path(file)) { [] of Int32 } << line
-  end
+  #
+  # Configuration for a spec runner. More global state is defined in `./dsl.cr`.
+  class CLI
+    getter pattern : Regex?
+    getter line : Int32?
+    getter slowest : Int32?
+    getter? fail_fast = false
+    property? focus = false
+    getter? dry_run = false
+    getter? list_tags = false
 
-  # :nodoc:
-  def self.add_tag(tag)
-    if anti_tag = tag.lchop?('~')
-      (@@anti_tags ||= Set(String).new) << anti_tag
-    else
-      (@@tags ||= Set(String).new) << tag
+    def add_location(file, line)
+      locations = @locations ||= {} of String => Array(Int32)
+      locations.put_if_absent(File.expand_path(file)) { [] of Int32 } << line
     end
-  end
-
-  # :nodoc:
-  class_getter randomizer_seed : UInt64?
-  class_getter randomizer : Random::PCG32?
 
-  # :nodoc:
-  def self.order=(mode)
-    seed =
-      case mode
-      when "default"
-        nil
-      when "random"
-        Random::Secure.rand(1..99999).to_u64 # 5 digits or less for simplicity
-      when UInt64
-        mode
+    def add_tag(tag)
+      if anti_tag = tag.lchop?('~')
+        (@anti_tags ||= Set(String).new) << anti_tag
       else
-        raise ArgumentError.new("Order must be either 'default', 'random', or a numeric seed value")
+        (@tags ||= Set(String).new) << tag
       end
+    end
 
-    @@randomizer_seed = seed
-    @@randomizer = seed ? Random::PCG32.new(seed) : nil
-  end
+    getter randomizer_seed : UInt64?
+    getter randomizer : Random::PCG32?
 
-  # :nodoc:
-  class_property option_parser : OptionParser = begin
-    OptionParser.new do |opts|
-      opts.banner = "crystal spec runner"
-      opts.on("-e", "--example STRING", "run examples whose full nested names include STRING") do |pattern|
-        Spec.pattern = Regex.new(Regex.escape(pattern))
-      end
-      opts.on("-l", "--line LINE", "run examples whose line matches LINE") do |line|
-        Spec.line = line.to_i
-      end
-      opts.on("-p", "--profile", "Print the 10 slowest specs") do
-        Spec.slowest = 10
-      end
-      opts.on("--fail-fast", "abort the run on first failure") do
-        Spec.fail_fast = true
-      end
-      opts.on("--location file:line", "run example at line 'line' in file 'file', multiple allowed") do |location|
-        if location =~ /\A(.+?)\:(\d+)\Z/
-          Spec.add_location $1, $2.to_i
+    def order=(mode)
+      seed =
+        case mode
+        when "default"
+          nil
+        when "random"
+          Random::Secure.rand(1..99999).to_u64 # 5 digits or less for simplicity
+        when UInt64
+          mode
         else
-          STDERR.puts "location #{location} must be file:line"
-          exit 1
+          raise ArgumentError.new("Order must be either 'default', 'random', or a numeric seed value")
         end
-      end
-      opts.on("--tag TAG", "run examples with the specified TAG, or exclude examples by adding ~ before the TAG.") do |tag|
-        Spec.add_tag tag
-      end
-      opts.on("--list-tags", "lists all the tags used.") do
-        Spec.list_tags = true
-      end
-      opts.on("--order MODE", "run examples in random order by passing MODE as 'random' or to a specific seed by passing MODE as the seed value") do |mode|
-        if mode.in?("default", "random")
-          Spec.order = mode
-        elsif seed = mode.to_u64?
-          Spec.order = seed
-        else
-          abort("order must be either 'default', 'random', or a numeric seed value")
+
+      @randomizer_seed = seed
+      @randomizer = seed ? Random::PCG32.new(seed) : nil
+    end
+
+    def option_parser : OptionParser
+      @option_parser ||= OptionParser.new do |opts|
+        opts.banner = "crystal spec runner"
+        opts.on("-e", "--example STRING", "run examples whose full nested names include STRING") do |pattern|
+          @pattern = Regex.new(Regex.escape(pattern))
+        end
+        opts.on("-l", "--line LINE", "run examples whose line matches LINE") do |line|
+          @line = line.to_i
+        end
+        opts.on("-p", "--profile", "Print the 10 slowest specs") do
+          @slowest = 10
+        end
+        opts.on("--fail-fast", "abort the run on first failure") do
+          @fail_fast = true
+        end
+        opts.on("--location file:line", "run example at line 'line' in file 'file', multiple allowed") do |location|
+          if location =~ /\A(.+?)\:(\d+)\Z/
+            add_location $1, $2.to_i
+          else
+            STDERR.puts "location #{location} must be file:line"
+            exit 1
+          end
+        end
+        opts.on("--tag TAG", "run examples with the specified TAG, or exclude examples by adding ~ before the TAG.") do |tag|
+          add_tag tag
+        end
+        opts.on("--list-tags", "lists all the tags used.") do
+          @list_tags = true
+        end
+        opts.on("--order MODE", "run examples in random order by passing MODE as 'random' or to a specific seed by passing MODE as the seed value") do |mode|
+          if mode.in?("default", "random")
+            self.order = mode
+          elsif seed = mode.to_u64?
+            self.order = seed
+          else
+            abort("order must be either 'default', 'random', or a numeric seed value")
+          end
+        end
+        opts.on("--junit_output OUTPUT_PATH", "generate JUnit XML output within the given OUTPUT_PATH") do |output_path|
+          configure_formatter("junit", output_path)
+        end
+        opts.on("-h", "--help", "show this help") do |pattern|
+          puts opts
+          exit
+        end
+        opts.on("-v", "--verbose", "verbose output") do
+          configure_formatter("verbose")
+        end
+        opts.on("--tap", "Generate TAP output (Test Anything Protocol)") do
+          configure_formatter("tap")
+        end
+        opts.on("--color", "Enabled ANSI colored output") do
+          Colorize.enabled = true
+        end
+        opts.on("--no-color", "Disable ANSI colored output") do
+          Colorize.enabled = false
+        end
+        opts.on("--dry-run", "Pass all tests without execution") do
+          @dry_run = true
+        end
+        opts.unknown_args do |args|
         end
-      end
-      opts.on("--junit_output OUTPUT_PATH", "generate JUnit XML output within the given OUTPUT_PATH") do |output_path|
-        configure_formatter("junit", output_path)
-      end
-      opts.on("-h", "--help", "show this help") do |pattern|
-        puts opts
-        exit
-      end
-      opts.on("-v", "--verbose", "verbose output") do
-        configure_formatter("verbose")
-      end
-      opts.on("--tap", "Generate TAP output (Test Anything Protocol)") do
-        configure_formatter("tap")
-      end
-      opts.on("--color", "Enabled ANSI colored output") do
-        Colorize.enabled = true
-      end
-      opts.on("--no-color", "Disable ANSI colored output") do
-        Colorize.enabled = false
-      end
-      opts.on("--dry-run", "Pass all tests without execution") do
-        Spec.dry_run = true
-      end
-      opts.unknown_args do |args|
       end
     end
+
+    # Blank implementation to reduce the interface of spec's option parser for
+    # inclusion in the compiler. This avoids depending on more of `Spec`
+    # module.
+    # The real implementation in `../spec.cr` overrides this for actual use.
+    def configure_formatter(formatter, output_path = nil)
+    end
   end
 
-  # :nodoc:
-  #
-  # Blank implementation to reduce the interface of spec's option parser for
-  # inclusion in the compiler. This avoids depending on more of `Spec`
-  # module.
-  # The real implementation in `../spec.cr` overrides this for actual use.
-  def self.configure_formatter(formatter, output_path = nil)
+  @[Deprecated("This is an internal API.")]
+  def self.randomizer : Random::PCG32?
+    @@cli.randomizer
   end
 end
diff --git a/src/spec/context.cr b/src/spec/context.cr
index 0a1109c12b92..c18836fe0455 100644
--- a/src/spec/context.cr
+++ b/src/spec/context.cr
@@ -126,13 +126,15 @@ module Spec
     exception : Exception?
 
   # :nodoc:
-  def self.root_context
-    RootContext.instance
-  end
+  class CLI
+    def root_context
+      RootContext.instance
+    end
 
-  # :nodoc:
-  def self.current_context : Context
-    RootContext.current_context
+    # :nodoc:
+    def current_context : Context
+      RootContext.current_context
+    end
   end
 
   # :nodoc:
@@ -167,7 +169,7 @@ module Spec
     end
 
     def report_formatters(result)
-      Spec.formatters.each(&.report(result))
+      Spec.cli.formatters.each(&.report(result))
     end
 
     def succeeded
@@ -175,8 +177,8 @@ module Spec
     end
 
     def finish(elapsed_time, aborted = false)
-      Spec.formatters.each(&.finish(elapsed_time, aborted))
-      Spec.formatters.each(&.print_results(elapsed_time, aborted))
+      Spec.cli.formatters.each(&.finish(elapsed_time, aborted))
+      Spec.cli.formatters.each(&.print_results(elapsed_time, aborted))
     end
 
     def print_results(elapsed_time, aborted = false)
@@ -223,13 +225,13 @@ module Spec
         end
       end
 
-      if Spec.slowest
+      if Spec.cli.slowest
         puts
         results = results_for(:success) + results_for(:fail)
-        top_n = results.sort_by { |res| -res.elapsed.not_nil!.to_f }[0..Spec.slowest.not_nil!]
+        top_n = results.sort_by { |res| -res.elapsed.not_nil!.to_f }[0..Spec.cli.slowest.not_nil!]
         top_n_time = top_n.sum &.elapsed.not_nil!.total_seconds
         percent = (top_n_time * 100) / elapsed_time.total_seconds
-        puts "Top #{Spec.slowest} slowest examples (#{top_n_time.humanize} seconds, #{percent.round(2)}% of total time):"
+        puts "Top #{Spec.cli.slowest} slowest examples (#{top_n_time.humanize} seconds, #{percent.round(2)}% of total time):"
         top_n.each do |res|
           puts "  #{res.description}"
           res_elapsed = res.elapsed.not_nil!.total_seconds.humanize
@@ -252,7 +254,7 @@ module Spec
       puts "Aborted!".colorize.red if aborted
       puts "Finished in #{Spec.to_human(elapsed_time)}"
       puts Spec.color("#{total} examples, #{failures.size} failures, #{errors.size} errors, #{pendings.size} pending", final_status)
-      puts Spec.color("Only running `focus: true`", :focus) if Spec.focus?
+      puts Spec.color("Only running `focus: true`", :focus) if Spec.cli.focus?
 
       unless failures_and_errors.empty?
         puts
@@ -268,13 +270,13 @@ module Spec
     end
 
     def print_order_message
-      if randomizer_seed = Spec.randomizer_seed
+      if randomizer_seed = Spec.cli.randomizer_seed
         puts Spec.color("Randomized with seed: #{randomizer_seed}", :order)
       end
     end
 
     def describe(description, file, line, end_line, focus, tags, &block)
-      Spec.focus = true if focus
+      Spec.cli.focus = true if focus
 
       context = Spec::ExampleGroup.new(@@current_context, description, file, line, end_line, focus, tags)
       @@current_context.children << context
@@ -298,7 +300,7 @@ module Spec
 
     private def add_example(description, file, line, end_line, focus, tags, block)
       check_nesting_spec(file, line) do
-        Spec.focus = true if focus
+        Spec.cli.focus = true if focus
         @@current_context.children <<
           Example.new(@@current_context, description, file, line, end_line, focus, tags, block)
       end
@@ -334,12 +336,12 @@ module Spec
 
     # :nodoc:
     def run
-      Spec.formatters.each(&.push(self))
+      Spec.cli.formatters.each(&.push(self))
 
       ran = run_around_all_hooks(ExampleGroup::Procsy.new(self) { internal_run })
       ran || internal_run
 
-      Spec.formatters.each(&.pop)
+      Spec.cli.formatters.each(&.pop)
     end
 
     protected def report(status : Status, description, file, line, elapsed = nil, ex = nil)
diff --git a/src/spec/dsl.cr b/src/spec/dsl.cr
index 065b31e7aff4..578076b86d69 100644
--- a/src/spec/dsl.cr
+++ b/src/spec/dsl.cr
@@ -2,6 +2,10 @@ require "colorize"
 require "option_parser"
 
 module Spec
+  # :nodoc:
+  # The default spec runner.
+  class_getter cli = CLI.new
+
   # :nodoc:
   enum InfoKind
     Comment
@@ -61,14 +65,6 @@ module Spec
   class NestingSpecError < SpecError
   end
 
-  @@aborted = false
-
-  # :nodoc:
-  def self.abort!
-    @@aborted = true
-    finish_run
-  end
-
   # :nodoc:
   def self.to_human(span : Time::Span)
     total_milliseconds = span.total_milliseconds
@@ -92,17 +88,6 @@ module Spec
 
   record SplitFilter, remainder : Int32, quotient : Int32
 
-  @@split_filter : SplitFilter? = nil
-
-  def self.add_split_filter(filter)
-    if filter
-      r, _, m = filter.partition('%')
-      @@split_filter = SplitFilter.new(remainder: r.to_i, quotient: m.to_i)
-    else
-      @@split_filter = nil
-    end
-  end
-
   # Instructs the spec runner to execute the given block
   # before each spec in the spec suite.
   #
@@ -118,7 +103,7 @@ module Spec
   #
   # will print, just before each spec, 1 and then 2.
   def self.before_each(&block)
-    root_context.before_each(&block)
+    @@cli.root_context.before_each(&block)
   end
 
   # Instructs the spec runner to execute the given block
@@ -136,7 +121,7 @@ module Spec
   #
   # will print, just after each spec, 2 and then 1.
   def self.after_each(&block)
-    root_context.after_each(&block)
+    @@cli.root_context.after_each(&block)
   end
 
   # Instructs the spec runner to execute the given block
@@ -154,7 +139,7 @@ module Spec
   #
   # will print, just before the spec suite starts, 1 and then 2.
   def self.before_suite(&block)
-    root_context.before_all(&block)
+    @@cli.root_context.before_all(&block)
   end
 
   # Instructs the spec runner to execute the given block
@@ -172,7 +157,7 @@ module Spec
   #
   # will print, just after the spec suite ends, 2 and then 1.
   def self.after_suite(&block)
-    root_context.after_all(&block)
+    @@cli.root_context.after_all(&block)
   end
 
   # Instructs the spec runner to execute the given block when each spec in the
@@ -196,129 +181,157 @@ module Spec
   # it { }
   # ```
   def self.around_each(&block : Example::Procsy ->)
-    root_context.around_each(&block)
+    @@cli.root_context.around_each(&block)
   end
 
-  @@start_time : Time::Span? = nil
-
   # :nodoc:
-  def self.run
-    @@start_time = Time.monotonic
-
-    at_exit do |status|
-      # Do not run specs if the process is exiting on an error
-      next unless status == 0
-
-      begin
-        if Spec.list_tags?
-          execute_list_tags
-        else
-          execute_examples
+  class CLI
+    @aborted = false
+
+    def abort!
+      @aborted = true
+      finish_run
+    end
+
+    @split_filter : SplitFilter? = nil
+
+    def add_split_filter(filter)
+      if filter
+        r, _, m = filter.partition('%')
+        @split_filter = SplitFilter.new(remainder: r.to_i, quotient: m.to_i)
+      else
+        @split_filter = nil
+      end
+    end
+
+    @start_time : Time::Span? = nil
+
+    def run
+      @start_time = Time.monotonic
+
+      at_exit do |status|
+        # Do not run specs if the process is exiting on an error
+        next unless status == 0
+
+        begin
+          if list_tags?
+            execute_list_tags
+          else
+            execute_examples
+          end
+        rescue ex
+          STDERR.print "Unhandled exception: "
+          ex.inspect_with_backtrace(STDERR)
+          STDERR.flush
+          @aborted = true
+        ensure
+          finish_run unless list_tags?
         end
-      rescue ex
-        STDERR.print "Unhandled exception: "
-        ex.inspect_with_backtrace(STDERR)
-        STDERR.flush
-        @@aborted = true
-      ensure
-        finish_run unless Spec.list_tags?
       end
     end
-  end
 
-  # :nodoc:
-  def self.execute_examples
-    log_setup
-    maybe_randomize
-    run_filters
-    root_context.run
-  end
+    def execute_examples
+      log_setup
+      maybe_randomize
+      run_filters
+      root_context.run
+    end
 
-  # :nodoc:
-  def self.execute_list_tags
-    run_filters
-    tag_counts = collect_tags(root_context)
-    print_list_tags(tag_counts)
-  end
+    def execute_list_tags
+      run_filters
+      tag_counts = collect_tags(root_context)
+      print_list_tags(tag_counts)
+    end
 
-  private def self.collect_tags(context) : Hash(String, Int32)
-    tag_counts = Hash(String, Int32).new(0)
-    collect_tags(tag_counts, context, Set(String).new)
-    tag_counts
-  end
+    private def collect_tags(context) : Hash(String, Int32)
+      tag_counts = Hash(String, Int32).new(0)
+      collect_tags(tag_counts, context, Set(String).new)
+      tag_counts
+    end
 
-  private def self.collect_tags(tag_counts, context : Context, tags)
-    if context.responds_to?(:tags) && (context_tags = context.tags)
-      tags += context_tags
+    private def collect_tags(tag_counts, context : Context, tags)
+      if context.responds_to?(:tags) && (context_tags = context.tags)
+        tags += context_tags
+      end
+      context.children.each do |child|
+        collect_tags(tag_counts, child, tags)
+      end
     end
-    context.children.each do |child|
-      collect_tags(tag_counts, child, tags)
+
+    private def collect_tags(tag_counts, example : Example, tags)
+      if example_tags = example.tags
+        tags += example_tags
+      end
+      if tags.empty?
+        tag_counts.update("untagged") { |count| count + 1 }
+      else
+        tags.tally(tag_counts)
+      end
     end
-  end
 
-  private def self.collect_tags(tag_counts, example : Example, tags)
-    if example_tags = example.tags
-      tags += example_tags
+    private def print_list_tags(tag_counts : Hash(String, Int32)) : Nil
+      return if tag_counts.empty?
+      longest_name_size = tag_counts.keys.max_of(&.size)
+      tag_counts.to_a.sort_by! { |k, v| {-v, k} }.each do |tag_name, count|
+        puts "#{tag_name.rjust(longest_name_size)}: #{count}"
+      end
     end
-    if tags.empty?
-      tag_counts.update("untagged") { |count| count + 1 }
-    else
-      tags.tally(tag_counts)
+
+    # :nodoc:
+    #
+    # Workaround for #8914
+    private macro defined?(t)
+      {% if t.resolve? %}
+        {{ yield }}
+      {% end %}
     end
-  end
 
-  private def self.print_list_tags(tag_counts : Hash(String, Int32)) : Nil
-    return if tag_counts.empty?
-    longest_name_size = tag_counts.keys.max_of(&.size)
-    tag_counts.to_a.sort_by! { |k, v| {-v, k} }.each do |tag_name, count|
-      puts "#{tag_name.rjust(longest_name_size)}: #{count}"
+    # :nodoc:
+    def log_setup
     end
-  end
 
-  # :nodoc:
-  #
-  # Workaround for #8914
-  private macro defined?(t)
-    {% if t.resolve? %}
-      {{ yield }}
-    {% end %}
-  end
+    # :nodoc:
+    macro finished
+      # :nodoc:
+      #
+      # Initialized the log module for the specs.
+      # If the "log" module is required it is configured to emit no entries by default.
+      def log_setup
+        defined?(::Log) do
+          if Log.responds_to?(:setup)
+            Log.setup_from_env(default_level: :none)
+          end
+        end
+      end
+    end
 
-  # :nodoc:
-  def self.log_setup
-  end
+    def finish_run
+      elapsed_time = Time.monotonic - @start_time.not_nil!
+      root_context.finish(elapsed_time, @aborted)
+      exit 1 if !root_context.succeeded || @aborted || (focus? && ENV["SPEC_FOCUS_NO_FAIL"]? != "1")
+    end
 
-  # :nodoc:
-  macro finished
     # :nodoc:
-    #
-    # Initialized the log module for the specs.
-    # If the "log" module is required it is configured to emit no entries by default.
-    def self.log_setup
-      defined?(::Log) do
-        if Log.responds_to?(:setup)
-          Log.setup_from_env(default_level: :none)
-        end
+    def maybe_randomize
+      if randomizer = @randomizer
+        root_context.randomize(randomizer)
       end
     end
-  end
 
-  def self.finish_run
-    elapsed_time = Time.monotonic - @@start_time.not_nil!
-    root_context.finish(elapsed_time, @@aborted)
-    exit 1 if !root_context.succeeded || @@aborted || (focus? && ENV["SPEC_FOCUS_NO_FAIL"]? != "1")
+    # :nodoc:
+    def run_filters
+      root_context.run_filters(@pattern, @line, @locations, @split_filter, @focus, @tags, @anti_tags)
+    end
   end
 
-  # :nodoc:
-  def self.maybe_randomize
-    if randomizer = @@randomizer
-      root_context.randomize(randomizer)
-    end
+  @[Deprecated("This is an internal API.")]
+  def self.finish_run
+    @@cli.finish_run
   end
 
-  # :nodoc:
-  def self.run_filters
-    root_context.run_filters(@@pattern, @@line, @@locations, @@split_filter, @@focus, @@tags, @@anti_tags)
+  @[Deprecated("This is an internal API.")]
+  def self.add_split_filter(filter)
+    @@cli.add_split_filter(filter)
   end
 end
 
diff --git a/src/spec/example.cr b/src/spec/example.cr
index e6ae51942a38..72bffd6c0e07 100644
--- a/src/spec/example.cr
+++ b/src/spec/example.cr
@@ -18,10 +18,10 @@ module Spec
 
     # :nodoc:
     def run
-      Spec.root_context.check_nesting_spec(file, line) do
-        Spec.formatters.each(&.before_example(description))
+      Spec.cli.root_context.check_nesting_spec(file, line) do
+        Spec.cli.formatters.each(&.before_example(description))
 
-        if Spec.dry_run?
+        if Spec.cli.dry_run?
           @parent.report(:success, description, file, line)
           return
         end
@@ -51,12 +51,12 @@ module Spec
       @parent.report(:success, description, file, line, Time.monotonic - start)
     rescue ex : Spec::AssertionFailed
       @parent.report(:fail, description, file, line, Time.monotonic - start, ex)
-      Spec.abort! if Spec.fail_fast?
+      Spec.cli.abort! if Spec.cli.fail_fast?
     rescue ex : Spec::ExamplePending
       @parent.report(:pending, description, file, line, Time.monotonic - start)
     rescue ex
       @parent.report(:error, description, file, line, Time.monotonic - start, ex)
-      Spec.abort! if Spec.fail_fast?
+      Spec.cli.abort! if Spec.cli.fail_fast?
     ensure
       @parent.run_after_each_hooks
     end
diff --git a/src/spec/formatter.cr b/src/spec/formatter.cr
index 51b355ec075f..cfd88f2b5a6a 100644
--- a/src/spec/formatter.cr
+++ b/src/spec/formatter.cr
@@ -55,7 +55,7 @@ module Spec
     end
 
     def print_results(elapsed_time : Time::Span, aborted : Bool)
-      Spec.root_context.print_results(elapsed_time, aborted)
+      Spec.cli.root_context.print_results(elapsed_time, aborted)
     end
   end
 
@@ -111,22 +111,34 @@ module Spec
     end
 
     def print_results(elapsed_time : Time::Span, aborted : Bool)
-      Spec.root_context.print_results(elapsed_time, aborted)
+      Spec.cli.root_context.print_results(elapsed_time, aborted)
     end
   end
 
-  @@formatters = [Spec::DotFormatter.new] of Spec::Formatter
-
   # :nodoc:
-  def self.formatters
-    @@formatters
+  class CLI
+    @formatters = [Spec::DotFormatter.new] of Spec::Formatter
+
+    def formatters
+      @formatters
+    end
+
+    def override_default_formatter(formatter)
+      @formatters[0] = formatter
+    end
+
+    def add_formatter(formatter)
+      @formatters << formatter
+    end
   end
 
+  @[Deprecated("This is an internal API.")]
   def self.override_default_formatter(formatter)
-    @@formatters[0] = formatter
+    @@cli.override_default_formatter(formatter)
   end
 
+  @[Deprecated("This is an internal API.")]
   def self.add_formatter(formatter)
-    @@formatters << formatter
+    @@cli.add_formatter(formatter)
   end
 end
diff --git a/src/spec/methods.cr b/src/spec/methods.cr
index f98326be0ed3..54b8de34b9bb 100644
--- a/src/spec/methods.cr
+++ b/src/spec/methods.cr
@@ -17,7 +17,7 @@ module Spec::Methods
   #
   # If `focus` is `true`, only this `describe`, and others marked with `focus: true`, will run.
   def describe(description = nil, file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block)
-    Spec.root_context.describe(description.to_s, file, line, end_line, focus, tags, &block)
+    Spec.cli.root_context.describe(description.to_s, file, line, end_line, focus, tags, &block)
   end
 
   # Defines an example group that establishes a specific context,
@@ -46,7 +46,7 @@ module Spec::Methods
   #
   # If `focus` is `true`, only this test, and others marked with `focus: true`, will run.
   def it(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil, &block)
-    Spec.root_context.it(description.to_s, file, line, end_line, focus, tags, &block)
+    Spec.cli.root_context.it(description.to_s, file, line, end_line, focus, tags, &block)
   end
 
   # Defines a pending test case.
@@ -72,7 +72,7 @@ module Spec::Methods
   #
   # If `focus` is `true`, only this test, and others marked with `focus: true`, will run.
   def pending(description = "assert", file = __FILE__, line = __LINE__, end_line = __END_LINE__, focus : Bool = false, tags : String | Enumerable(String) | Nil = nil)
-    Spec.root_context.pending(description.to_s, file, line, end_line, focus, tags)
+    Spec.cli.root_context.pending(description.to_s, file, line, end_line, focus, tags)
   end
 
   # Fails an example.
@@ -124,10 +124,10 @@ module Spec::Methods
   # end
   # ```
   def before_each(&block)
-    if Spec.current_context.is_a?(RootContext)
+    if Spec.cli.current_context.is_a?(RootContext)
       raise "Can't call `before_each` outside of a describe/context"
     end
-    Spec.current_context.before_each(&block)
+    Spec.cli.current_context.before_each(&block)
   end
 
   # Executes the given block after each spec in the current context runs.
@@ -154,10 +154,10 @@ module Spec::Methods
   # end
   # ```
   def after_each(&block)
-    if Spec.current_context.is_a?(RootContext)
+    if Spec.cli.current_context.is_a?(RootContext)
       raise "Can't call `after_each` outside of a describe/context"
     end
-    Spec.current_context.after_each(&block)
+    Spec.cli.current_context.after_each(&block)
   end
 
   # Executes the given block before the first spec in the current context runs.
@@ -184,10 +184,10 @@ module Spec::Methods
   # end
   # ```
   def before_all(&block)
-    if Spec.current_context.is_a?(RootContext)
+    if Spec.cli.current_context.is_a?(RootContext)
       raise "Can't call `before_all` outside of a describe/context"
     end
-    Spec.current_context.before_all(&block)
+    Spec.cli.current_context.before_all(&block)
   end
 
   # Executes the given block after the last spec in the current context runs.
@@ -214,10 +214,10 @@ module Spec::Methods
   # end
   # ```
   def after_all(&block)
-    if Spec.current_context.is_a?(RootContext)
+    if Spec.cli.current_context.is_a?(RootContext)
       raise "Can't call `after_all` outside of a describe/context"
     end
-    Spec.current_context.after_all(&block)
+    Spec.cli.current_context.after_all(&block)
   end
 
   # Executes the given block when each spec in the current context runs.
@@ -252,10 +252,10 @@ module Spec::Methods
   # end
   # ```
   def around_each(&block : Example::Procsy ->)
-    if Spec.current_context.is_a?(RootContext)
+    if Spec.cli.current_context.is_a?(RootContext)
       raise "Can't call `around_each` outside of a describe/context"
     end
-    Spec.current_context.around_each(&block)
+    Spec.cli.current_context.around_each(&block)
   end
 
   # Executes the given block when the current context runs.
@@ -297,10 +297,10 @@ module Spec::Methods
   # end
   # ```
   def around_all(&block : ExampleGroup::Procsy ->)
-    if Spec.current_context.is_a?(RootContext)
+    if Spec.cli.current_context.is_a?(RootContext)
       raise "Can't call `around_all` outside of a describe/context"
     end
-    Spec.current_context.around_all(&block)
+    Spec.cli.current_context.around_all(&block)
   end
 end
 

From 11b107ba1ae5a0978b28e1381e62e88870a52f2f Mon Sep 17 00:00:00 2001
From: femto <femtowin@gmail.com>
Date: Fri, 12 Jan 2024 20:19:58 +0800
Subject: [PATCH 051/105] Add support for `Etc/UTC` time zone identifier
 without tzdb (#14185)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Johannes Müller <straightshoota@gmail.com>
Co-authored-by: George Dietrich <george@dietrich.app>
---
 spec/std/time/location_spec.cr |  4 +---
 src/time/location.cr           | 12 ++++++++----
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/spec/std/time/location_spec.cr b/spec/std/time/location_spec.cr
index bcf7595cffd8..78e27a230fde 100644
--- a/spec/std/time/location_spec.cr
+++ b/spec/std/time/location_spec.cr
@@ -67,9 +67,7 @@ class Time::Location
         with_zoneinfo do
           Location.load("UTC").should eq Location::UTC
           Location.load("").should eq Location::UTC
-
-          # Etc/UTC could be pointing to anything
-          Location.load("Etc/UTC").should_not eq Location::UTC
+          Location.load("Etc/UTC").should eq Location::UTC
         end
       end
 
diff --git a/src/time/location.cr b/src/time/location.cr
index d84c1ab14218..7e0e8f160cb9 100644
--- a/src/time/location.cr
+++ b/src/time/location.cr
@@ -236,7 +236,7 @@ class Time::Location
   #
   # *name* is understood to be a location name in the IANA Time
   # Zone database, such as `"America/New_York"`. As special cases,
-  # `"UTC"` and empty string (`""`) return `Location::UTC`, and
+  # `"UTC"`, `"Etc/UTC"` and empty string (`""`) return `Location::UTC`, and
   # `"Local"` returns `Location.local`.
   #
   # The implementation uses a list of system-specific paths to look for a time
@@ -277,7 +277,11 @@ class Time::Location
   # `Location`, unless the time zone database has been updated in between.
   def self.load(name : String) : Location
     case name
-    when "", "UTC"
+    when "", "UTC", "Etc/UTC"
+      # `UTC` is a special identifier, empty string represents a fallback mechanism.
+      # `Etc/UTC` is technically a tzdb identifier which could potentially point to anything.
+      # But we map it to `Location::UTC` directly for convenience which allows it to work
+      # without a copy of the database.
       UTC
     when "Local"
       local
@@ -339,7 +343,7 @@ class Time::Location
   # The environment variable `ENV["TZ"]` is consulted for finding the time zone
   # to use.
   #
-  # * `"UTC"` and empty string (`""`) return `Location::UTC`
+  # * `"UTC"`, `"Etc/UTC"` and empty string (`""`) return `Location::UTC`
   # * Any other value (such as `"Europe/Berlin"`) is tried to be resolved using
   #   `Location.load`.
   # * If `ENV["TZ"]` is not set, the system's local time zone data will be used
@@ -348,7 +352,7 @@ class Time::Location
   #   `Location::UTC` is returned.
   def self.load_local : Location
     case tz = ENV["TZ"]?
-    when "", "UTC"
+    when "", "UTC", "Etc/UTC"
       return UTC
     when Nil
       if localtime = Crystal::System::Time.load_localtime

From 7ed7a74255c736ecf2045a54de0fd34dfa028dfe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 12 Jan 2024 15:02:54 +0100
Subject: [PATCH 052/105] Update previous Crystal release 1.11.1 (#14224)

---
 .circleci/config.yml                     |  2 +-
 .github/workflows/interpreter.yml        |  6 +++---
 .github/workflows/linux.yml              |  2 +-
 .github/workflows/llvm.yml               |  2 +-
 .github/workflows/openssl.yml            |  6 +++---
 .github/workflows/regex-engine.yml       |  4 ++--
 .github/workflows/wasm32.yml             |  2 +-
 .github/workflows/win_build_portable.yml |  2 +-
 bin/ci                                   |  6 +++---
 shell.nix                                | 12 ++++++------
 10 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9804bf22894c..548716adb511 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -12,7 +12,7 @@ parameters:
   previous_crystal_base_url:
     description: "Prefix for URLs to Crystal bootstrap compiler"
     type: string
-    default: "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1"
+    default: "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1"
 
 defaults:
   environment: &env
diff --git a/.github/workflows/interpreter.yml b/.github/workflows/interpreter.yml
index 64ef777fa9d3..96403e595e17 100644
--- a/.github/workflows/interpreter.yml
+++ b/.github/workflows/interpreter.yml
@@ -13,7 +13,7 @@ jobs:
   test-interpreter_spec:
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.11.0-build
+      image: crystallang/crystal:1.11.1-build
     name: "Test Interpreter"
     steps:
       - uses: actions/checkout@v4
@@ -24,7 +24,7 @@ jobs:
   build-interpreter:
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.11.0-build
+      image: crystallang/crystal:1.11.1-build
     name: Build interpreter
     steps:
       - uses: actions/checkout@v4
@@ -43,7 +43,7 @@ jobs:
     needs: build-interpreter
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.11.0-build
+      image: crystallang/crystal:1.11.1-build
     strategy:
       matrix:
         part: [0, 1, 2, 3]
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index c501d1b0061c..f4b284f9ce74 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -19,7 +19,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1, 1.11.0]
+        crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1, 1.11.1]
         flags: [""]
         include:
           # libffi is only available starting from the 1.2.2 build images
diff --git a/.github/workflows/llvm.yml b/.github/workflows/llvm.yml
index e8e891cab665..15fa6df8712c 100644
--- a/.github/workflows/llvm.yml
+++ b/.github/workflows/llvm.yml
@@ -56,7 +56,7 @@ jobs:
       - name: Install Crystal
         uses: crystal-lang/install-crystal@v1
         with:
-          crystal: "1.11.0"
+          crystal: "1.11.1"
 
       - name: Build libllvm_ext
         run: make -B deps
diff --git a/.github/workflows/openssl.yml b/.github/workflows/openssl.yml
index 16dfe3b42e32..30b148448416 100644
--- a/.github/workflows/openssl.yml
+++ b/.github/workflows/openssl.yml
@@ -10,7 +10,7 @@ jobs:
   openssl3:
     runs-on: ubuntu-latest
     name: "OpenSSL 3.0"
-    container: crystallang/crystal:1.11.0-alpine
+    container: crystallang/crystal:1.11.1-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -27,7 +27,7 @@ jobs:
   openssl111:
     runs-on: ubuntu-latest
     name: "OpenSSL 1.1.1"
-    container: crystallang/crystal:1.11.0-alpine
+    container: crystallang/crystal:1.11.1-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -42,7 +42,7 @@ jobs:
   libressl34:
     runs-on: ubuntu-latest
     name: "LibreSSL 3.4"
-    container: crystallang/crystal:1.11.0-alpine
+    container: crystallang/crystal:1.11.1-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/regex-engine.yml b/.github/workflows/regex-engine.yml
index ad6de969c5f5..523a645085bf 100644
--- a/.github/workflows/regex-engine.yml
+++ b/.github/workflows/regex-engine.yml
@@ -10,7 +10,7 @@ jobs:
   pcre:
     runs-on: ubuntu-latest
     name: "PCRE"
-    container: crystallang/crystal:1.11.0-alpine
+    container: crystallang/crystal:1.11.1-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -25,7 +25,7 @@ jobs:
   pcre2:
     runs-on: ubuntu-latest
     name: "PCRE2"
-    container: crystallang/crystal:1.11.0-alpine
+    container: crystallang/crystal:1.11.1-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/wasm32.yml b/.github/workflows/wasm32.yml
index eec64cc0bb39..ca3431808c01 100644
--- a/.github/workflows/wasm32.yml
+++ b/.github/workflows/wasm32.yml
@@ -12,7 +12,7 @@ env:
 jobs:
   wasm32-test:
     runs-on: ubuntu-latest
-    container: crystallang/crystal:1.11.0-build
+    container: crystallang/crystal:1.11.1-build
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/win_build_portable.yml b/.github/workflows/win_build_portable.yml
index 6ea5568305b6..77e823384ef2 100644
--- a/.github/workflows/win_build_portable.yml
+++ b/.github/workflows/win_build_portable.yml
@@ -24,7 +24,7 @@ jobs:
       - name: Install Crystal
         uses: crystal-lang/install-crystal@v1
         with:
-          crystal: "1.11.0"
+          crystal: "1.11.1"
 
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/bin/ci b/bin/ci
index d67c2d7f6c4e..9a3776a3b7d3 100755
--- a/bin/ci
+++ b/bin/ci
@@ -135,8 +135,8 @@ format() {
 prepare_build() {
   on_linux verify_linux_environment
 
-  on_osx curl -L https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-darwin-universal.tar.gz -o ~/crystal.tar.gz
-  on_osx 'pushd ~;gunzip -c ~/crystal.tar.gz | tar xopf -;mv crystal-1.11.0-1 crystal;popd'
+  on_osx curl -L https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-darwin-universal.tar.gz -o ~/crystal.tar.gz
+  on_osx 'pushd ~;gunzip -c ~/crystal.tar.gz | tar xopf -;mv crystal-1.11.1-1 crystal;popd'
 
   # These commands may take a few minutes to run due to the large size of the repositories.
   # This restriction has been made on GitHub's request because updating shallow
@@ -189,7 +189,7 @@ with_build_env() {
 
   on_linux verify_linux_environment
 
-  export DOCKER_TEST_PREFIX="${DOCKER_TEST_PREFIX:=crystallang/crystal:1.11.0}"
+  export DOCKER_TEST_PREFIX="${DOCKER_TEST_PREFIX:=crystallang/crystal:1.11.1}"
 
   case $ARCH in
     x86_64)
diff --git a/shell.nix b/shell.nix
index 02db8fb637f7..647315af5e70 100644
--- a/shell.nix
+++ b/shell.nix
@@ -52,18 +52,18 @@ let
   # Hashes obtained using `nix-prefetch-url --unpack <url>`
   latestCrystalBinary = genericBinary ({
     x86_64-darwin = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-darwin-universal.tar.gz";
-      sha256 = "sha256:0x3adik0rpfkgw8nszf6l52vr4m7fs7rwqf1r0m17x4kgq67daiz";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-darwin-universal.tar.gz";
+      sha256 = "sha256:1yfb8xzhb3hnf9dn5y0mk25va1hbmk03x0hm9da6805xllr7bq8l";
     };
 
     aarch64-darwin = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-darwin-universal.tar.gz";
-      sha256 = "sha256:0x3adik0rpfkgw8nszf6l52vr4m7fs7rwqf1r0m17x4kgq67daiz";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-darwin-universal.tar.gz";
+      sha256 = "sha256:1yfb8xzhb3hnf9dn5y0mk25va1hbmk03x0hm9da6805xllr7bq8l";
     };
 
     x86_64-linux = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.0/crystal-1.11.0-1-linux-x86_64.tar.gz";
-      sha256 = "sha256:1npbn61mw6fchdlg64s7zd3k33711ifhs8n75skw8w30i4ryilhk";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-linux-x86_64.tar.gz";
+      sha256 = "sha256:18mqp2sy5df6bkyvndg4xwgjf6lmaipz5mcr6lg9a47is2vr1i7v";
     };
   }.${pkgs.stdenv.system});
 

From 5bd7cb538e47e2639b118c7ade2e68362d85a434 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 00:46:00 +0800
Subject: [PATCH 053/105] `XML::Reader`: Disallow attributes containing null
 bytes (#14193)

---
 spec/std/xml/reader_spec.cr | 15 +++++++++++++++
 src/xml/reader.cr           |  8 ++++++++
 2 files changed, 23 insertions(+)

diff --git a/spec/std/xml/reader_spec.cr b/spec/std/xml/reader_spec.cr
index 54183dd8742d..d89593620970 100644
--- a/spec/std/xml/reader_spec.cr
+++ b/spec/std/xml/reader_spec.cr
@@ -359,6 +359,11 @@ module XML
         reader.value.should eq("2")
         reader.read.should be_false
       end
+
+      it "raises if attribute contains null byte" do
+        reader = Reader.new("<root/>")
+        expect_raises(Exception) { reader.move_to_attribute("\0") }
+      end
     end
 
     describe "#[]" do
@@ -378,6 +383,11 @@ module XML
         reader.read # </root>
         reader["id"].should eq("1")
       end
+
+      it "raises if attribute contains null byte" do
+        reader = Reader.new("<root/>")
+        expect_raises(Exception) { reader["\0"] }
+      end
     end
 
     describe "#[]?" do
@@ -397,6 +407,11 @@ module XML
         reader.read # </root>
         reader["id"]?.should eq("1")
       end
+
+      it "raises if attribute contains null byte" do
+        reader = Reader.new("<root/>")
+        expect_raises(Exception) { reader["\0"]? }
+      end
     end
 
     describe "#move_to_element" do
diff --git a/src/xml/reader.cr b/src/xml/reader.cr
index 9d1de3ed4c9e..decdd8468185 100644
--- a/src/xml/reader.cr
+++ b/src/xml/reader.cr
@@ -119,6 +119,7 @@ class XML::Reader
 
   # Moves to the `XML::Reader::Type::ATTRIBUTE` with the specified name.
   def move_to_attribute(name : String) : Bool
+    check_no_null_byte(name)
     LibXML.xmlTextReaderMoveToAttribute(@reader, name) == 1
   end
 
@@ -131,6 +132,7 @@ class XML::Reader
   # Gets the attribute content for the *attribute* given by name.
   # Returns `nil` if attribute is not found.
   def []?(attribute : String) : String?
+    check_no_null_byte(attribute)
     value = LibXML.xmlTextReaderGetAttribute(@reader, attribute)
     String.new(value) if value
   end
@@ -200,4 +202,10 @@ class XML::Reader
       Error.add_errors(@errors)
     end
   end
+
+  private def check_no_null_byte(attribute)
+    if attribute.byte_index(0)
+      raise XML::Error.new("Invalid attribute name: #{attribute.inspect} (contains null character)", 0)
+    end
+  end
 end

From 06f2f82b156cec23d5f1dee06e9041457281c0f6 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 00:46:15 +0800
Subject: [PATCH 054/105] Always call `LibXML.xmlInitParser` when requiring XML
 libraries (#14191)

---
 src/xml/libxml2.cr | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/xml/libxml2.cr b/src/xml/libxml2.cr
index 3dff7fb6cb40..feea8a1ba6d7 100644
--- a/src/xml/libxml2.cr
+++ b/src/xml/libxml2.cr
@@ -11,9 +11,10 @@ require "./save_options"
 lib LibXML
   alias Int = LibC::Int
 
+  fun xmlInitParser
+
   # TODO: check if other platforms also support per-thread globals
   {% if flag?(:win32) %}
-    fun xmlInitParser
     fun __xmlIndentTreeOutput : Int*
     fun __xmlTreeIndentString : UInt8**
   {% else %}
@@ -324,9 +325,7 @@ lib LibXML
   fun xmlValidateNameValue(value : UInt8*) : Int
 end
 
-{% if flag?(:win32) %}
-  LibXML.xmlInitParser
-{% end %}
+LibXML.xmlInitParser
 
 LibXML.xmlGcMemSetup(
   ->GC.free,

From f5844b0fc1ad9eec10cb823f732b9e6e72ee7422 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 00:48:20 +0800
Subject: [PATCH 055/105] Reserve stack space on non-main threads for crash
 recovery on Windows (#14187)

---
 src/crystal/system/win32/thread.cr    | 13 ++++++++++++-
 src/exception/call_stack/stackwalk.cr |  3 ++-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr
index 9a13bfb4dc03..5dbcbabbfad9 100644
--- a/src/crystal/system/win32/thread.cr
+++ b/src/crystal/system/win32/thread.cr
@@ -12,13 +12,24 @@ module Crystal::System::Thread
     @system_handle = GC.beginthreadex(
       security: Pointer(Void).null,
       stack_size: LibC::UInt.zero,
-      start_address: ->(data : Void*) { data.as(::Thread).start; LibC::UInt.zero },
+      start_address: ->Thread.thread_proc(Void*),
       arglist: self.as(Void*),
       initflag: LibC::UInt.zero,
       thrdaddr: Pointer(LibC::UInt).null,
     )
   end
 
+  def self.thread_proc(data : Void*) : LibC::UInt
+    # ensure that even in the case of stack overflow there is enough reserved
+    # stack space for recovery (for the main thread this is done in
+    # `Exception::CallStack.setup_crash_handler`)
+    stack_size = Crystal::System::Fiber::RESERVED_STACK_SIZE
+    LibC.SetThreadStackGuarantee(pointerof(stack_size))
+
+    data.as(::Thread).start
+    LibC::UInt.zero
+  end
+
   def self.current_handle : Handle
     # `GetCurrentThread` returns a _constant_ and is only meaningful as an
     # argument to Win32 APIs; to uniquely identify it we must duplicate the handle
diff --git a/src/exception/call_stack/stackwalk.cr b/src/exception/call_stack/stackwalk.cr
index 4879ed8bb95d..4d60e02305d0 100644
--- a/src/exception/call_stack/stackwalk.cr
+++ b/src/exception/call_stack/stackwalk.cr
@@ -51,7 +51,8 @@ struct Exception::CallStack
     end)
 
     # ensure that even in the case of stack overflow there is enough reserved
-    # stack space for recovery
+    # stack space for recovery (for other threads this is done in
+    # `Crystal::System::Thread.thread_proc`)
     stack_size = Crystal::System::Fiber::RESERVED_STACK_SIZE
     LibC.SetThreadStackGuarantee(pointerof(stack_size))
   end

From 3bf68ddfcc8cf253ec84a7aa27dd103180a51618 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 06:17:35 +0800
Subject: [PATCH 056/105] Remove extra newline in top-level `FunDef`'s string
 representation (#14212)

---
 spec/compiler/parser/to_s_spec.cr   | 3 ++-
 src/compiler/crystal/syntax/to_s.cr | 1 -
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/spec/compiler/parser/to_s_spec.cr b/spec/compiler/parser/to_s_spec.cr
index 752bece45374..75c0bac3ebee 100644
--- a/spec/compiler/parser/to_s_spec.cr
+++ b/spec/compiler/parser/to_s_spec.cr
@@ -143,7 +143,8 @@ describe "ASTNode#to_s" do
   expect_to_s %(@[Foo(1, 2, a: 1, b: 2)])
   expect_to_s %(lib Foo\nend)
   expect_to_s %(lib LibC\n  fun getchar(Int, Float)\nend)
-  expect_to_s %(fun foo(a : Void, b : Void, ...) : Void\n\nend)
+  expect_to_s %(fun foo(a : Void, b : Void, ...) : Void\nend)
+  expect_to_s %(fun foo\nend)
   expect_to_s %(lib Foo\n  struct Foo\n    a : Void\n    b : Void\n  end\nend)
   expect_to_s %(lib Foo\n  union Foo\n    a : Int\n    b : Int32\n  end\nend)
   expect_to_s %(lib Foo\n  FOO = 0\nend)
diff --git a/src/compiler/crystal/syntax/to_s.cr b/src/compiler/crystal/syntax/to_s.cr
index 8ea364d3f991..bf8eff6aef2d 100644
--- a/src/compiler/crystal/syntax/to_s.cr
+++ b/src/compiler/crystal/syntax/to_s.cr
@@ -1170,7 +1170,6 @@ module Crystal
       if body = node.body
         newline
         accept_with_indent body
-        newline
         append_indent
         @str << "end"
       end

From e814029e3f27d2a7f6fe3a9d8d0222902fec6756 Mon Sep 17 00:00:00 2001
From: femto <femtowin@gmail.com>
Date: Sat, 13 Jan 2024 06:18:00 +0800
Subject: [PATCH 057/105] Change short reference for top-level macros to
 `::foo` (#14203)

---
 spec/compiler/macro/macro_methods_spec.cr | 2 +-
 src/compiler/crystal/macros/methods.cr    | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr
index 9d6304e81f01..6e3af42e4d3f 100644
--- a/spec/compiler/macro/macro_methods_spec.cr
+++ b/spec/compiler/macro/macro_methods_spec.cr
@@ -3565,7 +3565,7 @@ module Crystal
     # there are no macro methods with required named parameters
 
     it "uses correct name for top-level macro methods" do
-      assert_macro_error %({{flag?}}), "wrong number of arguments for top-level macro 'flag?' (given 0, expected 1)"
+      assert_macro_error %({{flag?}}), "wrong number of arguments for macro '::flag?' (given 0, expected 1)"
     end
   end
 
diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr
index 24d3d8bbd14d..abef63c402d3 100644
--- a/src/compiler/crystal/macros/methods.cr
+++ b/src/compiler/crystal/macros/methods.cr
@@ -300,7 +300,7 @@ module Crystal
 
     def interpret_run(node)
       if node.args.size == 0
-        node.wrong_number_of_arguments "top-level macro 'run'", 0, "1+"
+        node.wrong_number_of_arguments "macro '::run'", 0, "1+"
       end
 
       node.args.first.accept self
@@ -2841,7 +2841,7 @@ end
 
 private def full_macro_name(node, method, top_level)
   if top_level
-    "top-level macro '#{method}'"
+    "macro '::#{method}'"
   else
     "macro '#{node.class_desc}##{method}'"
   end

From db8ecefc6d77df61b35a69c587c3dc1324f0222d Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 06:18:13 +0800
Subject: [PATCH 058/105] Formatter: Add more whitespace around `ProcLiteral`s
 (#14209)

---
 spec/compiler/formatter/formatter_spec.cr | 8 ++++++++
 src/compiler/crystal/tools/formatter.cr   | 3 ++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/spec/compiler/formatter/formatter_spec.cr b/spec/compiler/formatter/formatter_spec.cr
index 4567638f0fd8..ce2c7e72364c 100644
--- a/spec/compiler/formatter/formatter_spec.cr
+++ b/spec/compiler/formatter/formatter_spec.cr
@@ -1629,6 +1629,14 @@ describe Crystal::Formatter do
   assert_format "->( x : Int32 , y )   { x }", "->(x : Int32, y) { x }"
   assert_format "->{}"
 
+  # #13232
+  assert_format "->{}", "-> { }", flags: %w[proc_literal_whitespace]
+  assert_format "->(){}", "-> { }", flags: %w[proc_literal_whitespace]
+  assert_format "->{1}", "-> { 1 }", flags: %w[proc_literal_whitespace]
+  assert_format "->(x : Int32) {}", "->(x : Int32) { }", flags: %w[proc_literal_whitespace]
+  assert_format "-> : Int32 {}", "-> : Int32 { }", flags: %w[proc_literal_whitespace]
+  assert_format "->do\nend", "-> do\nend", flags: %w[proc_literal_whitespace]
+
   assert_format "-> : Int32 {}"
   assert_format "-> : Int32 | String { 1 }"
   assert_format "-> : Array(Int32) {}"
diff --git a/src/compiler/crystal/tools/formatter.cr b/src/compiler/crystal/tools/formatter.cr
index fc3be7a4cf66..a18634fe8232 100644
--- a/src/compiler/crystal/tools/formatter.cr
+++ b/src/compiler/crystal/tools/formatter.cr
@@ -4256,7 +4256,7 @@ module Crystal
         skip_space_or_newline
       end
 
-      write " " unless a_def.args.empty? && !return_type
+      write " " if a_def.args.present? || return_type || flag?("proc_literal_whitespace")
 
       is_do = false
       if @token.keyword?(:do)
@@ -4264,6 +4264,7 @@ module Crystal
         is_do = true
       else
         write_token :OP_LCURLY
+        write " " if a_def.body.is_a?(Nop) && flag?("proc_literal_whitespace")
       end
       skip_space
 

From dba80384366cc0c2620682dfc4e2982430ee990a Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 19:38:41 +0800
Subject: [PATCH 059/105] Fix: Always use `%p` for pointers in
 `Crystal::System.print_error` (#14221)

---
 src/exception/call_stack/libunwind.cr | 2 +-
 src/exception/call_stack/stackwalk.cr | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/exception/call_stack/libunwind.cr b/src/exception/call_stack/libunwind.cr
index 81943d99f376..9f17512491fe 100644
--- a/src/exception/call_stack/libunwind.cr
+++ b/src/exception/call_stack/libunwind.cr
@@ -102,7 +102,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
+    Crystal::System.print_error "[%p] ", repeated_frame.ip
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"
diff --git a/src/exception/call_stack/stackwalk.cr b/src/exception/call_stack/stackwalk.cr
index 4d60e02305d0..47b78e0ee0df 100644
--- a/src/exception/call_stack/stackwalk.cr
+++ b/src/exception/call_stack/stackwalk.cr
@@ -151,7 +151,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
+    Crystal::System.print_error "[%p] ", repeated_frame.ip
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"

From c35b5e8b6fd0ee69f1c8ce8990bb2ea10e267f2f Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 19:38:52 +0800
Subject: [PATCH 060/105] Always preserve the environment for specs that modify
 `ENV` (#14211)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Johannes Müller <straightshoota@gmail.com>
---
 spec/compiler/macro/macro_methods_spec.cr | 12 ++--
 spec/std/dir_spec.cr                      | 20 +------
 spec/std/env_spec.cr                      | 46 ++++++---------
 spec/std/process_spec.cr                  | 71 +++++++++++------------
 4 files changed, 59 insertions(+), 90 deletions(-)

diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr
index 6e3af42e4d3f..13b063355c33 100644
--- a/spec/compiler/macro/macro_methods_spec.cr
+++ b/spec/compiler/macro/macro_methods_spec.cr
@@ -1,4 +1,5 @@
 require "../../spec_helper"
+require "../../support/env"
 
 private def declare_class_var(container : ClassVarContainer, name, var_type : Type, annotations = nil)
   var = MetaTypeVar.new(name)
@@ -3281,14 +3282,15 @@ module Crystal
 
     describe "env" do
       it "has key" do
-        ENV["FOO"] = "foo"
-        assert_macro %({{env("FOO")}}), %("foo")
-        ENV.delete "FOO"
+        with_env("FOO": "foo") do
+          assert_macro %({{env("FOO")}}), %("foo")
+        end
       end
 
       it "doesn't have key" do
-        ENV.delete "FOO"
-        assert_macro %({{env("FOO")}}), %(nil)
+        with_env("FOO": nil) do
+          assert_macro %({{env("FOO")}}), %(nil)
+        end
       end
     end
 
diff --git a/spec/std/dir_spec.cr b/spec/std/dir_spec.cr
index f0721ef66abb..f0c01d613570 100644
--- a/spec/std/dir_spec.cr
+++ b/spec/std/dir_spec.cr
@@ -3,25 +3,9 @@ require "../support/env"
 
 private def unset_tempdir(&)
   {% if flag?(:windows) %}
-    old_tempdirs = {ENV["TMP"]?, ENV["TEMP"]?, ENV["USERPROFILE"]?}
-    begin
-      ENV.delete("TMP")
-      ENV.delete("TEMP")
-      ENV.delete("USERPROFILE")
-
-      yield
-    ensure
-      ENV["TMP"], ENV["TEMP"], ENV["USERPROFILE"] = old_tempdirs
-    end
+    with_env("TMP": nil, "TEMP": nil, "USERPROFILE": nil) { yield }
   {% else %}
-    begin
-      old_tempdir = ENV["TMPDIR"]?
-      ENV.delete("TMPDIR")
-
-      yield
-    ensure
-      ENV["TMPDIR"] = old_tempdir
-    end
+    with_env("TMPDIR": nil) { yield }
   {% end %}
 end
 
diff --git a/spec/std/env_spec.cr b/spec/std/env_spec.cr
index 8342494b10f6..038bdc74b9b1 100644
--- a/spec/std/env_spec.cr
+++ b/spec/std/env_spec.cr
@@ -2,6 +2,23 @@ require "spec"
 require "./spec_helper"
 
 describe "ENV" do
+  # Preserves the existing environment for each spec.
+  # To avoid potential circular definitions, this has to use the system methods
+  # directly, rather than `ENV` or `with_env`.
+  around_each do |example|
+    old_env = {} of String => String
+    Crystal::System::Env.each { |key, value| old_env[key] = value }
+
+    begin
+      example.run
+    ensure
+      keys = [] of String
+      Crystal::System::Env.each { |key| keys << key }
+      keys.each { |key| Crystal::System::Env.set(key, nil) }
+      old_env.each { |key, value| Crystal::System::Env.set(key, value) }
+    end
+  end
+
   it "gets non existent key raises" do
     expect_raises KeyError, "Missing ENV key: \"NON-EXISTENT\"" do
       ENV["NON-EXISTENT"]
@@ -16,8 +33,6 @@ describe "ENV" do
     (ENV["FOO"] = "1").should eq("1")
     ENV["FOO"].should eq("1")
     ENV["FOO"]?.should eq("1")
-  ensure
-    ENV.delete("FOO")
   end
 
   {% if flag?(:win32) %}
@@ -25,15 +40,11 @@ describe "ENV" do
       (ENV["FOO"] = "1").should eq("1")
       ENV["Foo"].should eq("1")
       ENV["foo"]?.should eq("1")
-    ensure
-      ENV.delete("FOO")
     end
   {% else %}
     it "sets and gets case-sensitive" do
       ENV["FOO"] = "1"
       ENV["foo"]?.should be_nil
-    ensure
-      ENV.delete("FOO")
     end
   {% end %}
 
@@ -47,16 +58,12 @@ describe "ENV" do
   it "sets to empty string" do
     (ENV["FOO_EMPTY"] = "").should eq ""
     ENV["FOO_EMPTY"]?.should eq ""
-  ensure
-    ENV.delete("FOO_EMPTY")
   end
 
   it "does has_key?" do
     ENV["FOO"] = "1"
     ENV.has_key?("NON_EXISTENT").should be_false
     ENV.has_key?("FOO").should be_true
-  ensure
-    ENV.delete("FOO")
   end
 
   it "deletes a key" do
@@ -70,9 +77,6 @@ describe "ENV" do
     %w(FOO BAR).each { |k| ENV.keys.should_not contain(k) }
     ENV["FOO"] = ENV["BAR"] = "1"
     %w(FOO BAR).each { |k| ENV.keys.should contain(k) }
-  ensure
-    ENV.delete("FOO")
-    ENV.delete("BAR")
   end
 
   it "does not have an empty key" do
@@ -86,9 +90,6 @@ describe "ENV" do
     ENV["FOO"] = "SOMEVALUE_1"
     ENV["BAR"] = "SOMEVALUE_2"
     [1, 2].each { |i| ENV.values.should contain("SOMEVALUE_#{i}") }
-  ensure
-    ENV.delete("FOO")
-    ENV.delete("BAR")
   end
 
   describe "[]=" do
@@ -115,16 +116,12 @@ describe "ENV" do
     it "fetches with one argument" do
       ENV["1"] = "2"
       ENV.fetch("1").should eq("2")
-    ensure
-      ENV.delete("1")
     end
 
     it "fetches with default value" do
       ENV["1"] = "2"
       ENV.fetch("1", "3").should eq("2")
       ENV.fetch("2", "3").should eq("3")
-    ensure
-      ENV.delete("1")
     end
 
     it "fetches with block" do
@@ -132,8 +129,6 @@ describe "ENV" do
       ENV.fetch("1") { |k| k + "block" }.should eq("2")
       ENV.fetch("2") { |k| k + "block" }.should eq("2block")
       ENV.fetch("3") { 4 }.should eq(4)
-    ensure
-      ENV.delete("1")
     end
 
     it "fetches and raises" do
@@ -141,8 +136,6 @@ describe "ENV" do
       expect_raises KeyError, "Missing ENV key: \"2\"" do
         ENV.fetch("2")
       end
-    ensure
-      ENV.delete("1")
     end
   end
 
@@ -162,16 +155,11 @@ describe "ENV" do
       "TEST_UNICODE_1" => "bar\u{d7ff}\u{10000}",
       "TEST_UNICODE_2" => "\u{1234}",
     })
-  ensure
-    ENV.delete("TEST_UNICODE_1")
-    ENV.delete("TEST_UNICODE_2")
   end
 
   it "#to_h" do
     ENV["FOO"] = "foo"
     ENV.to_h["FOO"].should eq "foo"
-  ensure
-    ENV.delete("FOO")
   end
 
   {% if flag?(:win32) %}
diff --git a/spec/std/process_spec.cr b/spec/std/process_spec.cr
index 94b8ec18a915..9734ec5ea99c 100644
--- a/spec/std/process_spec.cr
+++ b/spec/std/process_spec.cr
@@ -3,6 +3,7 @@
 require "spec"
 require "process"
 require "./spec_helper"
+require "../support/env"
 
 private def exit_code_command(code)
   {% if flag?(:win32) %}
@@ -267,68 +268,62 @@ describe Process do
       end
 
       it "deletes existing environment variable" do
-        ENV["FOO"] = "bar"
-        value = Process.run(*print_env_command, env: {"FOO" => nil}) do |proc|
-          proc.output.gets_to_end
+        with_env("FOO": "bar") do
+          value = Process.run(*print_env_command, env: {"FOO" => nil}) do |proc|
+            proc.output.gets_to_end
+          end
+          value.should_not match /(*ANYCRLF)^FOO=/m
         end
-        value.should_not match /(*ANYCRLF)^FOO=/m
-      ensure
-        ENV.delete("FOO")
       end
 
       {% if flag?(:win32) %}
         it "deletes existing environment variable case-insensitive" do
-          ENV["FOO"] = "bar"
-          value = Process.run(*print_env_command, env: {"foo" => nil}) do |proc|
-            proc.output.gets_to_end
+          with_env("FOO": "bar") do
+            value = Process.run(*print_env_command, env: {"foo" => nil}) do |proc|
+              proc.output.gets_to_end
+            end
+            value.should_not match /(*ANYCRLF)^FOO=/mi
           end
-          value.should_not match /(*ANYCRLF)^FOO=/mi
-        ensure
-          ENV.delete("FOO")
         end
       {% end %}
 
       it "preserves existing environment variable" do
-        ENV["FOO"] = "bar"
-        value = Process.run(*print_env_command) do |proc|
-          proc.output.gets_to_end
+        with_env("FOO": "bar") do
+          value = Process.run(*print_env_command) do |proc|
+            proc.output.gets_to_end
+          end
+          value.should match /(*ANYCRLF)^FOO=bar$/m
         end
-        value.should match /(*ANYCRLF)^FOO=bar$/m
-      ensure
-        ENV.delete("FOO")
       end
 
       it "preserves and sets an environment variable" do
-        ENV["FOO"] = "bar"
-        value = Process.run(*print_env_command, env: {"FOO2" => "bar2"}) do |proc|
-          proc.output.gets_to_end
+        with_env("FOO": "bar") do
+          value = Process.run(*print_env_command, env: {"FOO2" => "bar2"}) do |proc|
+            proc.output.gets_to_end
+          end
+          value.should match /(*ANYCRLF)^FOO=bar$/m
+          value.should match /(*ANYCRLF)^FOO2=bar2$/m
         end
-        value.should match /(*ANYCRLF)^FOO=bar$/m
-        value.should match /(*ANYCRLF)^FOO2=bar2$/m
-      ensure
-        ENV.delete("FOO")
       end
 
       it "overrides existing environment variable" do
-        ENV["FOO"] = "bar"
-        value = Process.run(*print_env_command, env: {"FOO" => "different"}) do |proc|
-          proc.output.gets_to_end
+        with_env("FOO": "bar") do
+          value = Process.run(*print_env_command, env: {"FOO" => "different"}) do |proc|
+            proc.output.gets_to_end
+          end
+          value.should match /(*ANYCRLF)^FOO=different$/m
         end
-        value.should match /(*ANYCRLF)^FOO=different$/m
-      ensure
-        ENV.delete("FOO")
       end
 
       {% if flag?(:win32) %}
         it "overrides existing environment variable case-insensitive" do
-          ENV["FOO"] = "bar"
-          value = Process.run(*print_env_command, env: {"fOo" => "different"}) do |proc|
-            proc.output.gets_to_end
+          with_env("FOO": "bar") do
+            value = Process.run(*print_env_command, env: {"fOo" => "different"}) do |proc|
+              proc.output.gets_to_end
+            end
+            value.should_not match /(*ANYCRLF)^FOO=/m
+            value.should match /(*ANYCRLF)^fOo=different$/m
           end
-          value.should_not match /(*ANYCRLF)^FOO=/m
-          value.should match /(*ANYCRLF)^fOo=different$/m
-        ensure
-          ENV.delete("FOO")
         end
       {% end %}
     end

From e0c5301a5eb22c1e22398e146d44dbc85b3ff998 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 19:38:59 +0800
Subject: [PATCH 061/105] Remove `T*` and `T[N]` macro interpolation behavior
 inside libs (#14215)

---
 spec/compiler/parser/to_s_spec.cr             | 19 ++++++++++++++++
 .../semantic/restrictions_augmenter_spec.cr   |  4 ++--
 src/compiler/crystal/syntax/to_s.cr           | 22 -------------------
 3 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/spec/compiler/parser/to_s_spec.cr b/spec/compiler/parser/to_s_spec.cr
index 75c0bac3ebee..63da166aba45 100644
--- a/spec/compiler/parser/to_s_spec.cr
+++ b/spec/compiler/parser/to_s_spec.cr
@@ -148,6 +148,25 @@ describe "ASTNode#to_s" do
   expect_to_s %(lib Foo\n  struct Foo\n    a : Void\n    b : Void\n  end\nend)
   expect_to_s %(lib Foo\n  union Foo\n    a : Int\n    b : Int32\n  end\nend)
   expect_to_s %(lib Foo\n  FOO = 0\nend)
+  expect_to_s <<-CRYSTAL, <<-CRYSTAL
+    lib Foo
+      A = Pointer(Void).new(0)
+      struct B
+        x : Void*
+        y : Int[1]
+      end
+      fun c(Void*) : Char[2]*
+    end
+    CRYSTAL
+    lib Foo
+      A = Pointer(Void).new(0)
+      struct B
+        x : ::Pointer(Void)
+        y : ::StaticArray(Int, 1)
+      end
+      fun c(::Pointer(Void)) : ::Pointer(::StaticArray(Char, 2))
+    end
+    CRYSTAL
   expect_to_s %(lib LibC\n  fun getch = "get.char"\nend)
   expect_to_s %(lib Foo::Bar\nend)
   expect_to_s %(enum Foo\n  A = 0\n  B\nend)
diff --git a/spec/compiler/semantic/restrictions_augmenter_spec.cr b/spec/compiler/semantic/restrictions_augmenter_spec.cr
index b3798dc257c0..5095f8613943 100644
--- a/spec/compiler/semantic/restrictions_augmenter_spec.cr
+++ b/spec/compiler/semantic/restrictions_augmenter_spec.cr
@@ -272,7 +272,7 @@ describe "Semantic: restrictions augmenter" do
   it "augments typedef" do
     before = <<-CRYSTAL
       lib LibFoo
-        type X = Void*
+        type X = Int32
       end
       class Foo
         @x : LibFoo::X
@@ -284,7 +284,7 @@ describe "Semantic: restrictions augmenter" do
 
     after = <<-CRYSTAL
       lib LibFoo
-        type X = Void*
+        type X = Int32
       end
       class Foo
         @x : LibFoo::X
diff --git a/src/compiler/crystal/syntax/to_s.cr b/src/compiler/crystal/syntax/to_s.cr
index bf8eff6aef2d..f5086e346277 100644
--- a/src/compiler/crystal/syntax/to_s.cr
+++ b/src/compiler/crystal/syntax/to_s.cr
@@ -28,7 +28,6 @@ module Crystal
     def initialize(@str = IO::Memory.new, @macro_expansion_pragmas = nil, @emit_doc = false)
       @indent = 0
       @inside_macro = 0
-      @inside_lib = false
     end
 
     def visit_any(node)
@@ -847,25 +846,6 @@ module Crystal
     def visit(node : Generic)
       name = node.name
 
-      if @inside_lib && (name.is_a?(Path) && name.names.size == 1)
-        case name.names.first
-        when "Pointer"
-          node.type_vars.first.accept self
-          @str << '*'
-          return false
-        when "StaticArray"
-          if node.type_vars.size == 2
-            node.type_vars[0].accept self
-            @str << '['
-            node.type_vars[1].accept self
-            @str << ']'
-            return false
-          end
-        else
-          # Not a special type
-        end
-      end
-
       node.name.accept self
 
       printed_arg = false
@@ -1131,9 +1111,7 @@ module Crystal
       @str << "lib "
       node.name.accept self
       newline
-      @inside_lib = true
       accept_with_indent(node.body)
-      @inside_lib = false
       append_indent
       @str << "end"
       false

From bb96c5398e001f41b31431eea283a1a28198a84b Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sun, 14 Jan 2024 00:37:42 +0800
Subject: [PATCH 062/105] Support `@[Link]`'s DLL search order in the
 interpreter on Windows (#14146)

---
 spec/compiler/ffi/ffi_spec.cr               | 32 +++++++---
 spec/compiler/loader/msvc_spec.cr           | 65 +++++++++++++++++----
 src/compiler/crystal/codegen/link.cr        |  4 ++
 src/compiler/crystal/interpreter/context.cr | 23 +++++++-
 src/compiler/crystal/loader.cr              | 19 +++---
 src/compiler/crystal/loader/msvc.cr         | 37 ++++++++----
 src/compiler/crystal/loader/unix.cr         | 14 ++++-
 7 files changed, 151 insertions(+), 43 deletions(-)

diff --git a/spec/compiler/ffi/ffi_spec.cr b/spec/compiler/ffi/ffi_spec.cr
index ac16cfc425f2..ec644e45870d 100644
--- a/spec/compiler/ffi/ffi_spec.cr
+++ b/spec/compiler/ffi/ffi_spec.cr
@@ -19,6 +19,22 @@ private record TestStruct,
   d : Float64,
   p : Pointer(Void)
 
+private def dll_search_paths
+  {% if flag?(:msvc) %}
+    [SPEC_CRYSTAL_LOADER_LIB_PATH]
+  {% else %}
+    nil
+  {% end %}
+end
+
+{% if flag?(:unix) %}
+  class Crystal::Loader
+    def self.new(search_paths : Array(String), *, dll_search_paths : Nil)
+      new(search_paths)
+    end
+  end
+{% end %}
+
 describe Crystal::FFI::CallInterface do
   before_all do
     FileUtils.mkdir_p(SPEC_CRYSTAL_LOADER_LIB_PATH)
@@ -33,7 +49,7 @@ describe Crystal::FFI::CallInterface do
     it "simple call" do
       call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.sint64, [] of Crystal::FFI::Type
 
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
       loader.load_library "sum"
       function_pointer = loader.find_symbol("answer")
       return_value = 0_i64
@@ -48,7 +64,7 @@ describe Crystal::FFI::CallInterface do
         Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32,
       ] of Crystal::FFI::Type
 
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
       loader.load_library "sum"
       function_pointer = loader.find_symbol("sum")
 
@@ -71,7 +87,7 @@ describe Crystal::FFI::CallInterface do
         Crystal::FFI::Type.pointer,
       ] of Crystal::FFI::Type
 
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
       loader.load_library "sum"
       function_pointer = loader.find_symbol("sum_primitive_types")
 
@@ -109,7 +125,7 @@ describe Crystal::FFI::CallInterface do
       ]
       call_interface = Crystal::FFI::CallInterface.new Crystal::FFI::Type.struct(struct_fields), struct_fields
 
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
       loader.load_library "sum"
       function_pointer = loader.find_symbol("make_struct")
 
@@ -145,7 +161,7 @@ describe Crystal::FFI::CallInterface do
         ]),
       ] of Crystal::FFI::Type
 
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
       loader.load_library "sum"
       function_pointer = loader.find_symbol("sum_struct")
 
@@ -183,7 +199,7 @@ describe Crystal::FFI::CallInterface do
           ]),
         ] of Crystal::FFI::Type
 
-        loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+        loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
         loader.load_library "sum"
         function_pointer = loader.find_symbol("sum_array")
 
@@ -208,7 +224,7 @@ describe Crystal::FFI::CallInterface do
     it "basic" do
       call_interface = Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint64, [Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32, Crystal::FFI::Type.sint32] of Crystal::FFI::Type, 1
 
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
       loader.load_library "sum"
       function_pointer = loader.find_symbol("sum_variadic")
 
@@ -224,7 +240,7 @@ describe Crystal::FFI::CallInterface do
     it "zero varargs" do
       call_interface = Crystal::FFI::CallInterface.variadic Crystal::FFI::Type.sint64, [Crystal::FFI::Type.sint32] of Crystal::FFI::Type, 1
 
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH])
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: dll_search_paths)
       loader.load_library "sum"
       function_pointer = loader.find_symbol("sum_variadic")
 
diff --git a/spec/compiler/loader/msvc_spec.cr b/spec/compiler/loader/msvc_spec.cr
index 5893d29aee02..e62ba0bd620c 100644
--- a/spec/compiler/loader/msvc_spec.cr
+++ b/spec/compiler/loader/msvc_spec.cr
@@ -45,7 +45,7 @@ describe Crystal::Loader do
 
     describe "#load_file?" do
       it "finds function symbol" do
-        loader = Crystal::Loader.new([] of String)
+        loader = Crystal::Loader.new([] of String, dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         loader.load_file?(File.join(SPEC_CRYSTAL_LOADER_LIB_PATH, Crystal::Loader.library_filename("foo"))).should be_true
         loader.find_symbol?("foo").should_not be_nil
       ensure
@@ -55,7 +55,7 @@ describe Crystal::Loader do
 
     describe "#load_library?" do
       it "library name" do
-        loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+        loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         loader.load_library?("foo").should be_true
         loader.find_symbol?("foo").should_not be_nil
       ensure
@@ -63,7 +63,7 @@ describe Crystal::Loader do
       end
 
       it "full path" do
-        loader = Crystal::Loader.new([] of String)
+        loader = Crystal::Loader.new([] of String, dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         loader.load_library?(File.join(SPEC_CRYSTAL_LOADER_LIB_PATH, Crystal::Loader.library_filename("foo"))).should be_true
         loader.find_symbol?("foo").should_not be_nil
       ensure
@@ -72,7 +72,7 @@ describe Crystal::Loader do
 
       it "does not implicitly find dependencies" do
         build_c_dynlib(compiler_datapath("loader", "bar.c"))
-        loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+        loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         loader.load_library?("bar").should be_true
         loader.find_symbol?("bar").should_not be_nil
         loader.find_symbol?("foo").should be_nil
@@ -83,23 +83,23 @@ describe Crystal::Loader do
       it "lookup in order" do
         build_c_dynlib(compiler_datapath("loader", "foo2.c"))
 
-        help_loader1 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+        help_loader1 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         help_loader1.load_library?("foo").should be_true
         foo_address = help_loader1.find_symbol?("foo").should_not be_nil
 
-        help_loader2 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+        help_loader2 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         help_loader2.load_library?("foo2").should be_true
         foo2_address = help_loader2.find_symbol?("foo").should_not be_nil
 
         foo_address.should_not eq foo2_address
 
-        loader1 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+        loader1 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         loader1.load_library("foo")
         loader1.load_library("foo2")
 
         loader1.find_symbol?("foo").should eq foo_address
 
-        loader2 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+        loader2 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
         loader2.load_library("foo2")
         loader2.load_library("foo")
 
@@ -114,18 +114,59 @@ describe Crystal::Loader do
     end
 
     it "does not find global symbols" do
-      loader = Crystal::Loader.new([] of String)
+      loader = Crystal::Loader.new([] of String, dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
       loader.find_symbol?("__crystal_main").should be_nil
     end
 
     it "validate that lib handles are properly closed" do
-      loader = Crystal::Loader.new([] of String)
+      loader = Crystal::Loader.new([] of String, dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
       expect_raises(Crystal::Loader::LoadError, "undefined reference to `foo'") do
         loader.find_symbol("foo")
       end
     end
   end
 
+  describe "dll_search_paths" do
+    it "supports an arbitrary path different from lib search path" do
+      with_tempfile("loader-dll_search_paths") do |path|
+        FileUtils.mkdir_p(SPEC_CRYSTAL_LOADER_LIB_PATH)
+        FileUtils.mkdir_p(path)
+
+        build_c_dynlib(compiler_datapath("loader", "foo.c"))
+        File.rename(File.join(SPEC_CRYSTAL_LOADER_LIB_PATH, "foo.dll"), File.join(path, "foo.dll"))
+
+        loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String, dll_search_paths: [path])
+        loader.load_library?("foo").should be_true
+      ensure
+        loader.try &.close_all
+
+        FileUtils.rm_rf(path)
+        FileUtils.rm_rf(SPEC_CRYSTAL_LOADER_LIB_PATH)
+      end
+    end
+
+    it "doesn't load DLLs outside dll_search_path or Windows' default search paths" do
+      with_tempfile("loader-dll_search_paths") do |path|
+        FileUtils.mkdir_p(SPEC_CRYSTAL_LOADER_LIB_PATH)
+        FileUtils.mkdir_p(path)
+
+        build_c_dynlib(compiler_datapath("loader", "foo.c"))
+        File.rename(File.join(SPEC_CRYSTAL_LOADER_LIB_PATH, "foo.dll"), File.join(path, "foo.dll"))
+
+        loader1 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String, dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
+        loader1.load_library?("foo").should be_false
+        loader2 = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+        loader2.load_library?("foo").should be_false
+      ensure
+        loader2.try &.close_all
+        loader1.try &.close_all
+
+        FileUtils.rm_rf(path)
+        FileUtils.rm_rf(SPEC_CRYSTAL_LOADER_LIB_PATH)
+      end
+    end
+  end
+
   describe "lib suffix" do
     before_all do
       FileUtils.mkdir_p(SPEC_CRYSTAL_LOADER_LIB_PATH)
@@ -137,7 +178,7 @@ describe Crystal::Loader do
 
     it "respects -dynamic" do
       build_c_dynlib(compiler_datapath("loader", "foo.c"), lib_name: "foo-dynamic")
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
       loader.load_library?("foo").should be_true
     ensure
       loader.close_all if loader
@@ -145,7 +186,7 @@ describe Crystal::Loader do
 
     it "ignores -static" do
       build_c_dynlib(compiler_datapath("loader", "foo.c"), lib_name: "bar-static")
-      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH] of String)
+      loader = Crystal::Loader.new([SPEC_CRYSTAL_LOADER_LIB_PATH], dll_search_paths: [SPEC_CRYSTAL_LOADER_LIB_PATH])
       loader.load_library?("bar").should be_false
     ensure
       loader.close_all if loader
diff --git a/src/compiler/crystal/codegen/link.cr b/src/compiler/crystal/codegen/link.cr
index cc703ec81eef..d9910d64c7a8 100644
--- a/src/compiler/crystal/codegen/link.cr
+++ b/src/compiler/crystal/codegen/link.cr
@@ -232,6 +232,10 @@ module Crystal
       flags.join(" ")
     end
 
+    # Searches among CRYSTAL_LIBRARY_PATH, the compiler's directory, and PATH
+    # for every DLL specified in the used `@[Link]` annotations. Yields the
+    # absolute path and `true` if found, the base name and `false` if not found.
+    # The directories should match `Crystal::Repl::Context#dll_search_paths`
     def each_dll_path(& : String, Bool ->)
       executable_path = nil
       compiler_origin = nil
diff --git a/src/compiler/crystal/interpreter/context.cr b/src/compiler/crystal/interpreter/context.cr
index d597810b36de..2d5da06dcf15 100644
--- a/src/compiler/crystal/interpreter/context.cr
+++ b/src/compiler/crystal/interpreter/context.cr
@@ -409,7 +409,7 @@ class Crystal::Repl::Context
     # (MSVC doesn't seem to have this issue)
     args.delete("-lgc")
 
-    Crystal::Loader.parse(args).tap do |loader|
+    Crystal::Loader.parse(args, dll_search_paths: dll_search_paths).tap do |loader|
       # FIXME: Part 2: This is a workaround for initial integration of the interpreter:
       # We append a handle to the current executable (i.e. the compiler program)
       # to the loader's handle list. This gives the loader access to all the symbols in the compiler program,
@@ -427,6 +427,27 @@ class Crystal::Repl::Context
     end
   }
 
+  # Extra DLL search paths to mimic compiled code's DLL-copying behavior
+  # regarding `@[Link]` annotations. These directories should match the ones
+  # used in `Crystal::Program#each_dll_path`
+  private def dll_search_paths
+    {% if flag?(:msvc) %}
+      paths = CrystalLibraryPath.paths
+
+      if executable_path = Process.executable_path
+        paths << File.dirname(executable_path)
+      end
+
+      ENV["PATH"]?.try &.split(Process::PATH_DELIMITER, remove_empty: true) do |path|
+        paths << path
+      end
+
+      paths
+    {% else %}
+      nil
+    {% end %}
+  end
+
   def c_function(name : String)
     loader.find_symbol(name)
   end
diff --git a/src/compiler/crystal/loader.cr b/src/compiler/crystal/loader.cr
index d7d0133cc993..5a147dad590f 100644
--- a/src/compiler/crystal/loader.cr
+++ b/src/compiler/crystal/loader.cr
@@ -14,6 +14,7 @@ class Crystal::Loader
   class LoadError < Exception
     property args : Array(String)?
     property search_paths : Array(String)?
+    property dll_search_paths : Array(String)?
 
     def message
       String.build do |io|
@@ -26,28 +27,26 @@ class Crystal::Loader
           io << "\nSearch path: "
           search_paths.join(io, Process::PATH_DELIMITER)
         end
+        if dll_search_paths = @dll_search_paths
+          io << "\nDLL search path: "
+          dll_search_paths.join(io, Process::PATH_DELIMITER)
+        end
       end
     end
   end
 
-  def self.new(search_paths : Array(String), libnames : Array(String), file_paths : Array(String)) : self
-    loader = new(search_paths)
-
+  def load_all(libnames : Array(String), file_paths : Array(String))
     file_paths.each do |path|
-      loader.load_file(::Path[path].expand)
+      load_file(::Path[path].expand)
     end
     libnames.each do |libname|
-      loader.load_library(libname)
+      load_library(libname)
     end
-    loader
   end
 
   getter search_paths : Array(String)
   getter loaded_libraries = [] of String
-
-  def initialize(@search_paths : Array(String))
-    @handles = [] of Handle
-  end
+  @handles = [] of Handle
 
   # def self.library_filename(libname : String) : String
   #   raise NotImplementedError.new("library_filename")
diff --git a/src/compiler/crystal/loader/msvc.cr b/src/compiler/crystal/loader/msvc.cr
index e9fdc9af5bbd..60aca1aae333 100644
--- a/src/compiler/crystal/loader/msvc.cr
+++ b/src/compiler/crystal/loader/msvc.cr
@@ -5,9 +5,9 @@ require "crystal/system/win32/library_archive"
 # `link.exe`, using the Win32 DLL API.
 #
 # * Only dynamic libraries can be loaded. Static libraries and object files
-#   are unsupported. in particular, `LibC.printf` and `LibC.snprintf`are inline
-#   functions in `legacy-stdio_definitions.lib` since VS2015, so they are never
-#   found by the loader.
+#   are unsupported. For example, `LibC.printf` and `LibC.snprintf` are inline
+#   functions in `legacy_stdio_definitions.lib` since VS2015, so they are never
+#   found by the loader (this is why stdlib no longer uses those functions).
 # * Unlike the Unix counterpart, symbols in the current module do not clash with
 #   the ones in DLLs or their corresponding import libraries.
 
@@ -18,16 +18,28 @@ class Crystal::Loader
     include SystemError
   end
 
+  getter dll_search_paths : Array(String)?
+
+  def initialize(@search_paths : Array(String), @dll_search_paths : Array(String)? = nil)
+  end
+
   # Parses linker arguments in the style of `link.exe`.
-  def self.parse(args : Array(String), *, search_paths : Array(String) = default_search_paths) : self
+  #
+  # The directories in *dll_search_paths* are tried before Windows' search order
+  # when looking for DLLs corresponding to an import library. The compiler uses
+  # this to mimic `@[Link]`'s DLL-copying behavior for compiled code.
+  def self.parse(args : Array(String), *, search_paths : Array(String) = default_search_paths, dll_search_paths : Array(String)? = nil) : self
     search_paths, libnames = parse_args(args, search_paths)
     file_paths = [] of String
 
     begin
-      self.new(search_paths, libnames, file_paths)
+      loader = new(search_paths, dll_search_paths)
+      loader.load_all(libnames, file_paths)
+      loader
     rescue exc : LoadError
       exc.args = args
       exc.search_paths = search_paths
+      exc.dll_search_paths = dll_search_paths
       raise exc
     end
   end
@@ -127,14 +139,19 @@ class Crystal::Loader
     # files, whose base names may not match the library's. Thus it is necessary
     # to extract this information from the library archive itself.
     System::LibraryArchive.imported_dlls(path).each do |dll|
-      # always consider the `.dll` in the same directory as the `.lib` first,
-      # regardless of the search order
-      first_path = File.join(File.dirname(path), dll)
-      dll = first_path if File.file?(first_path)
+      dll_full_path = @dll_search_paths.try &.each do |search_path|
+        full_path = File.join(search_path, dll)
+        break full_path if File.file?(full_path)
+      end
+      dll = dll_full_path || dll
 
       # TODO: `dll` is an unqualified name, e.g. `SHELL32.dll`, so the default
-      # DLL search order is used; consider getting rid of the cwd
+      # DLL search order is used if *dll_full_path* is nil; consider getting rid
+      # of the current working directory altogether
       # (https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order)
+      #
+      # Note that the compiler's directory and PATH are effectively searched
+      # twice when coming from the interpreter
       handle = open_library(dll)
       return false unless handle
 
diff --git a/src/compiler/crystal/loader/unix.cr b/src/compiler/crystal/loader/unix.cr
index 39fef6e0c318..46bca67341cc 100644
--- a/src/compiler/crystal/loader/unix.cr
+++ b/src/compiler/crystal/loader/unix.cr
@@ -35,8 +35,16 @@ class Crystal::Loader
     end
   end
 
+  def initialize(@search_paths : Array(String))
+  end
+
   # Parses linker arguments in the style of `ld`.
-  def self.parse(args : Array(String), *, search_paths : Array(String) = default_search_paths) : self
+  #
+  # *dll_search_paths* has no effect. (Technically speaking, `LD_LIBRARY_PATH`
+  # goes here and `LIBRARY_PATH` goes into *search_paths*, but there is little
+  # point in doing so since the same library files are used at both compile and
+  # run time.)
+  def self.parse(args : Array(String), *, search_paths : Array(String) = default_search_paths, dll_search_paths : Array(String)? = nil) : self
     libnames = [] of String
     file_paths = [] of String
 
@@ -73,7 +81,9 @@ class Crystal::Loader
     search_paths = extra_search_paths + search_paths
 
     begin
-      self.new(search_paths, libnames, file_paths)
+      loader = new(search_paths)
+      loader.load_all(libnames, file_paths)
+      loader
     rescue exc : LoadError
       exc.args = args
       exc.search_paths = search_paths

From f8b52134b39d023a29b89e5c75089a322b0c9961 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 16 Jan 2024 14:11:03 +0100
Subject: [PATCH 063/105] Add macro methods for lib-related nodes (#14218)

---
 spec/compiler/macro/macro_methods_spec.cr | 121 +++++++++++++
 src/compiler/crystal/macros.cr            | 200 +++++++++++++++++++---
 src/compiler/crystal/macros/methods.cr    |  91 ++++++++++
 3 files changed, 391 insertions(+), 21 deletions(-)

diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr
index 13b063355c33..5142ad86c5bd 100644
--- a/spec/compiler/macro/macro_methods_spec.cr
+++ b/spec/compiler/macro/macro_methods_spec.cr
@@ -3280,6 +3280,127 @@ module Crystal
       end
     end
 
+    describe LibDef do
+      lib_def = LibDef.new(Path.new("Foo", "Bar", global: true), FunDef.new("foo"))
+
+      it "executes kind" do
+        assert_macro %({{x.kind}}), %(lib), {x: lib_def}
+      end
+
+      it "executes name" do
+        assert_macro %({{x.name}}), %(::Foo::Bar), {x: lib_def}
+        assert_macro %({{x.name(generic_args: true)}}), %(::Foo::Bar), {x: lib_def}
+        assert_macro %({{x.name(generic_args: false)}}), %(::Foo::Bar), {x: lib_def}
+        assert_macro_error %({{x.name(generic_args: 99)}}), "named argument 'generic_args' to LibDef#name must be a BoolLiteral, not NumberLiteral", {x: lib_def}
+      end
+
+      it "executes body" do
+        assert_macro %({{x.body}}), %(fun foo), {x: lib_def}
+      end
+    end
+
+    describe CStructOrUnionDef do
+      c_struct_def = CStructOrUnionDef.new("Foo", TypeDeclaration.new("x".var, "Int".path))
+      c_union_def = CStructOrUnionDef.new("Bar", Include.new("Foo".path), union: true)
+
+      it "executes kind" do
+        assert_macro %({{x.kind}}), %(struct), {x: c_struct_def}
+        assert_macro %({{x.kind}}), %(union), {x: c_union_def}
+      end
+
+      it "executes name" do
+        assert_macro %({{x.name}}), %(Foo), {x: c_struct_def}
+        assert_macro %({{x.name(generic_args: true)}}), %(Foo), {x: c_struct_def}
+        assert_macro %({{x.name(generic_args: false)}}), %(Foo), {x: c_struct_def}
+        assert_macro_error %({{x.name(generic_args: 99)}}), "named argument 'generic_args' to CStructOrUnionDef#name must be a BoolLiteral, not NumberLiteral", {x: c_struct_def}
+      end
+
+      it "executes body" do
+        assert_macro %({{x.body}}), %(x : Int), {x: c_struct_def}
+        assert_macro %({{x.body}}), %(include Foo), {x: c_union_def}
+      end
+
+      it "executes union?" do
+        assert_macro %({{x.union?}}), %(false), {x: c_struct_def}
+        assert_macro %({{x.union?}}), %(true), {x: c_union_def}
+      end
+    end
+
+    describe FunDef do
+      lib_fun = FunDef.new("foo")
+      top_level_fun = FunDef.new("bar", [Arg.new("x", restriction: "Int32".path), Arg.new("", restriction: "Char".path)], "Void".path, true, 1.int32, "y.z")
+      top_level_fun2 = FunDef.new("baz", body: Nop.new)
+
+      it "executes name" do
+        assert_macro %({{x.name}}), %(foo), {x: lib_fun}
+        assert_macro %({{x.name}}), %(bar), {x: top_level_fun}
+      end
+
+      it "executes real_name" do
+        assert_macro %({{x.real_name}}), %(), {x: lib_fun}
+        assert_macro %({{x.real_name}}), %("y.z"), {x: top_level_fun}
+      end
+
+      it "executes args" do
+        assert_macro %({{x.args}}), %([]), {x: lib_fun}
+        assert_macro %({{x.args}}), %([x : Int32,  : Char]), {x: top_level_fun}
+      end
+
+      it "executes variadic?" do
+        assert_macro %({{x.variadic?}}), %(false), {x: lib_fun}
+        assert_macro %({{x.variadic?}}), %(true), {x: top_level_fun}
+      end
+
+      it "executes return_type" do
+        assert_macro %({{x.return_type}}), %(), {x: lib_fun}
+        assert_macro %({{x.return_type}}), %(Void), {x: top_level_fun}
+      end
+
+      it "executes body" do
+        assert_macro %({{x.body}}), %(), {x: lib_fun}
+        assert_macro %({{x.body}}), %(1), {x: top_level_fun}
+        assert_macro %({{x.body}}), %(), {x: top_level_fun2}
+      end
+
+      it "executes has_body?" do
+        assert_macro %({{x.has_body?}}), %(false), {x: lib_fun}
+        assert_macro %({{x.has_body?}}), %(true), {x: top_level_fun}
+        assert_macro %({{x.has_body?}}), %(true), {x: top_level_fun2}
+      end
+    end
+
+    describe TypeDef do
+      type_def = TypeDef.new("Foo", Path.new("Bar", "Baz", global: true))
+
+      it "executes name" do
+        assert_macro %({{x.name}}), %(Foo), {x: type_def}
+      end
+
+      it "executes type" do
+        assert_macro %({{x.type}}), %(::Bar::Baz), {x: type_def}
+      end
+    end
+
+    describe ExternalVar do
+      external_var1 = ExternalVar.new("foo", Path.new("Bar", "Baz"))
+      external_var2 = ExternalVar.new("X", Generic.new(Path.global("Pointer"), ["Char".path] of ASTNode), real_name: "y.z")
+
+      it "executes name" do
+        assert_macro %({{x.name}}), %(foo), {x: external_var1}
+        assert_macro %({{x.name}}), %(X), {x: external_var2}
+      end
+
+      it "executes real_name" do
+        assert_macro %({{x.real_name}}), %(), {x: external_var1}
+        assert_macro %({{x.real_name}}), %("y.z"), {x: external_var2}
+      end
+
+      it "executes type" do
+        assert_macro %({{x.type}}), %(Bar::Baz), {x: external_var1}
+        assert_macro %({{x.type}}), %(::Pointer(Char)), {x: external_var2}
+      end
+    end
+
     describe "env" do
       it "has key" do
         with_env("FOO": "foo") do
diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr
index 90c802bad25e..c18782dac954 100644
--- a/src/compiler/crystal/macros.cr
+++ b/src/compiler/crystal/macros.cr
@@ -1806,6 +1806,185 @@ module Crystal::Macros
     end
   end
 
+  # A lib definition.
+  #
+  # Every lib definition `node` is equivalent to:
+  #
+  # ```
+  # {% begin %}
+  #   {{ node.kind }} {{ node.name }}
+  #     {{ node.body }}
+  #   end
+  # {% end %}
+  # ```
+  class LibDef < ASTNode
+    # Returns the keyword used to define this type.
+    #
+    # For `LibDef` this is always `lib`.
+    def kind : MacroId
+    end
+
+    # Returns the name of this type definition.
+    #
+    # *generic_args* has no effect. It exists solely to match the interface of
+    # other related AST nodes.
+    def name(*, generic_args : BoolLiteral = true) : Path
+    end
+
+    # Returns the body of this type definition.
+    def body : ASTNode
+    end
+  end
+
+  # A struct or union definition inside a lib.
+  #
+  # Every type definition `node` is equivalent to:
+  #
+  # ```
+  # {% begin %}
+  #   {{ node.kind }} {{ node.name }}
+  #     {{ node.body }}
+  #   end
+  # {% end %}
+  # ```
+  class CStructOrUnionDef < ASTNode
+    # Returns whether this node defines a C union.
+    def union? : BoolLiteral
+    end
+
+    # Returns the keyword used to define this type.
+    #
+    # For `CStructOrUnionDef` this is either `struct` or `union`.
+    def kind : MacroId
+    end
+
+    # Returns the name of this type definition.
+    #
+    # *generic_args* has no effect. It exists solely to match the interface of
+    # other related AST nodes.
+    def name(*, generic_args : BoolLiteral = true) : Path
+    end
+
+    # Returns the body of this type definition.
+    def body : ASTNode
+    end
+  end
+
+  # A function declaration inside a lib, or a top-level C function definition.
+  #
+  # Every function `node` is equivalent to:
+  #
+  # ```
+  # fun {{ node.name }} {% if real_name = node.real_name %}= {{ real_name }}{% end %}(
+  #   {% for arg in node.args %} {{ arg }}, {% end %}
+  #   {% if node.variadic? %} ... {% end %}
+  # ) {% if return_type = node.return_type %}: {{ return_type }}{% end %}
+  # {% if node.has_body? %}
+  #   {{ body }}
+  # end
+  # {% end %}
+  # ```
+  class FunDef < ASTNode
+    # Returns the name of the function in Crystal.
+    def name : MacroId
+    end
+
+    # Returns the real C name of the function, if any.
+    def real_name : StringLiteral | Nop
+    end
+
+    # Returns the parameters of the function.
+    #
+    # This does not include the variadic parameter.
+    def args : ArrayLiteral(Arg)
+    end
+
+    # Returns whether the function is variadic.
+    def variadic? : BoolLiteral
+    end
+
+    # Returns the return type of the function, if specified.
+    def return_type : ASTNode | Nop
+    end
+
+    # Returns the body of the function, if any.
+    #
+    # Both top-level funs and lib funs may return a `Nop`. Instead, `#has_body?`
+    # can be used to distinguish between the two.
+    #
+    # ```
+    # macro body_class(x)
+    #   {{ (x.is_a?(LibDef) ? x.body : x).body.class_name }}
+    # end
+    #
+    # body_class(lib MyLib
+    #   fun foo
+    # end) # => "Nop"
+    #
+    # body_class(fun foo
+    # end) # => "Nop"
+    # ```
+    def body : ASTNode | Nop
+    end
+
+    # Returns whether this function has a body.
+    #
+    # Top-level funs have a body, whereas lib funs do not.
+    #
+    # ```
+    # macro has_body(x)
+    #   {{ (x.is_a?(LibDef) ? x.body : x).has_body? }}
+    # end
+    #
+    # has_body(lib MyLib
+    #   fun foo
+    # end) # => false
+    #
+    # has_body(fun foo
+    # end) # => true
+    # ```
+    def has_body? : BoolLiteral
+    end
+  end
+
+  # A typedef inside a lib.
+  #
+  # Every typedef `node` is equivalent to:
+  #
+  # ```
+  # type {{ node.name }} = {{ node.type }}
+  # ```
+  class TypeDef < ASTNode
+    # Returns the name of the typedef.
+    def name : Path
+    end
+
+    # Returns the name of the type this typedef is equivalent to.
+    def type : ASTNode
+    end
+  end
+
+  # An external variable declaration inside a lib.
+  #
+  # Every variable `node` is equivalent to:
+  #
+  # ```
+  # ${{ node.name }} {% if real_name = node.real_name %}= {{ real_name }}{% end %} : {{ node.type }}
+  # ```
+  class ExternalVar < ASTNode
+    # Returns the name of the variable in Crystal, without the preceding `$`.
+    def name : MacroId
+    end
+
+    # Returns the real C name of the variable, if any.
+    def real_name : StringLiteral | Nop
+    end
+
+    # Returns the name of the variable's type.
+    def type : ASTNode
+    end
+  end
+
   # A `while` expression
   class While < ASTNode
     # Returns this while's condition.
@@ -2034,27 +2213,6 @@ module Crystal::Macros
     end
   end
 
-  # class LibDef < ASTNode
-  # end
-
-  # class FunDef < ASTNode
-  # end
-
-  # class TypeDef < ASTNode
-  # end
-
-  # abstract class CStructOrUnionDef < ASTNode
-  # end
-
-  # class StructDef < CStructOrUnionDef
-  # end
-
-  # class UnionDef < CStructOrUnionDef
-  # end
-
-  # class ExternalVar < ASTNode
-  # end
-
   # class Alias < ASTNode
   # end
 
diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr
index abef63c402d3..39ec31828328 100644
--- a/src/compiler/crystal/macros/methods.cr
+++ b/src/compiler/crystal/macros/methods.cr
@@ -2522,6 +2522,97 @@ module Crystal
       end
     end
   end
+
+  class LibDef
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "kind"
+        interpret_check_args { MacroId.new("lib") }
+      when "name"
+        interpret_check_args(named_params: ["generic_args"]) do
+          # parse the argument, but ignore it otherwise
+          parse_generic_args_argument(self, method, named_args, default: true)
+          @name
+        end
+      when "body"
+        interpret_check_args { @body }
+      else
+        super
+      end
+    end
+  end
+
+  class CStructOrUnionDef
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "kind"
+        interpret_check_args { MacroId.new(@union ? "union" : "struct") }
+      when "name"
+        interpret_check_args(named_params: ["generic_args"]) do
+          # parse the argument, but ignore it otherwise
+          parse_generic_args_argument(self, method, named_args, default: true)
+          Path.new(@name)
+        end
+      when "body"
+        interpret_check_args { @body }
+      when "union?"
+        interpret_check_args { BoolLiteral.new(@union) }
+      else
+        super
+      end
+    end
+  end
+
+  class FunDef
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "name"
+        interpret_check_args { MacroId.new(@name) }
+      when "real_name"
+        interpret_check_args { @real_name != @name ? StringLiteral.new(@real_name) : Nop.new }
+      when "args"
+        interpret_check_args { ArrayLiteral.map(@args, &.itself) }
+      when "variadic?"
+        interpret_check_args { BoolLiteral.new(@varargs) }
+      when "return_type"
+        interpret_check_args { @return_type || Nop.new }
+      when "body"
+        interpret_check_args { @body || Nop.new }
+      when "has_body?"
+        interpret_check_args { BoolLiteral.new(!@body.nil?) }
+      else
+        super
+      end
+    end
+  end
+
+  class TypeDef
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "name"
+        interpret_check_args { Path.new(@name).at(@name_location) }
+      when "type"
+        interpret_check_args { @type_spec }
+      else
+        super
+      end
+    end
+  end
+
+  class ExternalVar
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "name"
+        interpret_check_args { MacroId.new(@name) }
+      when "real_name"
+        interpret_check_args { (real_name = @real_name) ? StringLiteral.new(real_name) : Nop.new }
+      when "type"
+        interpret_check_args { @type_spec }
+      else
+        super
+      end
+    end
+  end
 end
 
 private def get_named_annotation_args(object)

From 261f46f540d398e826fdf44b31ec591fb01cf031 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Tue, 16 Jan 2024 19:39:51 +0100
Subject: [PATCH 064/105] Fix missing `cause` parameter from
 `IO::Error#initialize` (#14242)

---
 spec/std/io/io_spec.cr | 10 ++++++++++
 src/io/error.cr        |  4 ++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/spec/std/io/io_spec.cr b/spec/std/io/io_spec.cr
index e2c065ecebf0..2c53df75205e 100644
--- a/spec/std/io/io_spec.cr
+++ b/spec/std/io/io_spec.cr
@@ -1013,4 +1013,14 @@ describe IO do
   typeof(STDIN.cooked!)
   typeof(STDIN.raw { })
   typeof(STDIN.raw!)
+
+  describe IO::Error do
+    describe ".new" do
+      it "accepts `cause` argument (#14241)" do
+        cause = Exception.new("cause")
+        error = IO::Error.new("foo", cause: cause)
+        error.cause.should be cause
+      end
+    end
+  end
 end
diff --git a/src/io/error.cr b/src/io/error.cr
index 4c6d30952f13..ec0374040699 100644
--- a/src/io/error.cr
+++ b/src/io/error.cr
@@ -16,10 +16,10 @@ class IO
       "#{message} (#{target})"
     end
 
-    def initialize(message : String? = nil, *, target = nil)
+    def initialize(message : String? = nil, cause : Exception? = nil, *, target = nil)
       @target = target.try(&.to_s)
 
-      super message
+      super message, cause
     end
   end
 

From 045547a1715868d8b8bca272c64fc82a2677fd98 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 17 Jan 2024 12:17:03 +0100
Subject: [PATCH 065/105] Drop flag `openbsd6.2` (#14233)

---
 src/crystal/system/unix/fiber.cr | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/crystal/system/unix/fiber.cr b/src/crystal/system/unix/fiber.cr
index 17cbe5c07fdb..2a06b3d3d1a1 100644
--- a/src/crystal/system/unix/fiber.cr
+++ b/src/crystal/system/unix/fiber.cr
@@ -3,7 +3,7 @@ require "c/sys/mman"
 module Crystal::System::Fiber
   def self.allocate_stack(stack_size) : Void*
     flags = LibC::MAP_PRIVATE | LibC::MAP_ANON
-    {% if flag?(:openbsd) && !flag?(:"openbsd6.2") %}
+    {% if flag?(:openbsd) %}
       flags |= LibC::MAP_STACK
     {% end %}
 

From 97ca775f2f03d18000972ad16d8f96fa15f29f10 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Thu, 11 Jan 2024 06:26:03 +0800
Subject: [PATCH 066/105] Always use `%p` for pointers in
 `Crystal::System.print_error` (#14186)

---
 src/crystal/system/unix/signal.cr     | 2 +-
 src/exception/call_stack/libunwind.cr | 2 +-
 src/exception/call_stack/stackwalk.cr | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/crystal/system/unix/signal.cr b/src/crystal/system/unix/signal.cr
index c30a2b985af2..f7c0ad31e326 100644
--- a/src/crystal/system/unix/signal.cr
+++ b/src/crystal/system/unix/signal.cr
@@ -149,7 +149,7 @@ module Crystal::System::Signal
     if is_stack_overflow
       Crystal::System.print_error "Stack overflow (e.g., infinite or very deep recursion)\n"
     else
-      Crystal::System.print_error "Invalid memory access (signal %d) at address 0x%lx\n", sig, addr
+      Crystal::System.print_error "Invalid memory access (signal %d) at address %p\n", sig, addr
     end
 
     Exception::CallStack.print_backtrace
diff --git a/src/exception/call_stack/libunwind.cr b/src/exception/call_stack/libunwind.cr
index 220db21b71f0..81943d99f376 100644
--- a/src/exception/call_stack/libunwind.cr
+++ b/src/exception/call_stack/libunwind.cr
@@ -102,7 +102,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[0x%llx] ", repeated_frame.ip.address.to_u64
+    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"
diff --git a/src/exception/call_stack/stackwalk.cr b/src/exception/call_stack/stackwalk.cr
index f49c87fae623..4879ed8bb95d 100644
--- a/src/exception/call_stack/stackwalk.cr
+++ b/src/exception/call_stack/stackwalk.cr
@@ -37,7 +37,7 @@ struct Exception::CallStack
       case exception_info.value.exceptionRecord.value.exceptionCode
       when LibC::EXCEPTION_ACCESS_VIOLATION
         addr = exception_info.value.exceptionRecord.value.exceptionInformation[1]
-        Crystal::System.print_error "Invalid memory access (C0000005) at address 0x%llx\n", addr
+        Crystal::System.print_error "Invalid memory access (C0000005) at address %p\n", Pointer(Void).new(addr)
         print_backtrace(exception_info)
         LibC._exit(1)
       when LibC::EXCEPTION_STACK_OVERFLOW
@@ -150,7 +150,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[0x%llx] ", repeated_frame.ip.address.to_u64
+    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"

From 4e6531aaf6cfcb8aed6c783137387337481cb3c1 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 13 Jan 2024 19:38:41 +0800
Subject: [PATCH 067/105] Fix: Always use `%p` for pointers in
 `Crystal::System.print_error` (#14221)

---
 src/exception/call_stack/libunwind.cr | 2 +-
 src/exception/call_stack/stackwalk.cr | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/exception/call_stack/libunwind.cr b/src/exception/call_stack/libunwind.cr
index 81943d99f376..9f17512491fe 100644
--- a/src/exception/call_stack/libunwind.cr
+++ b/src/exception/call_stack/libunwind.cr
@@ -102,7 +102,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
+    Crystal::System.print_error "[%p] ", repeated_frame.ip
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"
diff --git a/src/exception/call_stack/stackwalk.cr b/src/exception/call_stack/stackwalk.cr
index 4879ed8bb95d..a6a400b1befd 100644
--- a/src/exception/call_stack/stackwalk.cr
+++ b/src/exception/call_stack/stackwalk.cr
@@ -150,7 +150,7 @@ struct Exception::CallStack
   end
 
   private def self.print_frame(repeated_frame)
-    Crystal::System.print_error "[%p] ", repeated_frame.ip.address
+    Crystal::System.print_error "[%p] ", repeated_frame.ip
     print_frame_location(repeated_frame)
     Crystal::System.print_error " (%d times)", repeated_frame.count + 1 unless repeated_frame.count == 0
     Crystal::System.print_error "\n"

From fda656c7134138e013e89281e74a4f3761b53fd7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Thu, 18 Jan 2024 14:36:11 +0100
Subject: [PATCH 068/105] Changelog for 1.11.2 (#14249)

---
 CHANGELOG.md | 16 ++++++++++++++++
 src/VERSION  |  2 +-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 658d9f42f822..4e152e9ad2d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
 # Changelog
 
+## [1.11.2] (2024-01-18)
+
+[1.11.2]: https://github.com/crystal-lang/crystal/releases/1.11.2
+
+### Bugfixes
+
+#### stdlib
+
+- *(files)* Fix missing `cause` parameter from `IO::Error#initialize` ([#14242](https://github.com/crystal-lang/crystal/pull/14242), thanks @straight-shoota)
+- *(runtime)* Always use `%p` for pointers in `Crystal::System.print_error` ([#14186](https://github.com/crystal-lang/crystal/pull/14186), thanks @HertzDevil)
+- *(runtime)* Fixup for always use `%p` for pointers in `Crystal::System.print_error` ([#14221](https://github.com/crystal-lang/crystal/pull/14221), thanks @HertzDevil)
+
+### Infrastructure
+
+- Changelog for 1.11.2 ([#14249](https://github.com/crystal-lang/crystal/pull/14249), thanks @straight-shoota)
+
 ## [1.11.1] (2024-01-11)
 
 [1.11.1]: https://github.com/crystal-lang/crystal/releases/1.11.1
diff --git a/src/VERSION b/src/VERSION
index 720c7384c619..ca7176690dd6 100644
--- a/src/VERSION
+++ b/src/VERSION
@@ -1 +1 @@
-1.11.1
+1.11.2

From f01de65e852dfb1c21aef609525ff447e96ec66c Mon Sep 17 00:00:00 2001
From: Julien Portalier <julien@portalier.com>
Date: Wed, 24 Jan 2024 11:18:50 +0100
Subject: [PATCH 069/105] MT: reduce interleaved backtraces in spawn unhandled
 exceptions (#14220)

---
 src/fiber.cr | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/fiber.cr b/src/fiber.cr
index c96184f3cf1f..049b7e9bb0c0 100644
--- a/src/fiber.cr
+++ b/src/fiber.cr
@@ -140,12 +140,20 @@ class Fiber
     GC.unlock_read
     @proc.call
   rescue ex
+    io = {% if flag?(:preview_mt) %}
+           IO::Memory.new(4096) # PIPE_BUF
+         {% else %}
+           STDERR
+         {% end %}
     if name = @name
-      STDERR.print "Unhandled exception in spawn(name: #{name}): "
+      io << "Unhandled exception in spawn(name: " << name << "): "
     else
-      STDERR.print "Unhandled exception in spawn: "
+      io << "Unhandled exception in spawn: "
     end
-    ex.inspect_with_backtrace(STDERR)
+    ex.inspect_with_backtrace(io)
+    {% if flag?(:preview_mt) %}
+      STDERR.write(io.to_slice)
+    {% end %}
     STDERR.flush
   ensure
     # Remove the current fiber from the linked list

From 724249fb54858a6eff33895b1144f00ac276ad01 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 24 Jan 2024 11:19:18 +0100
Subject: [PATCH 070/105] Remove filtering of already mentioned PRs (#14229)

---
 scripts/github-changelog.cr | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/scripts/github-changelog.cr b/scripts/github-changelog.cr
index c660a01cd8ca..7397440c3676 100755
--- a/scripts/github-changelog.cr
+++ b/scripts/github-changelog.cr
@@ -262,9 +262,6 @@ array = parser.on_key! "data" do
   end
 end
 
-changelog = File.read("CHANGELOG.md")
-array.select! { |pr| pr.merged_at && !changelog.index(pr.permalink) }
-
 sections = array.group_by(&.section)
 
 SECTION_TITLES = {

From d42b67382b6a97b74ebcb96e6e30531aa1c3a26e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Sat, 27 Jan 2024 15:03:59 +0100
Subject: [PATCH 071/105] Update previous Crystal release - 1.11.2 (#14251)

---
 .circleci/config.yml                     |  2 +-
 .github/workflows/interpreter.yml        |  6 +++---
 .github/workflows/linux.yml              |  2 +-
 .github/workflows/llvm.yml               |  2 +-
 .github/workflows/openssl.yml            |  6 +++---
 .github/workflows/regex-engine.yml       |  4 ++--
 .github/workflows/wasm32.yml             |  2 +-
 .github/workflows/win_build_portable.yml |  2 +-
 bin/ci                                   |  6 +++---
 shell.nix                                | 12 ++++++------
 10 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 548716adb511..2eef408ee4ad 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -12,7 +12,7 @@ parameters:
   previous_crystal_base_url:
     description: "Prefix for URLs to Crystal bootstrap compiler"
     type: string
-    default: "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1"
+    default: "https://github.com/crystal-lang/crystal/releases/download/1.11.2/crystal-1.11.2-1"
 
 defaults:
   environment: &env
diff --git a/.github/workflows/interpreter.yml b/.github/workflows/interpreter.yml
index 96403e595e17..35cf1f916770 100644
--- a/.github/workflows/interpreter.yml
+++ b/.github/workflows/interpreter.yml
@@ -13,7 +13,7 @@ jobs:
   test-interpreter_spec:
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.11.1-build
+      image: crystallang/crystal:1.11.2-build
     name: "Test Interpreter"
     steps:
       - uses: actions/checkout@v4
@@ -24,7 +24,7 @@ jobs:
   build-interpreter:
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.11.1-build
+      image: crystallang/crystal:1.11.2-build
     name: Build interpreter
     steps:
       - uses: actions/checkout@v4
@@ -43,7 +43,7 @@ jobs:
     needs: build-interpreter
     runs-on: ubuntu-22.04
     container:
-      image: crystallang/crystal:1.11.1-build
+      image: crystallang/crystal:1.11.2-build
     strategy:
       matrix:
         part: [0, 1, 2, 3]
diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index f4b284f9ce74..3d85af22e5a3 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -19,7 +19,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1, 1.11.1]
+        crystal_bootstrap_version: [1.7.3, 1.8.2, 1.9.2, 1.10.1, 1.11.2]
         flags: [""]
         include:
           # libffi is only available starting from the 1.2.2 build images
diff --git a/.github/workflows/llvm.yml b/.github/workflows/llvm.yml
index 15fa6df8712c..fe8ad578163a 100644
--- a/.github/workflows/llvm.yml
+++ b/.github/workflows/llvm.yml
@@ -56,7 +56,7 @@ jobs:
       - name: Install Crystal
         uses: crystal-lang/install-crystal@v1
         with:
-          crystal: "1.11.1"
+          crystal: "1.11.2"
 
       - name: Build libllvm_ext
         run: make -B deps
diff --git a/.github/workflows/openssl.yml b/.github/workflows/openssl.yml
index 30b148448416..65766c6325c2 100644
--- a/.github/workflows/openssl.yml
+++ b/.github/workflows/openssl.yml
@@ -10,7 +10,7 @@ jobs:
   openssl3:
     runs-on: ubuntu-latest
     name: "OpenSSL 3.0"
-    container: crystallang/crystal:1.11.1-alpine
+    container: crystallang/crystal:1.11.2-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -27,7 +27,7 @@ jobs:
   openssl111:
     runs-on: ubuntu-latest
     name: "OpenSSL 1.1.1"
-    container: crystallang/crystal:1.11.1-alpine
+    container: crystallang/crystal:1.11.2-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -42,7 +42,7 @@ jobs:
   libressl34:
     runs-on: ubuntu-latest
     name: "LibreSSL 3.4"
-    container: crystallang/crystal:1.11.1-alpine
+    container: crystallang/crystal:1.11.2-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/regex-engine.yml b/.github/workflows/regex-engine.yml
index 523a645085bf..d7d9c2655584 100644
--- a/.github/workflows/regex-engine.yml
+++ b/.github/workflows/regex-engine.yml
@@ -10,7 +10,7 @@ jobs:
   pcre:
     runs-on: ubuntu-latest
     name: "PCRE"
-    container: crystallang/crystal:1.11.1-alpine
+    container: crystallang/crystal:1.11.2-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
@@ -25,7 +25,7 @@ jobs:
   pcre2:
     runs-on: ubuntu-latest
     name: "PCRE2"
-    container: crystallang/crystal:1.11.1-alpine
+    container: crystallang/crystal:1.11.2-alpine
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/wasm32.yml b/.github/workflows/wasm32.yml
index ca3431808c01..c8f2058ebea0 100644
--- a/.github/workflows/wasm32.yml
+++ b/.github/workflows/wasm32.yml
@@ -12,7 +12,7 @@ env:
 jobs:
   wasm32-test:
     runs-on: ubuntu-latest
-    container: crystallang/crystal:1.11.1-build
+    container: crystallang/crystal:1.11.2-build
     steps:
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/.github/workflows/win_build_portable.yml b/.github/workflows/win_build_portable.yml
index 77e823384ef2..d1aa2793d4ff 100644
--- a/.github/workflows/win_build_portable.yml
+++ b/.github/workflows/win_build_portable.yml
@@ -24,7 +24,7 @@ jobs:
       - name: Install Crystal
         uses: crystal-lang/install-crystal@v1
         with:
-          crystal: "1.11.1"
+          crystal: "1.11.2"
 
       - name: Download Crystal source
         uses: actions/checkout@v4
diff --git a/bin/ci b/bin/ci
index 9a3776a3b7d3..9d0b73507f24 100755
--- a/bin/ci
+++ b/bin/ci
@@ -135,8 +135,8 @@ format() {
 prepare_build() {
   on_linux verify_linux_environment
 
-  on_osx curl -L https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-darwin-universal.tar.gz -o ~/crystal.tar.gz
-  on_osx 'pushd ~;gunzip -c ~/crystal.tar.gz | tar xopf -;mv crystal-1.11.1-1 crystal;popd'
+  on_osx curl -L https://github.com/crystal-lang/crystal/releases/download/1.11.2/crystal-1.11.2-1-darwin-universal.tar.gz -o ~/crystal.tar.gz
+  on_osx 'pushd ~;gunzip -c ~/crystal.tar.gz | tar xopf -;mv crystal-1.11.2-1 crystal;popd'
 
   # These commands may take a few minutes to run due to the large size of the repositories.
   # This restriction has been made on GitHub's request because updating shallow
@@ -189,7 +189,7 @@ with_build_env() {
 
   on_linux verify_linux_environment
 
-  export DOCKER_TEST_PREFIX="${DOCKER_TEST_PREFIX:=crystallang/crystal:1.11.1}"
+  export DOCKER_TEST_PREFIX="${DOCKER_TEST_PREFIX:=crystallang/crystal:1.11.2}"
 
   case $ARCH in
     x86_64)
diff --git a/shell.nix b/shell.nix
index 647315af5e70..aef4211f280a 100644
--- a/shell.nix
+++ b/shell.nix
@@ -52,18 +52,18 @@ let
   # Hashes obtained using `nix-prefetch-url --unpack <url>`
   latestCrystalBinary = genericBinary ({
     x86_64-darwin = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-darwin-universal.tar.gz";
-      sha256 = "sha256:1yfb8xzhb3hnf9dn5y0mk25va1hbmk03x0hm9da6805xllr7bq8l";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.2/crystal-1.11.2-1-darwin-universal.tar.gz";
+      sha256 = "sha256:0qcdr8yl6k7il0x63z2gyqbkjp89m77nq7x1h3m80y1imfg0z1q9";
     };
 
     aarch64-darwin = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-darwin-universal.tar.gz";
-      sha256 = "sha256:1yfb8xzhb3hnf9dn5y0mk25va1hbmk03x0hm9da6805xllr7bq8l";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.2/crystal-1.11.2-1-darwin-universal.tar.gz";
+      sha256 = "sha256:0qcdr8yl6k7il0x63z2gyqbkjp89m77nq7x1h3m80y1imfg0z1q9";
     };
 
     x86_64-linux = {
-      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.1/crystal-1.11.1-1-linux-x86_64.tar.gz";
-      sha256 = "sha256:18mqp2sy5df6bkyvndg4xwgjf6lmaipz5mcr6lg9a47is2vr1i7v";
+      url = "https://github.com/crystal-lang/crystal/releases/download/1.11.2/crystal-1.11.2-1-linux-x86_64.tar.gz";
+      sha256 = "sha256:01l9cq8d3p7p3ijkrg0xpchj0l21z3sjvd5f6zw1pnms647a6hdr";
     };
   }.${pkgs.stdenv.system});
 

From ac895ff483789b34079388210f1d4fc37b220227 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 27 Jan 2024 15:04:10 +0100
Subject: [PATCH 072/105] Update GH Actions (#14246)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
 .github/workflows/llvm.yml               |  2 +-
 .github/workflows/macos.yml              |  4 ++--
 .github/workflows/win.yml                | 16 ++++++++--------
 .github/workflows/win_build_portable.yml | 12 ++++++------
 4 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/.github/workflows/llvm.yml b/.github/workflows/llvm.yml
index fe8ad578163a..887ede290fe3 100644
--- a/.github/workflows/llvm.yml
+++ b/.github/workflows/llvm.yml
@@ -33,7 +33,7 @@ jobs:
 
       - name: Cache LLVM
         id: cache-llvm
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: ./llvm
           key: llvm-${{ matrix.llvm_version }}
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index dbab5f5bc93c..765595ce2d09 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -17,12 +17,12 @@ jobs:
       - name: Download Crystal source
         uses: actions/checkout@v4
 
-      - uses: cachix/install-nix-action@v24
+      - uses: cachix/install-nix-action@v25
         with:
           install_url: https://releases.nixos.org/nix/nix-2.9.2/install
           extra_nix_config: |
             experimental-features = nix-command
-      - uses: cachix/cachix-action@v13
+      - uses: cachix/cachix-action@v14
         with:
           name: crystal-ci
           signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml
index c80dcfce8fb6..9fce9f93aa44 100644
--- a/.github/workflows/win.yml
+++ b/.github/workflows/win.yml
@@ -25,7 +25,7 @@ jobs:
 
       - name: Cache libraries
         id: cache-libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: | # openssl and llvm take much longer to build so they are cached separately
             libs/pcre.lib
@@ -68,7 +68,7 @@ jobs:
 
       - name: Cache OpenSSL
         id: cache-openssl
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             libs/crypto.lib
@@ -97,7 +97,7 @@ jobs:
 
       - name: Cache libraries
         id: cache-dlls
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: | # openssl and llvm take much longer to build so they are cached separately
             libs/pcre-dynamic.lib
@@ -149,7 +149,7 @@ jobs:
 
       - name: Cache OpenSSL
         id: cache-openssl-dlls
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             libs/crypto-dynamic.lib
@@ -172,7 +172,7 @@ jobs:
 
       - name: Cache LLVM
         id: cache-llvm-libs
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: llvm
           key: llvm-libs-${{ env.CI_LLVM_VERSION }}-msvc
@@ -219,7 +219,7 @@ jobs:
 
       - name: Cache LLVM
         id: cache-llvm-dlls
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             libs/llvm_VERSION
@@ -258,7 +258,7 @@ jobs:
           path: build
 
       - name: Restore LLVM
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: llvm
           key: llvm-libs-${{ env.CI_LLVM_VERSION }}-msvc
@@ -309,7 +309,7 @@ jobs:
           path: etc/win-ci/portable
 
       - name: Restore LLVM
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: llvm
           key: llvm-libs-${{ env.CI_LLVM_VERSION }}-msvc
diff --git a/.github/workflows/win_build_portable.yml b/.github/workflows/win_build_portable.yml
index d1aa2793d4ff..bab89e04685e 100644
--- a/.github/workflows/win_build_portable.yml
+++ b/.github/workflows/win_build_portable.yml
@@ -30,7 +30,7 @@ jobs:
         uses: actions/checkout@v4
 
       - name: Restore libraries
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: |
             libs/pcre.lib
@@ -45,7 +45,7 @@ jobs:
           key: win-libs-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc
           fail-on-cache-miss: true
       - name: Restore OpenSSL
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: |
             libs/crypto.lib
@@ -54,7 +54,7 @@ jobs:
           key: win-openssl-libs-3.1.0-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc
           fail-on-cache-miss: true
       - name: Restore DLLs
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: |
             libs/pcre-dynamic.lib
@@ -78,7 +78,7 @@ jobs:
           key: win-dlls-${{ hashFiles('.github/workflows/win.yml', 'etc/win-ci/*.ps1') }}-msvc
           fail-on-cache-miss: true
       - name: Restore OpenSSL DLLs
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: |
             libs/crypto-dynamic.lib
@@ -88,13 +88,13 @@ jobs:
           key: win-openssl-dlls-3.1.0-${{ hashFiles('etc/win-ci/build-openssl.ps1') }}-msvc
           fail-on-cache-miss: true
       - name: Restore LLVM
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: llvm
           key: llvm-libs-${{ inputs.llvm_version }}-msvc
           fail-on-cache-miss: true
       - name: Restore LLVM DLLs
-        uses: actions/cache/restore@v3
+        uses: actions/cache/restore@v4
         with:
           path: |
             libs/llvm_VERSION

From 7628de67ea55801ad575623d2a9045b750d5cefa Mon Sep 17 00:00:00 2001
From: Ryan Gonzalez <git@refi64.dev>
Date: Sat, 27 Jan 2024 08:48:32 -0600
Subject: [PATCH 073/105] Add `--frame-pointers` to control preservation of
 frame pointers (#13860)

Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
Co-authored-by: Quinton Miller <nicetas.c@gmail.com>
---
 man/crystal.1                           |  2 ++
 src/compiler/crystal/codegen/codegen.cr | 11 ++++++++---
 src/compiler/crystal/codegen/fun.cr     |  6 +++++-
 src/compiler/crystal/command.cr         |  8 ++++++++
 src/compiler/crystal/compiler.cr        | 12 +++++++++++-
 src/llvm/function.cr                    |  7 +++++++
 src/llvm/lib_llvm/core.cr               |  1 +
 7 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/man/crystal.1 b/man/crystal.1
index 3a2a3d4a1b2a..ef23beac77c3 100644
--- a/man/crystal.1
+++ b/man/crystal.1
@@ -117,6 +117,8 @@ Generate the output without any symbolic debug symbols.
 Define a compile-time flag. This is useful to conditionally define types, methods, or commands based on flags available at compile time. The default flags are from the target triple given with --target-triple or the hosts default, if none is given.
 .It Fl -emit Op asm|llvm-bc|llvm-ir|obj
 Comma separated list of types of output for the compiler to emit. You can use this to see the generated LLVM IR, LLVM bitcode, assembly, and object files.
+.It Fl -frame-pointers Op auto|always|non-leaf
+Control the preservation of frame pointers. The default value, --frame-pointers=auto, will preserve frame pointers on debug builds and try to omit them on release builds (certain platforms require them to stay enabled). --frame-pointers=always will always preserve them, and non-leaf will only force their preservation on non-leaf functions.
 .It Fl f Ar text|json, Fl -format Ar text|json
 Format of output. Defaults to text. The json format can be used to get a more parser-friendly output.
 .It Fl -error-trace
diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr
index 651afa44ca27..a6015012eb7c 100644
--- a/src/compiler/crystal/codegen/codegen.cr
+++ b/src/compiler/crystal/codegen/codegen.cr
@@ -69,8 +69,10 @@ module Crystal
       end
     end
 
-    def codegen(node, single_module = false, debug = Debug::Default)
-      visitor = CodeGenVisitor.new self, node, single_module: single_module, debug: debug
+    def codegen(node, single_module = false, debug = Debug::Default,
+                frame_pointers = FramePointers::Auto)
+      visitor = CodeGenVisitor.new self, node, single_module: single_module,
+        debug: debug, frame_pointers: frame_pointers
       visitor.accept node
       visitor.process_finished_hooks
       visitor.finish
@@ -190,7 +192,10 @@ module Crystal
     @c_malloc_fun : LLVMTypedFunction?
     @c_realloc_fun : LLVMTypedFunction?
 
-    def initialize(@program : Program, @node : ASTNode, @single_module : Bool = false, @debug = Debug::Default)
+    def initialize(@program : Program, @node : ASTNode,
+                   @single_module : Bool = false,
+                   @debug = Debug::Default,
+                   @frame_pointers : FramePointers = :auto)
       @abi = @program.target_machine.abi
       @llvm_context = LLVM::Context.new
       # LLVM::Context.register(@llvm_context, "main")
diff --git a/src/compiler/crystal/codegen/fun.cr b/src/compiler/crystal/codegen/fun.cr
index 9a8e51df3175..784eba83b9b9 100644
--- a/src/compiler/crystal/codegen/fun.cr
+++ b/src/compiler/crystal/codegen/fun.cr
@@ -101,9 +101,13 @@ class Crystal::CodeGenVisitor
           context.fun.add_attribute LLVM::Attribute::UWTable, value: @program.has_flag?("aarch64") ? LLVM::UWTableKind::Sync : LLVM::UWTableKind::Async
         {% end %}
 
-        if @program.has_flag?("darwin")
+        if @frame_pointers.always?
+          context.fun.add_attribute "frame-pointer", value: "all"
+        elsif @program.has_flag?("darwin")
           # Disable frame pointer elimination in Darwin, as it causes issues during stack unwind
           context.fun.add_target_dependent_attribute "frame-pointer", "all"
+        elsif @frame_pointers.non_leaf?
+          context.fun.add_attribute "frame-pointer", value: "non-leaf"
         end
 
         new_entry_block
diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr
index 97bf46feb663..6549c2768aea 100644
--- a/src/compiler/crystal/command.cr
+++ b/src/compiler/crystal/command.cr
@@ -399,6 +399,14 @@ class Crystal::Command
         opts.on("--no-debug", "Skip any symbolic debug info") do
           compiler.debug = Crystal::Debug::None
         end
+
+        opts.on("--frame-pointers auto|always|non-leaf", "Control the preservation of frame pointers") do |value|
+          if frame_pointers = FramePointers.parse?(value)
+            compiler.frame_pointers = frame_pointers
+          else
+            error "Invalid value `#{value}` for frame-pointers"
+          end
+        end
       end
 
       opts.on("-D FLAG", "--define FLAG", "Define a compile-time flag") do |flag|
diff --git a/src/compiler/crystal/compiler.cr b/src/compiler/crystal/compiler.cr
index 283f44289468..899ef242f318 100644
--- a/src/compiler/crystal/compiler.cr
+++ b/src/compiler/crystal/compiler.cr
@@ -16,6 +16,12 @@ module Crystal
     Default     = LineNumbers
   end
 
+  enum FramePointers
+    Auto
+    Always
+    NonLeaf
+  end
+
   # Main interface to the compiler.
   #
   # A Compiler parses source code, type checks it and
@@ -45,6 +51,9 @@ module Crystal
     # code by the `flag?(...)` macro method.
     property flags = [] of String
 
+    # Controls generation of frame pointers.
+    property frame_pointers = FramePointers::Auto
+
     # If `true`, the executable will be generated with debug code
     # that can be understood by `gdb` and `lldb`.
     property debug = Debug::Default
@@ -297,7 +306,8 @@ module Crystal
 
     private def codegen(program, node : ASTNode, sources, output_filename)
       llvm_modules = @progress_tracker.stage("Codegen (crystal)") do
-        program.codegen node, debug: debug, single_module: @single_module || @cross_compile || !@emit_targets.none?
+        program.codegen node, debug: debug, frame_pointers: frame_pointers,
+          single_module: @single_module || @cross_compile || !@emit_targets.none?
       end
 
       output_dir = CacheDir.instance.directory_for(sources)
diff --git a/src/llvm/function.cr b/src/llvm/function.cr
index a586cd6fdde5..d643e74d758b 100644
--- a/src/llvm/function.cr
+++ b/src/llvm/function.cr
@@ -28,6 +28,13 @@ struct LLVM::Function
     end
   end
 
+  def add_attribute(attribute : String, index = AttributeIndex::FunctionIndex, *, value : String)
+    context = LibLLVM.get_module_context(LibLLVM.get_global_parent(self))
+    attribute_ref = LibLLVM.create_string_attribute(context, attribute, attribute.bytesize,
+      value, value.bytesize)
+    LibLLVM.add_attribute_at_index(self, index, attribute_ref)
+  end
+
   def add_attribute(attribute : Attribute, index = AttributeIndex::FunctionIndex, *, value)
     return if attribute.value == 0
 
diff --git a/src/llvm/lib_llvm/core.cr b/src/llvm/lib_llvm/core.cr
index 0645441f8a70..20f10c7e6e62 100644
--- a/src/llvm/lib_llvm/core.cr
+++ b/src/llvm/lib_llvm/core.cr
@@ -25,6 +25,7 @@ lib LibLLVM
   fun get_enum_attribute_kind_for_name = LLVMGetEnumAttributeKindForName(name : Char*, s_len : SizeT) : UInt
   fun get_last_enum_attribute_kind = LLVMGetLastEnumAttributeKind : UInt
   fun create_enum_attribute = LLVMCreateEnumAttribute(c : ContextRef, kind_id : UInt, val : UInt64) : AttributeRef
+  fun create_string_attribute = LLVMCreateStringAttribute(c : ContextRef, k : Char*, k_length : UInt, v : Char*, v_length : UInt) : AttributeRef
   {% unless LibLLVM::IS_LT_120 %}
     fun create_type_attribute = LLVMCreateTypeAttribute(c : ContextRef, kind_id : UInt, type_ref : TypeRef) : AttributeRef
   {% end %}

From 0ff99d97deafc47cf6ef80da8c1f0ece1f9c1343 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Mon, 29 Jan 2024 19:15:46 +0800
Subject: [PATCH 074/105] Add macro methods for `Primitive` (#14263)

---
 spec/compiler/macro/macro_methods_spec.cr |  7 +++++++
 src/compiler/crystal/macros.cr            | 21 +++++++++++++++++++++
 src/compiler/crystal/macros/methods.cr    | 11 +++++++++++
 3 files changed, 39 insertions(+)

diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr
index 5142ad86c5bd..516c3e408280 100644
--- a/spec/compiler/macro/macro_methods_spec.cr
+++ b/spec/compiler/macro/macro_methods_spec.cr
@@ -2505,6 +2505,13 @@ module Crystal
       end
     end
 
+    describe Primitive do
+      it "executes name" do
+        assert_macro %({{x.name}}), %(:abc), {x: Primitive.new("abc")}
+        assert_macro %({{x.name}}), %(:"x.y.z"), {x: Primitive.new("x.y.z")}
+      end
+    end
+
     describe "macro methods" do
       it "executes name" do
         assert_macro %({{x.name}}), "some_macro", {x: Macro.new("some_macro")}
diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr
index c18782dac954..f18c3c7246ab 100644
--- a/src/compiler/crystal/macros.cr
+++ b/src/compiler/crystal/macros.cr
@@ -1407,6 +1407,27 @@ module Crystal::Macros
     end
   end
 
+  # A fictitious node representing the body of a `Def` marked with
+  # `@[Primitive]`.
+  class Primitive < ASTNode
+    # Returns the name of the primitive.
+    #
+    # This is identical to the argument to the associated `@[Primitive]`
+    # annotation.
+    #
+    # ```
+    # module Foo
+    #   @[Primitive(:abc)]
+    #   def foo
+    #   end
+    # end
+    #
+    # {{ Foo.methods.first.body.name }} # => :abc
+    # ```
+    def name : SymbolLiteral
+    end
+  end
+
   # A macro definition.
   class Macro < ASTNode
     # Returns the name of this macro.
diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr
index 39ec31828328..60ecdb528509 100644
--- a/src/compiler/crystal/macros/methods.cr
+++ b/src/compiler/crystal/macros/methods.cr
@@ -1459,6 +1459,17 @@ module Crystal
     end
   end
 
+  class Primitive
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "name"
+        interpret_check_args { SymbolLiteral.new(@name) }
+      else
+        super
+      end
+    end
+  end
+
   class Macro
     def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
       case method

From ab96337f02315171a05d55645baaea3670aa7122 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Mon, 29 Jan 2024 19:15:56 +0800
Subject: [PATCH 075/105] Respect `NO_COLOR` in the compiler (#14260)

---
 src/compiler/crystal/command.cr | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr
index 6549c2768aea..18def74ebbd0 100644
--- a/src/compiler/crystal/command.cr
+++ b/src/compiler/crystal/command.cr
@@ -58,7 +58,7 @@ class Crystal::Command
   @compiler : Compiler?
 
   def initialize(@options : Array(String))
-    @color = ENV["TERM"]? != "dumb"
+    @color = ENV["TERM"]? != "dumb" && !ENV.has_key?("NO_COLOR")
     @error_trace = false
     @progress_tracker = ProgressTracker.new
   end
@@ -743,7 +743,7 @@ class Crystal::Command
 
   private def error(msg, exit_code = 1)
     # This is for the case where the main command is wrong
-    @color = false if ARGV.includes?("--no-color") || ENV["TERM"]? == "dumb"
+    @color = false if ARGV.includes?("--no-color") || ENV["TERM"]? == "dumb" || ENV.has_key?("NO_COLOR")
     Crystal.error msg, @color, exit_code: exit_code
   end
 

From f6b81842e10bc9bb1951ef70fa896591aad3d672 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Mon, 29 Jan 2024 19:16:06 +0800
Subject: [PATCH 076/105] Add macro methods for `TypeOf` (#14262)

---
 spec/compiler/macro/macro_methods_spec.cr |  6 ++++++
 src/compiler/crystal/macros.cr            | 14 ++++++++++++--
 src/compiler/crystal/macros/methods.cr    | 11 +++++++++++
 3 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr
index 516c3e408280..a970aff3e876 100644
--- a/spec/compiler/macro/macro_methods_spec.cr
+++ b/spec/compiler/macro/macro_methods_spec.cr
@@ -2770,6 +2770,12 @@ module Crystal
       end
     end
 
+    describe TypeOf do
+      it "executes args" do
+        assert_macro %({{x.args}}), "[1, 'a', Foo]", {x: TypeOf.new([1.int32, CharLiteral.new('a'), "Foo".path])}
+      end
+    end
+
     describe "case methods" do
       describe "when" do
         case_node = Case.new(1.int32, [When.new([2.int32, 3.int32] of ASTNode, 4.int32)], 5.int32, exhaustive: false)
diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr
index f18c3c7246ab..3b9ce399c7ef 100644
--- a/src/compiler/crystal/macros.cr
+++ b/src/compiler/crystal/macros.cr
@@ -2276,8 +2276,18 @@ module Crystal::Macros
     end
   end
 
-  # class TypeOf < ASTNode
-  # end
+  # A `typeof` expression.
+  #
+  # Every expression *node* is equivalent to:
+  #
+  # ```
+  # typeof({{ node.args.splat }})
+  # ```
+  class TypeOf < ASTNode
+    # Returns the arguments to this `typeof`.
+    def args : ArrayLiteral(ASTNode)
+    end
+  end
 
   # A macro expression,
   # surrounded by {{ ... }} (output = true)
diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr
index 60ecdb528509..b98306db3fc8 100644
--- a/src/compiler/crystal/macros/methods.cr
+++ b/src/compiler/crystal/macros/methods.cr
@@ -2362,6 +2362,17 @@ module Crystal
     end
   end
 
+  class TypeOf
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "args"
+        interpret_check_args { ArrayLiteral.map(@expressions, &.itself) }
+      else
+        super
+      end
+    end
+  end
+
   class Generic
     def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
       case method

From bc0c8725cf007c7e88728ef75100fe7fad1e505b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Mon, 29 Jan 2024 20:14:49 +0100
Subject: [PATCH 077/105] Optimize hash lookup in `Enumerable#group_by`
 (#14235)

Co-authored-by: Quinton Miller <nicetas.c@gmail.com>
---
 src/enumerable.cr | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/enumerable.cr b/src/enumerable.cr
index 6b24c833f44f..9a1aad3debd0 100644
--- a/src/enumerable.cr
+++ b/src/enumerable.cr
@@ -636,11 +636,7 @@ module Enumerable(T)
     h = Hash(U, Array(T)).new
     each do |e|
       v = yield e
-      if h.has_key?(v)
-        h[v].push(e)
-      else
-        h[v] = [e]
-      end
+      h.put_if_absent(v) { Array(T).new } << e
     end
     h
   end

From 57d67c2229d58f2737d00482a2f01e9179499ee3 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 30 Jan 2024 03:14:57 +0800
Subject: [PATCH 078/105] Fix `Colorize.enabled?`'s documentation (#14258)

---
 src/colorize.cr | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/colorize.cr b/src/colorize.cr
index 48975c8a451f..83fd82c3935e 100644
--- a/src/colorize.cr
+++ b/src/colorize.cr
@@ -129,8 +129,7 @@ module Colorize
   # "hello".colorize.red.to_s # => "hello"
   # ```
   #
-  # NOTE: This is by default disabled on non-TTY devices because they likely don't support ANSI escape codes.
-  # This will also be disabled if the environment variable `TERM` is "dumb" or `NO_COLOR` contains any value.
+  # NOTE: This is by default disabled if the environment variable `NO_COLOR` contains any value.
   class_property? enabled : Bool { !ENV.has_key?("NO_COLOR") }
 
   # Makes `Colorize.enabled` `true` if and only if both of `STDOUT.tty?`

From 0f7c4e0c1d4864fb905037dd9c9db684acc0122f Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 30 Jan 2024 03:15:05 +0800
Subject: [PATCH 079/105] Add macro methods for `Alias` (#14261)

---
 spec/compiler/macro/macro_methods_spec.cr | 12 ++++++++++++
 src/compiler/crystal/macros.cr            | 18 ++++++++++++++++--
 src/compiler/crystal/macros/methods.cr    | 13 +++++++++++++
 3 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr
index a970aff3e876..806040a55faf 100644
--- a/spec/compiler/macro/macro_methods_spec.cr
+++ b/spec/compiler/macro/macro_methods_spec.cr
@@ -2618,6 +2618,18 @@ module Crystal
       end
     end
 
+    describe Alias do
+      node = Alias.new("Foo".path, Generic.new(Path.new(["Bar", "Baz"], global: true), ["T".path] of ASTNode))
+
+      it "executes name" do
+        assert_macro %({{x.name}}), %(Foo), {x: node}
+      end
+
+      it "executes type" do
+        assert_macro %({{x.type}}), %(::Bar::Baz(T)), {x: node}
+      end
+    end
+
     describe "visibility modifier methods" do
       node = VisibilityModifier.new(Visibility::Protected, Def.new("some_def"))
 
diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr
index 3b9ce399c7ef..2ab9f051530e 100644
--- a/src/compiler/crystal/macros.cr
+++ b/src/compiler/crystal/macros.cr
@@ -2234,8 +2234,22 @@ module Crystal::Macros
     end
   end
 
-  # class Alias < ASTNode
-  # end
+  # An `alias` statement.
+  #
+  # Every statement `node` is equivalent to:
+  #
+  # ```
+  # alias {{ node.name }} = {{ node.type }}
+  # ```
+  class Alias < ASTNode
+    # Returns the name of the alias.
+    def name : Path
+    end
+
+    # Returns the name of the type this alias is equivalent to.
+    def type : ASTNode
+    end
+  end
 
   # A metaclass in a type expression: `T.class`
   class Metaclass < ASTNode
diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr
index b98306db3fc8..caa94c23035d 100644
--- a/src/compiler/crystal/macros/methods.cr
+++ b/src/compiler/crystal/macros/methods.cr
@@ -1560,6 +1560,19 @@ module Crystal
     end
   end
 
+  class Alias
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "name"
+        interpret_check_args { @name }
+      when "type"
+        interpret_check_args { @value }
+      else
+        super
+      end
+    end
+  end
+
   class OffsetOf
     def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
       case method

From 4b8f5c59ae23a79b281a75fadef30b04e973d005 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 30 Jan 2024 06:28:16 +0800
Subject: [PATCH 080/105] Do not handle inline assembly with `"intel"` flag as
 AT&T syntax (#14264)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Johannes Müller <straightshoota@gmail.com>
---
 spec/compiler/codegen/asm_spec.cr   | 8 ++++++++
 src/compiler/crystal/codegen/asm.cr | 2 +-
 src/compiler/crystal/codegen/ast.cr | 6 ++++++
 src/llvm/enums.cr                   | 5 +++++
 src/llvm/lib_llvm/core.cr           | 9 ++-------
 src/llvm/type.cr                    | 6 +++---
 6 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/spec/compiler/codegen/asm_spec.cr b/spec/compiler/codegen/asm_spec.cr
index 2c6b0707699e..289c1455741e 100644
--- a/spec/compiler/codegen/asm_spec.cr
+++ b/spec/compiler/codegen/asm_spec.cr
@@ -44,5 +44,13 @@ describe "Code gen: asm" do
         c
         )).to_i.should eq(42)
     end
+
+    it "codegens with intel dialect" do
+      run(<<-CRYSTAL).to_i.should eq(1234)
+        dst = uninitialized Int32
+        asm("mov dword ptr [$0], 1234" :: "r"(pointerof(dst)) :: "intel")
+        dst
+        CRYSTAL
+    end
   {% end %}
 end
diff --git a/src/compiler/crystal/codegen/asm.cr b/src/compiler/crystal/codegen/asm.cr
index f0b3e2f088ab..107d63f19ecf 100644
--- a/src/compiler/crystal/codegen/asm.cr
+++ b/src/compiler/crystal/codegen/asm.cr
@@ -53,7 +53,7 @@ class Crystal::CodeGenVisitor
     fun_type = LLVM::Type.function(input_types, output_type)
     constraints = constraints.to_s
 
-    value = fun_type.inline_asm(node.text, constraints, node.volatile?, node.alignstack?, node.can_throw?)
+    value = fun_type.inline_asm(node.text, constraints, node.volatile?, node.alignstack?, node.can_throw?, node.dialect)
     value = LLVM::Function.from_value(value)
     asm_value = call LLVMTypedFunction.new(fun_type, value), input_values
 
diff --git a/src/compiler/crystal/codegen/ast.cr b/src/compiler/crystal/codegen/ast.cr
index 816958844dd9..ab4fa76d4e16 100644
--- a/src/compiler/crystal/codegen/ast.cr
+++ b/src/compiler/crystal/codegen/ast.cr
@@ -138,4 +138,10 @@ module Crystal
       found_extern
     end
   end
+
+  class Asm
+    def dialect : LLVM::InlineAsmDialect
+      intel? ? LLVM::InlineAsmDialect::Intel : LLVM::InlineAsmDialect::ATT
+    end
+  end
 end
diff --git a/src/llvm/enums.cr b/src/llvm/enums.cr
index b8e06fb46f89..ac23fa711560 100644
--- a/src/llvm/enums.cr
+++ b/src/llvm/enums.cr
@@ -440,6 +440,11 @@ module LLVM
     LittleEndian = 1 << 28
   end
 
+  enum InlineAsmDialect
+    ATT
+    Intel
+  end
+
   struct Value
     enum Kind
       Argument
diff --git a/src/llvm/lib_llvm/core.cr b/src/llvm/lib_llvm/core.cr
index 20f10c7e6e62..c865baaa55a5 100644
--- a/src/llvm/lib_llvm/core.cr
+++ b/src/llvm/lib_llvm/core.cr
@@ -4,11 +4,6 @@ lib LibLLVM
   # NOTE: the following C enums usually have different values from their C++
   # counterparts (e.g. `LLVMModuleFlagBehavior` v.s. `LLVM::Module::ModFlagBehavior`)
 
-  enum InlineAsmDialect
-    ATT
-    Intel
-  end
-
   enum ModuleFlagBehavior
     Warning = 1
   end
@@ -39,9 +34,9 @@ lib LibLLVM
   fun print_module_to_file = LLVMPrintModuleToFile(m : ModuleRef, filename : Char*, error_message : Char**) : Bool
   fun print_module_to_string = LLVMPrintModuleToString(m : ModuleRef) : Char*
   {% if !LibLLVM::IS_LT_130 %}
-    fun get_inline_asm = LLVMGetInlineAsm(ty : TypeRef, asm_string : Char*, asm_string_size : SizeT, constraints : Char*, constraints_size : SizeT, has_side_effects : Bool, is_align_stack : Bool, dialect : InlineAsmDialect, can_throw : Bool) : ValueRef
+    fun get_inline_asm = LLVMGetInlineAsm(ty : TypeRef, asm_string : Char*, asm_string_size : SizeT, constraints : Char*, constraints_size : SizeT, has_side_effects : Bool, is_align_stack : Bool, dialect : LLVM::InlineAsmDialect, can_throw : Bool) : ValueRef
   {% else %}
-    fun get_inline_asm = LLVMGetInlineAsm(t : TypeRef, asm_string : Char*, asm_string_size : SizeT, constraints : Char*, constraints_size : SizeT, has_side_effects : Bool, is_align_stack : Bool, dialect : InlineAsmDialect) : ValueRef
+    fun get_inline_asm = LLVMGetInlineAsm(t : TypeRef, asm_string : Char*, asm_string_size : SizeT, constraints : Char*, constraints_size : SizeT, has_side_effects : Bool, is_align_stack : Bool, dialect : LLVM::InlineAsmDialect) : ValueRef
   {% end %}
   fun get_module_context = LLVMGetModuleContext(m : ModuleRef) : ContextRef
 
diff --git a/src/llvm/type.cr b/src/llvm/type.cr
index 06c36ff5796d..c391019aef83 100644
--- a/src/llvm/type.cr
+++ b/src/llvm/type.cr
@@ -173,7 +173,7 @@ struct LLVM::Type
     Value.new LibLLVM.const_array(self, (values.to_unsafe.as(LibLLVM::ValueRef*)), values.size)
   end
 
-  def inline_asm(asm_string, constraints, has_side_effects = false, is_align_stack = false, can_throw = false)
+  def inline_asm(asm_string, constraints, has_side_effects = false, is_align_stack = false, can_throw = false, dialect : InlineAsmDialect = InlineAsmDialect::ATT)
     value =
       {% if LibLLVM::IS_LT_130 %}
         LibLLVM.get_inline_asm(
@@ -184,7 +184,7 @@ struct LLVM::Type
           constraints.size,
           (has_side_effects ? 1 : 0),
           (is_align_stack ? 1 : 0),
-          LibLLVM::InlineAsmDialect::ATT
+          dialect,
         )
       {% else %}
         LibLLVM.get_inline_asm(
@@ -195,7 +195,7 @@ struct LLVM::Type
           constraints.size,
           (has_side_effects ? 1 : 0),
           (is_align_stack ? 1 : 0),
-          LibLLVM::InlineAsmDialect::ATT,
+          dialect,
           (can_throw ? 1 : 0)
         )
       {% end %}

From de7a0786e5e1635f6cda6176ac9ec395086f8dcf Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 30 Jan 2024 06:28:27 +0800
Subject: [PATCH 081/105] Use correct string size for `LLVM::Type#inline_asm`
 (#14265)

---
 spec/compiler/codegen/asm_spec.cr | 8 ++++++++
 src/llvm/type.cr                  | 8 ++++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/spec/compiler/codegen/asm_spec.cr b/spec/compiler/codegen/asm_spec.cr
index 289c1455741e..05eb3b895032 100644
--- a/spec/compiler/codegen/asm_spec.cr
+++ b/spec/compiler/codegen/asm_spec.cr
@@ -3,6 +3,14 @@ require "../../spec_helper"
 describe "Code gen: asm" do
   # TODO: arm asm tests
   {% if flag?(:i386) || flag?(:x86_64) %}
+    it "passes correct string length to LLVM" do
+      run <<-CRYSTAL
+        asm("// 😂😂
+        nop
+        nop")
+        CRYSTAL
+    end
+
     it "codegens without inputs" do
       run(%(
         dst = uninitialized Int32
diff --git a/src/llvm/type.cr b/src/llvm/type.cr
index c391019aef83..42d1a314c118 100644
--- a/src/llvm/type.cr
+++ b/src/llvm/type.cr
@@ -179,9 +179,9 @@ struct LLVM::Type
         LibLLVM.get_inline_asm(
           self,
           asm_string,
-          asm_string.size,
+          asm_string.bytesize,
           constraints,
-          constraints.size,
+          constraints.bytesize,
           (has_side_effects ? 1 : 0),
           (is_align_stack ? 1 : 0),
           dialect,
@@ -190,9 +190,9 @@ struct LLVM::Type
         LibLLVM.get_inline_asm(
           self,
           asm_string,
-          asm_string.size,
+          asm_string.bytesize,
           constraints,
-          constraints.size,
+          constraints.bytesize,
           (has_side_effects ? 1 : 0),
           (is_align_stack ? 1 : 0),
           dialect,

From 8a2a1a83f1f454f2a424242eef2c6a55158a536c Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 30 Jan 2024 20:47:10 +0800
Subject: [PATCH 082/105] Fix name locations of `FunDef` and `External` nodes
 (#14267)

---
 spec/compiler/parser/parser_spec.cr            | 18 ++++++++++++++++++
 .../crystal/semantic/top_level_visitor.cr      |  1 +
 src/compiler/crystal/syntax/ast.cr             |  9 ++++++++-
 src/compiler/crystal/syntax/parser.cr          |  2 ++
 4 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr
index 2fa1a5b4c4a7..9f4ec5faccf7 100644
--- a/spec/compiler/parser/parser_spec.cr
+++ b/spec/compiler/parser/parser_spec.cr
@@ -2505,6 +2505,24 @@ module Crystal
         name_location.column_number.should eq(12)
       end
 
+      it "sets location of top-level fun name" do
+        parser = Parser.new("fun foo; end")
+        node = parser.parse.as(FunDef)
+
+        name_location = node.name_location.should_not be_nil
+        name_location.line_number.should eq(1)
+        name_location.column_number.should eq(5)
+      end
+
+      it "sets location of lib fun name" do
+        parser = Parser.new("lib Foo; fun foo; end")
+        node = parser.parse.as(LibDef).body.as(FunDef)
+
+        name_location = node.name_location.should_not be_nil
+        name_location.line_number.should eq(1)
+        name_location.column_number.should eq(14)
+      end
+
       it "sets correct location of proc literal" do
         parser = Parser.new("->(\n  x : Int32,\n  y : String\n) { }")
         node = parser.parse.as(ProcLiteral)
diff --git a/src/compiler/crystal/semantic/top_level_visitor.cr b/src/compiler/crystal/semantic/top_level_visitor.cr
index 05d8918f8383..11c5707b19fa 100644
--- a/src/compiler/crystal/semantic/top_level_visitor.cr
+++ b/src/compiler/crystal/semantic/top_level_visitor.cr
@@ -918,6 +918,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
     end
 
     external = External.new(node.name, external_args, node.body, node.real_name).at(node)
+    external.name_location = node.name_location
 
     call_convention = nil
     process_def_annotations(external, annotations) do |annotation_type, ann|
diff --git a/src/compiler/crystal/syntax/ast.cr b/src/compiler/crystal/syntax/ast.cr
index d0be18606714..9c0ffcf0d7e5 100644
--- a/src/compiler/crystal/syntax/ast.cr
+++ b/src/compiler/crystal/syntax/ast.cr
@@ -1954,6 +1954,7 @@ module Crystal
     property real_name : String
     property doc : String?
     property? varargs : Bool
+    property name_location : Location?
 
     def initialize(@name, @args = [] of Arg, @return_type = nil, @varargs = false, @body = nil, @real_name = name)
     end
@@ -1965,7 +1966,13 @@ module Crystal
     end
 
     def clone_without_location
-      FunDef.new(@name, @args.clone, @return_type.clone, @varargs, @body.clone, @real_name)
+      clone = FunDef.new(@name, @args.clone, @return_type.clone, @varargs, @body.clone, @real_name)
+      clone.name_location = name_location
+      clone
+    end
+
+    def name_size
+      @name.size
     end
 
     def_equals_and_hash @name, @args, @return_type, @varargs, @body, @real_name
diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr
index f14399212e65..e3f4c2605ed6 100644
--- a/src/compiler/crystal/syntax/parser.cr
+++ b/src/compiler/crystal/syntax/parser.cr
@@ -5732,6 +5732,7 @@ module Crystal
       with_isolated_var_scope(require_body) do
         next_token_skip_space_or_newline
 
+        name_location = @token.location
         name = if top_level
                  check_ident
                else
@@ -5835,6 +5836,7 @@ module Crystal
         end
 
         fun_def = FunDef.new name, params, return_type, varargs, body, real_name
+        fun_def.name_location = name_location
         fun_def.doc = doc
         fun_def.at(location).at_end(end_location)
       end

From d88c013588e4c92d2510af21b88fd14542c5a902 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 30 Jan 2024 20:47:21 +0800
Subject: [PATCH 083/105] Ensure `Crystal::Visitor#visit` returns `Bool`
 (#14266)

---
 samples/compiler/visitor_example.cr           |  1 +
 src/compiler/crystal/codegen/codegen.cr       | 17 +++++++++++---
 src/compiler/crystal/codegen/primitives.cr    |  2 ++
 src/compiler/crystal/interpreter/compiler.cr  |  5 +++--
 src/compiler/crystal/macros/interpreter.cr    |  8 +++++--
 .../crystal/semantic/cleanup_transformer.cr   |  2 ++
 src/compiler/crystal/semantic/main_visitor.cr | 22 ++++++++++++++++---
 .../semantic/restrictions_augmenter.cr        |  3 ++-
 src/compiler/crystal/semantic/to_s.cr         |  3 +++
 .../crystal/semantic/top_level_visitor.cr     |  1 +
 .../crystal/semantic/type_guess_visitor.cr    |  3 +++
 src/compiler/crystal/syntax/to_s.cr           | 15 +++++++++++++
 src/compiler/crystal/tools/expand.cr          |  4 ++++
 src/compiler/crystal/tools/implementations.cr |  2 ++
 .../crystal/tools/print_types_visitor.cr      |  4 ++++
 15 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/samples/compiler/visitor_example.cr b/samples/compiler/visitor_example.cr
index ec063a832efa..d9be4da91baf 100644
--- a/samples/compiler/visitor_example.cr
+++ b/samples/compiler/visitor_example.cr
@@ -15,6 +15,7 @@ class Counter < Crystal::Visitor
 
   def visit(node : Crystal::NumberLiteral)
     @count += 1
+    false
   end
 
   def visit(node : Crystal::ASTNode)
diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr
index a6015012eb7c..e7128302a66e 100644
--- a/src/compiler/crystal/codegen/codegen.cr
+++ b/src/compiler/crystal/codegen/codegen.cr
@@ -501,18 +501,22 @@ module Crystal
 
     def visit(node : Nop)
       @last = llvm_nil
+      false
     end
 
     def visit(node : NilLiteral)
       @last = llvm_nil
+      false
     end
 
     def visit(node : BoolLiteral)
       @last = int1(node.value ? 1 : 0)
+      false
     end
 
     def visit(node : CharLiteral)
       @last = int32(node.value.ord)
+      false
     end
 
     def visit(node : NumberLiteral)
@@ -542,14 +546,17 @@ module Crystal
       in .f64?
         @last = float64(node.value)
       end
+      false
     end
 
     def visit(node : StringLiteral)
       @last = build_string_constant(node.value, node.value)
+      false
     end
 
     def visit(node : SymbolLiteral)
       @last = int(@symbols[node.value])
+      false
     end
 
     def visit(node : TupleLiteral)
@@ -1092,7 +1099,7 @@ module Crystal
 
       request_value(value)
 
-      return if value.no_returns?
+      return false if value.no_returns?
 
       last = @last
 
@@ -1106,7 +1113,7 @@ module Crystal
               read_class_var_ptr(target)
             when Var
               # Can't assign void
-              return if target.type.void?
+              return false if target.type.void?
 
               # If assigning to a special variable in a method that yields,
               # assign to that variable too.
@@ -1284,6 +1291,7 @@ module Crystal
       else
         node.raise "BUG: missing context var: #{node.name}"
       end
+      false
     end
 
     def visit(node : Global)
@@ -1292,6 +1300,7 @@ module Crystal
 
     def visit(node : ClassVar)
       @last = read_class_var(node)
+      false
     end
 
     def visit(node : InstanceVar)
@@ -1403,7 +1412,7 @@ module Crystal
 
       unless filtered_type
         @last = upcast llvm_nil, resulting_type, @program.nil
-        return
+        return false
       end
 
       non_nilable_type = node.non_nilable_type
@@ -1664,6 +1673,7 @@ module Crystal
 
     def visit(node : Unreachable)
       builder.unreachable
+      false
     end
 
     def check_proc_is_not_closure(value, type)
@@ -2049,6 +2059,7 @@ module Crystal
     def unreachable(file = __FILE__, line = __LINE__)
       debug_codegen_log(file, line) { "Reached the unreachable!" }
       builder.unreachable
+      false
     end
 
     def allocate_aggregate(type)
diff --git a/src/compiler/crystal/codegen/primitives.cr b/src/compiler/crystal/codegen/primitives.cr
index 9ed05c0009f2..80ba7d832a41 100644
--- a/src/compiler/crystal/codegen/primitives.cr
+++ b/src/compiler/crystal/codegen/primitives.cr
@@ -11,6 +11,8 @@ class Crystal::CodeGenVisitor
             else
               raise "BUG: unhandled primitive in codegen visit: #{node.name}"
             end
+
+    false
   end
 
   def codegen_primitive(call, node, target_def, call_args)
diff --git a/src/compiler/crystal/interpreter/compiler.cr b/src/compiler/crystal/interpreter/compiler.cr
index bfd1514b419f..04fc885fce7e 100644
--- a/src/compiler/crystal/interpreter/compiler.cr
+++ b/src/compiler/crystal/interpreter/compiler.cr
@@ -762,7 +762,7 @@ class Crystal::Repl::Compiler < Crystal::Visitor
     # particularly when outside of a method.
     if is_self && !scope.is_a?(Program) && !scope.passed_as_self?
       put_type scope, node: node
-      return
+      return false
     end
 
     local_var = lookup_local_var_or_closured_var(node.name)
@@ -1687,7 +1687,7 @@ class Crystal::Repl::Compiler < Crystal::Visitor
     if node.upcast?
       upcast node.obj, obj_type, node.non_nilable_type
       upcast node.obj, node.non_nilable_type, node.type
-      return
+      return false
     end
 
     # Check if obj is a `to_type`
@@ -3158,6 +3158,7 @@ class Crystal::Repl::Compiler < Crystal::Visitor
     {% end %}
 
     call compiled_def, node: node
+    false
   end
 
   def visit(node : ASTNode)
diff --git a/src/compiler/crystal/macros/interpreter.cr b/src/compiler/crystal/macros/interpreter.cr
index 5bc7cd0117ca..1e18e92b7545 100644
--- a/src/compiler/crystal/macros/interpreter.cr
+++ b/src/compiler/crystal/macros/interpreter.cr
@@ -118,6 +118,7 @@ module Crystal
 
     def visit(node : MacroLiteral)
       @str << node.value
+      false
     end
 
     def visit(node : MacroVerbatim)
@@ -135,7 +136,8 @@ module Crystal
     def visit(node : Var)
       var = @vars[node.name]?
       if var
-        return @last = var
+        @last = var
+        return false
       end
 
       # Try to consider the var as a top-level macro call.
@@ -150,7 +152,8 @@ module Crystal
       # and in this case the parser has no idea about this, so the only
       # solution is to do it now.
       if value = interpret_top_level_call?(Call.new(nil, node.name))
-        return @last = value
+        @last = value
+        return false
       end
 
       node.raise "undefined macro variable '#{node.name}'"
@@ -549,6 +552,7 @@ module Crystal
       else
         node.raise "unknown macro instance var: '#{node.name}'"
       end
+      false
     end
 
     def visit(node : TupleLiteral)
diff --git a/src/compiler/crystal/semantic/cleanup_transformer.cr b/src/compiler/crystal/semantic/cleanup_transformer.cr
index bc3084429ed3..541e0f51d662 100644
--- a/src/compiler/crystal/semantic/cleanup_transformer.cr
+++ b/src/compiler/crystal/semantic/cleanup_transformer.cr
@@ -635,10 +635,12 @@ module Crystal
         if @a_def.vars.try &.[node.name]?.try &.closured?
           @vars << node
         end
+        false
       end
 
       def visit(node : InstanceVar)
         @vars << node
+        false
       end
 
       def visit(node : ASTNode)
diff --git a/src/compiler/crystal/semantic/main_visitor.cr b/src/compiler/crystal/semantic/main_visitor.cr
index 37218e7a34dc..61d1aa508a46 100644
--- a/src/compiler/crystal/semantic/main_visitor.cr
+++ b/src/compiler/crystal/semantic/main_visitor.cr
@@ -226,6 +226,8 @@ module Crystal
         node.syntax_replacement = type
         node.bind_to type
       end
+
+      false
     end
 
     def visit(node : Generic)
@@ -353,6 +355,7 @@ module Crystal
 
     def visit(node : Self)
       node.type = the_self(node).instance_type
+      false
     end
 
     def visit(node : Var)
@@ -394,6 +397,7 @@ module Crystal
       else
         node.raise "read before assignment to local variable '#{node.name}'"
       end
+      false
     end
 
     def visit(node : TypeDeclaration)
@@ -628,6 +632,8 @@ module Crystal
         ivar.nil_reason ||= NilReason.new(node.name, :used_before_initialized, [node] of ASTNode)
         ivar.bind_to program.nil_var
       end
+
+      false
     end
 
     def visit(node : ReadInstanceVar)
@@ -1007,7 +1013,7 @@ module Crystal
     end
 
     def visit(node : Block)
-      return if node.visited?
+      return false if node.visited?
 
       node.visited = true
       node.context = current_non_block_context
@@ -1630,6 +1636,7 @@ module Crystal
             ivars[node.name] = node_in_callstack(node)
           end
         end
+        false
       end
 
       def visit(node : Var)
@@ -1761,7 +1768,7 @@ module Crystal
         comp.accept self
         node.syntax_replacement = comp
         node.bind_to comp
-        return
+        return false
       end
 
       if needs_type_filters? && (var = get_expression_var(node.obj))
@@ -2060,7 +2067,7 @@ module Crystal
       unless node.has_breaks?
         if endless_while
           node.type = program.no_return
-          return
+          return false
         end
 
         filter_vars TypeFilters.not(cond_type_filters)
@@ -2325,6 +2332,8 @@ module Crystal
       else
         node.raise "BUG: unhandled primitive in MainVisitor: #{node.name}"
       end
+
+      false
     end
 
     def visit_va_arg(node)
@@ -3042,31 +3051,38 @@ module Crystal
 
     def visit(node : Nop)
       node.type = @program.nil
+      false
     end
 
     def visit(node : NilLiteral)
       node.type = @program.nil
+      false
     end
 
     def visit(node : BoolLiteral)
       node.type = program.bool
+      false
     end
 
     def visit(node : NumberLiteral)
       node.type = program.type_from_literal_kind node.kind
+      false
     end
 
     def visit(node : CharLiteral)
       node.type = program.char
+      false
     end
 
     def visit(node : SymbolLiteral)
       node.type = program.symbol
       program.symbols.add node.value
+      false
     end
 
     def visit(node : StringLiteral)
       node.type = program.string
+      false
     end
 
     def visit(node : RegexLiteral)
diff --git a/src/compiler/crystal/semantic/restrictions_augmenter.cr b/src/compiler/crystal/semantic/restrictions_augmenter.cr
index a627f27f5fe0..5b3e31056110 100644
--- a/src/compiler/crystal/semantic/restrictions_augmenter.cr
+++ b/src/compiler/crystal/semantic/restrictions_augmenter.cr
@@ -59,7 +59,8 @@ module Crystal
 
     def visit(node : Call)
       if expanded = node.expanded
-        return expanded.accept self
+        expanded.accept self
+        return false
       end
 
       node.obj.try &.accept self
diff --git a/src/compiler/crystal/semantic/to_s.cr b/src/compiler/crystal/semantic/to_s.cr
index 8c91426bc379..13e8203efe1d 100644
--- a/src/compiler/crystal/semantic/to_s.cr
+++ b/src/compiler/crystal/semantic/to_s.cr
@@ -44,14 +44,17 @@ module Crystal
     def visit(node : Primitive)
       @str << "# primitive: "
       @str << node.name
+      false
     end
 
     def visit(node : MetaVar)
       @str << node.name
+      false
     end
 
     def visit(node : MetaMacroVar)
       @str << node.name
+      false
     end
 
     def visit(node : TypeFilteredNode)
diff --git a/src/compiler/crystal/semantic/top_level_visitor.cr b/src/compiler/crystal/semantic/top_level_visitor.cr
index 11c5707b19fa..9b7eedb2a876 100644
--- a/src/compiler/crystal/semantic/top_level_visitor.cr
+++ b/src/compiler/crystal/semantic/top_level_visitor.cr
@@ -598,6 +598,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
       typed_def_type = lookup_type(node.type_spec)
       typed_def_type = check_allowed_in_lib node.type_spec, typed_def_type
       current_type.types[node.name] = TypeDefType.new @program, current_type, node.name, typed_def_type
+      false
     end
   end
 
diff --git a/src/compiler/crystal/semantic/type_guess_visitor.cr b/src/compiler/crystal/semantic/type_guess_visitor.cr
index 693cade2906b..612390db8e21 100644
--- a/src/compiler/crystal/semantic/type_guess_visitor.cr
+++ b/src/compiler/crystal/semantic/type_guess_visitor.cr
@@ -86,6 +86,7 @@ module Crystal
       end
 
       check_var_is_self(node)
+      false
     end
 
     def visit(node : UninitializedVar)
@@ -114,6 +115,7 @@ module Crystal
           # TODO: can this be reached?
         end
       end
+      false
     end
 
     def visit(node : Assign)
@@ -1353,6 +1355,7 @@ module Crystal
       if node.name == "self"
         @has_self = true
       end
+      false
     end
 
     def visit(node : ASTNode)
diff --git a/src/compiler/crystal/syntax/to_s.cr b/src/compiler/crystal/syntax/to_s.cr
index f5086e346277..3ea146d15c3e 100644
--- a/src/compiler/crystal/syntax/to_s.cr
+++ b/src/compiler/crystal/syntax/to_s.cr
@@ -49,10 +49,12 @@ module Crystal
     end
 
     def visit(node : Nop)
+      false
     end
 
     def visit(node : BoolLiteral)
       @str << (node.value ? "true" : "false")
+      false
     end
 
     def visit(node : NumberLiteral)
@@ -62,6 +64,8 @@ module Crystal
         @str << '_'
         @str << node.kind.to_s
       end
+
+      false
     end
 
     def needs_suffix?(node : NumberLiteral)
@@ -83,10 +87,12 @@ module Crystal
 
     def visit(node : CharLiteral)
       node.value.inspect(@str)
+      false
     end
 
     def visit(node : SymbolLiteral)
       visit_symbol_literal_value node.value
+      false
     end
 
     def visit_symbol_literal_value(value : String)
@@ -100,6 +106,7 @@ module Crystal
 
     def visit(node : StringLiteral)
       node.value.inspect(@str)
+      false
     end
 
     def visit(node : StringInterpolation)
@@ -189,6 +196,7 @@ module Crystal
 
     def visit(node : NilLiteral)
       @str << "nil"
+      false
     end
 
     def visit(node : Expressions)
@@ -573,6 +581,7 @@ module Crystal
 
     def visit(node : Var)
       @str << node.name
+      false
     end
 
     def visit(node : ProcLiteral)
@@ -836,11 +845,13 @@ module Crystal
 
     def visit(node : Self)
       @str << "self"
+      false
     end
 
     def visit(node : Path)
       @str << "::" if node.global?
       node.names.join(@str, "::")
+      false
     end
 
     def visit(node : Generic)
@@ -907,6 +918,7 @@ module Crystal
 
     def visit(node : InstanceVar)
       @str << node.name
+      false
     end
 
     def visit(node : ReadInstanceVar)
@@ -918,6 +930,7 @@ module Crystal
 
     def visit(node : ClassVar)
       @str << node.name
+      false
     end
 
     def visit(node : Yield)
@@ -1105,6 +1118,7 @@ module Crystal
 
     def visit(node : Global)
       @str << node.name
+      false
     end
 
     def visit(node : LibDef)
@@ -1449,6 +1463,7 @@ module Crystal
 
     def visit(node : MagicConstant)
       @str << node.name
+      false
     end
 
     def visit(node : Asm)
diff --git a/src/compiler/crystal/tools/expand.cr b/src/compiler/crystal/tools/expand.cr
index 365fc2b3f865..792d60869bd3 100644
--- a/src/compiler/crystal/tools/expand.cr
+++ b/src/compiler/crystal/tools/expand.cr
@@ -144,6 +144,8 @@ module Crystal
         else
           contains_target(node)
         end
+      else
+        false
       end
     end
 
@@ -156,6 +158,8 @@ module Crystal
         else
           contains_target(node)
         end
+      else
+        false
       end
     end
 
diff --git a/src/compiler/crystal/tools/implementations.cr b/src/compiler/crystal/tools/implementations.cr
index f4f3a390f0eb..e2dbee001346 100644
--- a/src/compiler/crystal/tools/implementations.cr
+++ b/src/compiler/crystal/tools/implementations.cr
@@ -114,6 +114,7 @@ module Crystal
           @locations << target_def.location.not_nil!
         end
       end
+      false
     end
 
     def visit(node : Path)
@@ -123,6 +124,7 @@ module Crystal
       target.try &.locations.try &.each do |loc|
         @locations << loc
       end
+      false
     end
 
     def visit(node)
diff --git a/src/compiler/crystal/tools/print_types_visitor.cr b/src/compiler/crystal/tools/print_types_visitor.cr
index 6ffc533a4b0f..0744dc17febd 100644
--- a/src/compiler/crystal/tools/print_types_visitor.cr
+++ b/src/compiler/crystal/tools/print_types_visitor.cr
@@ -39,10 +39,12 @@ module Crystal
 
     def visit(node : Var)
       output_name node
+      false
     end
 
     def visit(node : Global)
       output_name node
+      false
     end
 
     def visit(node : TypeDeclaration)
@@ -50,6 +52,7 @@ module Crystal
       if var.is_a?(Var)
         output_name var
       end
+      false
     end
 
     def visit(node : UninitializedVar)
@@ -57,6 +60,7 @@ module Crystal
       if var.is_a?(Var)
         output_name var
       end
+      false
     end
 
     def output_name(node)

From f66312174d0b7dfa30b8795e356c30b9c23e0649 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Tue, 30 Jan 2024 20:47:29 +0800
Subject: [PATCH 084/105] Add macro methods for `Asm` and `AsmOperand` (#14268)

---
 spec/compiler/macro/macro_methods_spec.cr | 69 +++++++++++++++++++++++
 src/compiler/crystal/macros.cr            | 69 +++++++++++++++++++++++
 src/compiler/crystal/macros/methods.cr    | 56 ++++++++++++++++++
 3 files changed, 194 insertions(+)

diff --git a/spec/compiler/macro/macro_methods_spec.cr b/spec/compiler/macro/macro_methods_spec.cr
index 806040a55faf..76d5f795903c 100644
--- a/spec/compiler/macro/macro_methods_spec.cr
+++ b/spec/compiler/macro/macro_methods_spec.cr
@@ -3426,6 +3426,75 @@ module Crystal
       end
     end
 
+    describe Asm do
+      asm1 = Asm.new("nop")
+      asm2 = Asm.new(
+        text: "foo",
+        outputs: [AsmOperand.new("=r", "x".var), AsmOperand.new("=r", "y".var)],
+        inputs: [AsmOperand.new("i", 1.int32), AsmOperand.new("r", 2.int32)],
+        clobbers: %w(rax memory),
+        volatile: true,
+        alignstack: true,
+        intel: true,
+        can_throw: true,
+      )
+
+      it "executes text" do
+        assert_macro %({{x.text}}), %("nop"), {x: asm1}
+        assert_macro %({{x.text}}), %("foo"), {x: asm2}
+      end
+
+      it "executes outputs" do
+        assert_macro %({{x.outputs}}), %([] of ::NoReturn), {x: asm1}
+        assert_macro %({{x.outputs}}), %(["=r"(x), "=r"(y)]), {x: asm2}
+      end
+
+      it "executes inputs" do
+        assert_macro %({{x.inputs}}), %([] of ::NoReturn), {x: asm1}
+        assert_macro %({{x.inputs}}), %(["i"(1), "r"(2)]), {x: asm2}
+      end
+
+      it "executes clobbers" do
+        assert_macro %({{x.clobbers}}), %([] of ::NoReturn), {x: asm1}
+        assert_macro %({{x.clobbers}}), %(["rax", "memory"]), {x: asm2}
+      end
+
+      it "executes volatile?" do
+        assert_macro %({{x.volatile?}}), %(false), {x: asm1}
+        assert_macro %({{x.volatile?}}), %(true), {x: asm2}
+      end
+
+      it "executes alignstack?" do
+        assert_macro %({{x.alignstack?}}), %(false), {x: asm1}
+        assert_macro %({{x.alignstack?}}), %(true), {x: asm2}
+      end
+
+      it "executes intel?" do
+        assert_macro %({{x.intel?}}), %(false), {x: asm1}
+        assert_macro %({{x.intel?}}), %(true), {x: asm2}
+      end
+
+      it "executes can_throw?" do
+        assert_macro %({{x.can_throw?}}), %(false), {x: asm1}
+        assert_macro %({{x.can_throw?}}), %(true), {x: asm2}
+      end
+    end
+
+    describe AsmOperand do
+      asm_operand1 = AsmOperand.new("=r", "x".var)
+      asm_operand2 = AsmOperand.new("i", 1.int32)
+
+      it "executes constraint" do
+        assert_macro %({{x.constraint}}), %("=r"), {x: asm_operand1}
+        assert_macro %({{x.constraint}}), %("i"), {x: asm_operand2}
+      end
+
+      it "executes exp" do
+        assert_macro %({{x.exp}}), %(x), {x: asm_operand1}
+        assert_macro %({{x.exp}}), %(1), {x: asm_operand2}
+      end
+    end
+
     describe "env" do
       it "has key" do
         with_env("FOO": "foo") do
diff --git a/src/compiler/crystal/macros.cr b/src/compiler/crystal/macros.cr
index 2ab9f051530e..3ec6243ffd62 100644
--- a/src/compiler/crystal/macros.cr
+++ b/src/compiler/crystal/macros.cr
@@ -2377,6 +2377,75 @@ module Crystal::Macros
   class MagicConstant < ASTNode
   end
 
+  # An inline assembly expression.
+  #
+  # Every assembly `node` is equivalent to:
+  #
+  # ```
+  # asm(
+  #   {{ node.text }} :
+  #   {{ node.outputs.splat }} :
+  #   {{ node.inputs.splat }} :
+  #   {{ node.clobbers.splat }} :
+  #   {% if node.volatile? %} "volatile", {% end %}
+  #   {% if node.alignstack? %} "alignstack", {% end %}
+  #   {% if node.intel? %} "intel", {% end %}
+  #   {% if node.can_throw? %} "unwind", {% end %}
+  # )
+  # ```
+  class Asm < ASTNode
+    # Returns the template string for this assembly expression.
+    def text : StringLiteral
+    end
+
+    # Returns an array of output operands for this assembly expression.
+    def outputs : ArrayLiteral(AsmOperand)
+    end
+
+    # Returns an array of input operands for this assembly expression.
+    def inputs : ArrayLiteral(AsmOperand)
+    end
+
+    # Returns an array of clobbered register names for this assembly expression.
+    def clobbers : ArrayLiteral(StringLiteral)
+    end
+
+    # Returns whether the assembly expression contains side effects that are
+    # not listed in `#outputs`, `#inputs`, and `#clobbers`.
+    def volatile? : BoolLiteral
+    end
+
+    # Returns whether the assembly expression requires stack alignment code.
+    def alignstack? : BoolLiteral
+    end
+
+    # Returns `true` if the template string uses the Intel syntax, `false` if it
+    # uses the AT&T syntax.
+    def intel? : BoolLiteral
+    end
+
+    # Returns whether the assembly expression might unwind the stack.
+    def can_throw? : BoolLiteral
+    end
+  end
+
+  # An output or input operand for an `Asm` node.
+  #
+  # Every operand `node` is equivalent to:
+  #
+  # ```
+  # {{ node.constraint }}({{ node.exp }})
+  # ```
+  class AsmOperand < ASTNode
+    # Returns the constraint string of this operand.
+    def constraint : StringLiteral
+    end
+
+    # Returns the associated output or input argument of this operand.
+    def exp : ASTNode
+    end
+  end
+
   # A fictitious node representing an identifier like, `foo`, `Bar` or `something_else`.
   #
   # The parser doesn't create these nodes. Instead, you create them by invoking `id`
diff --git a/src/compiler/crystal/macros/methods.cr b/src/compiler/crystal/macros/methods.cr
index caa94c23035d..9891c4cc2b2a 100644
--- a/src/compiler/crystal/macros/methods.cr
+++ b/src/compiler/crystal/macros/methods.cr
@@ -1653,6 +1653,62 @@ module Crystal
     end
   end
 
+  class Asm
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "text"
+        interpret_check_args { StringLiteral.new(@text) }
+      when "outputs"
+        interpret_check_args do
+          if outputs = @outputs
+            ArrayLiteral.map(outputs, &.itself)
+          else
+            empty_no_return_array
+          end
+        end
+      when "inputs"
+        interpret_check_args do
+          if inputs = @inputs
+            ArrayLiteral.map(inputs, &.itself)
+          else
+            empty_no_return_array
+          end
+        end
+      when "clobbers"
+        interpret_check_args do
+          if clobbers = @clobbers
+            ArrayLiteral.map(clobbers) { |clobber| StringLiteral.new(clobber) }
+          else
+            empty_no_return_array
+          end
+        end
+      when "volatile?"
+        interpret_check_args { BoolLiteral.new(@volatile) }
+      when "alignstack?"
+        interpret_check_args { BoolLiteral.new(@alignstack) }
+      when "intel?"
+        interpret_check_args { BoolLiteral.new(@intel) }
+      when "can_throw?"
+        interpret_check_args { BoolLiteral.new(@can_throw) }
+      else
+        super
+      end
+    end
+  end
+
+  class AsmOperand
+    def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
+      case method
+      when "constraint"
+        interpret_check_args { StringLiteral.new(@constraint) }
+      when "exp"
+        interpret_check_args { @exp }
+      else
+        super
+      end
+    end
+  end
+
   class MacroId
     def interpret(method : String, args : Array(ASTNode), named_args : Hash(String, ASTNode)?, block : Crystal::Block?, interpreter : Crystal::MacroInterpreter, name_loc : Location?)
       case method

From 8d1c0806d2e959825a65727fdc0cc5b36a5648a5 Mon Sep 17 00:00:00 2001
From: Julien Portalier <julien@portalier.com>
Date: Tue, 30 Jan 2024 20:13:06 +0100
Subject: [PATCH 085/105] Thread: set name (#14257)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Johannes Müller <straightshoota@gmail.com>
---
 spec/std/thread_spec.cr                       | 13 ++++++++++++
 src/crystal/scheduler.cr                      |  2 +-
 src/crystal/system/thread.cr                  | 20 ++++++++++++++++++-
 src/crystal/system/unix/pthread.cr            | 17 ++++++++++++++++
 src/crystal/system/win32/thread.cr            |  7 +++++++
 src/lib_c/aarch64-android/c/pthread.cr        |  1 +
 src/lib_c/aarch64-darwin/c/pthread.cr         |  1 +
 src/lib_c/aarch64-linux-gnu/c/pthread.cr      |  1 +
 src/lib_c/aarch64-linux-musl/c/pthread.cr     |  1 +
 src/lib_c/arm-linux-gnueabihf/c/pthread.cr    |  1 +
 src/lib_c/i386-linux-gnu/c/pthread.cr         |  1 +
 src/lib_c/i386-linux-musl/c/pthread.cr        |  1 +
 src/lib_c/x86_64-darwin/c/pthread.cr          |  1 +
 src/lib_c/x86_64-dragonfly/c/pthread.cr       |  1 +
 src/lib_c/x86_64-freebsd/c/pthread.cr         |  1 +
 src/lib_c/x86_64-linux-gnu/c/pthread.cr       |  1 +
 src/lib_c/x86_64-linux-musl/c/pthread.cr      |  1 +
 src/lib_c/x86_64-netbsd/c/pthread.cr          |  1 +
 src/lib_c/x86_64-openbsd/c/pthread.cr         |  1 +
 .../c/processthreadsapi.cr                    |  3 +++
 20 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/spec/std/thread_spec.cr b/spec/std/thread_spec.cr
index 599a1968f52f..136026667137 100644
--- a/spec/std/thread_spec.cr
+++ b/spec/std/thread_spec.cr
@@ -49,4 +49,17 @@ describe Thread do
 
     thread.join
   end
+
+  it "names the thread" do
+    Thread.current.name.should be_nil
+    name = nil
+
+    thread = Thread.new(name: "some-name") do
+      name = Thread.current.name
+    end
+    thread.name.should eq("some-name")
+
+    thread.join
+    name.should eq("some-name")
+  end
 end
diff --git a/src/crystal/scheduler.cr b/src/crystal/scheduler.cr
index fa963595bf6d..101a287d23bb 100644
--- a/src/crystal/scheduler.cr
+++ b/src/crystal/scheduler.cr
@@ -234,7 +234,7 @@ class Crystal::Scheduler
           Thread.current.scheduler.enqueue worker_loop
           Thread.current
         else
-          Thread.new do
+          Thread.new(name: "CRYSTAL-MT-#{i}") do
             scheduler = Thread.current.scheduler
             pending.sub(1)
             scheduler.run_loop
diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr
index 88784ed68330..b40a7dceb32b 100644
--- a/src/crystal/system/thread.cr
+++ b/src/crystal/system/thread.cr
@@ -17,6 +17,8 @@ module Crystal::System::Thread
   # private def system_close
 
   # private def stack_address : Void*
+
+  # private def system_name=(String) : String
 end
 
 {% if flag?(:wasi) %}
@@ -49,12 +51,14 @@ class Thread
   # :nodoc:
   property previous : Thread?
 
+  getter name : String?
+
   def self.unsafe_each(&)
     threads.unsafe_each { |thread| yield thread }
   end
 
   # Creates and starts a new system thread.
-  def initialize(&@func : ->)
+  def initialize(@name : String? = nil, &@func : ->)
     @system_handle = uninitialized Crystal::System::Thread::Handle
     init_handle
   end
@@ -104,6 +108,12 @@ class Thread
     Crystal::System::Thread.yield_current
   end
 
+  # Changes the name of the current thread.
+  def self.name=(name : String) : String
+    thread = Thread.current
+    thread.name = name
+  end
+
   # :nodoc:
   getter scheduler : Crystal::Scheduler { Crystal::Scheduler.new(self) }
 
@@ -112,6 +122,10 @@ class Thread
     Thread.current = self
     @main_fiber = fiber = Fiber.new(stack_address, self)
 
+    if name = @name
+      self.system_name = name
+    end
+
     begin
       @func.call
     rescue ex
@@ -123,6 +137,10 @@ class Thread
     end
   end
 
+  protected def name=(@name : String)
+    self.system_name = name
+  end
+
   # Holds the GC thread handler
   property gc_thread_handler : Void* = Pointer(Void).null
 end
diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr
index ca16080621e3..5d6e2a332adc 100644
--- a/src/crystal/system/unix/pthread.cr
+++ b/src/crystal/system/unix/pthread.cr
@@ -112,6 +112,23 @@ module Crystal::System::Thread
 
     address
   end
+
+  # Warning: must be called from the current thread itself, because Darwin
+  # doesn't allow to set the name of any thread but the current one!
+  private def system_name=(name : String) : String
+    {% if flag?(:darwin) %}
+      LibC.pthread_setname_np(name)
+    {% elsif flag?(:netbsd) %}
+      LibC.pthread_setname_np(@system_handle, name, nil)
+    {% elsif LibC.has_method?(:pthread_setname_np) %}
+      LibC.pthread_setname_np(@system_handle, name)
+    {% elsif LibC.has_method?(:pthread_set_name_np) %}
+      LibC.pthread_set_name_np(@system_handle, name)
+    {% else %}
+      {% raise "No `Crystal::System::Thread#system_name` implementation available" %}
+    {% end %}
+    name
+  end
 end
 
 # In musl (alpine) the calls to unwind API segfaults
diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr
index 5dbcbabbfad9..2b44f66c28ce 100644
--- a/src/crystal/system/win32/thread.cr
+++ b/src/crystal/system/win32/thread.cr
@@ -72,4 +72,11 @@ module Crystal::System::Thread
       low_limit
     {% end %}
   end
+
+  private def system_name=(name : String) : String
+    {% if LibC.has_method?(:SetThreadDescription) %}
+      LibC.SetThreadDescription(@system_handle, System.to_wstr(name))
+    {% end %}
+    name
+  end
 end
diff --git a/src/lib_c/aarch64-android/c/pthread.cr b/src/lib_c/aarch64-android/c/pthread.cr
index d761bcb3ceb2..fbab59bd07d7 100644
--- a/src/lib_c/aarch64-android/c/pthread.cr
+++ b/src/lib_c/aarch64-android/c/pthread.cr
@@ -38,6 +38,7 @@ lib LibC
   fun pthread_mutex_unlock(__mutex : PthreadMutexT*) : Int
 
   fun pthread_self : PthreadT
+  fun pthread_setname_np(__key : PthreadT, __name : Char*) : Int
 
   fun pthread_setspecific(__key : PthreadKeyT, __value : Void*) : Int
 end
diff --git a/src/lib_c/aarch64-darwin/c/pthread.cr b/src/lib_c/aarch64-darwin/c/pthread.cr
index dd262f7d9c12..d146e227197f 100644
--- a/src/lib_c/aarch64-darwin/c/pthread.cr
+++ b/src/lib_c/aarch64-darwin/c/pthread.cr
@@ -25,4 +25,5 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(Char*) : Int
 end
diff --git a/src/lib_c/aarch64-linux-gnu/c/pthread.cr b/src/lib_c/aarch64-linux-gnu/c/pthread.cr
index 643fca7c015a..5d9f7b94e225 100644
--- a/src/lib_c/aarch64-linux-gnu/c/pthread.cr
+++ b/src/lib_c/aarch64-linux-gnu/c/pthread.cr
@@ -36,4 +36,5 @@ lib LibC
   fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/aarch64-linux-musl/c/pthread.cr b/src/lib_c/aarch64-linux-musl/c/pthread.cr
index c318bb5f4357..6ee1a20d90a6 100644
--- a/src/lib_c/aarch64-linux-musl/c/pthread.cr
+++ b/src/lib_c/aarch64-linux-musl/c/pthread.cr
@@ -27,4 +27,5 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/arm-linux-gnueabihf/c/pthread.cr b/src/lib_c/arm-linux-gnueabihf/c/pthread.cr
index 643fca7c015a..5d9f7b94e225 100644
--- a/src/lib_c/arm-linux-gnueabihf/c/pthread.cr
+++ b/src/lib_c/arm-linux-gnueabihf/c/pthread.cr
@@ -36,4 +36,5 @@ lib LibC
   fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/i386-linux-gnu/c/pthread.cr b/src/lib_c/i386-linux-gnu/c/pthread.cr
index ab943b23587d..33274a6cf51d 100644
--- a/src/lib_c/i386-linux-gnu/c/pthread.cr
+++ b/src/lib_c/i386-linux-gnu/c/pthread.cr
@@ -35,4 +35,5 @@ lib LibC
   fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/i386-linux-musl/c/pthread.cr b/src/lib_c/i386-linux-musl/c/pthread.cr
index c318bb5f4357..6ee1a20d90a6 100644
--- a/src/lib_c/i386-linux-musl/c/pthread.cr
+++ b/src/lib_c/i386-linux-musl/c/pthread.cr
@@ -27,4 +27,5 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/x86_64-darwin/c/pthread.cr b/src/lib_c/x86_64-darwin/c/pthread.cr
index dd262f7d9c12..d146e227197f 100644
--- a/src/lib_c/x86_64-darwin/c/pthread.cr
+++ b/src/lib_c/x86_64-darwin/c/pthread.cr
@@ -25,4 +25,5 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(Char*) : Int
 end
diff --git a/src/lib_c/x86_64-dragonfly/c/pthread.cr b/src/lib_c/x86_64-dragonfly/c/pthread.cr
index 87ae8c05c358..90bf0c6285a0 100644
--- a/src/lib_c/x86_64-dragonfly/c/pthread.cr
+++ b/src/lib_c/x86_64-dragonfly/c/pthread.cr
@@ -29,4 +29,5 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/x86_64-freebsd/c/pthread.cr b/src/lib_c/x86_64-freebsd/c/pthread.cr
index 87ae8c05c358..9cc78c2f2850 100644
--- a/src/lib_c/x86_64-freebsd/c/pthread.cr
+++ b/src/lib_c/x86_64-freebsd/c/pthread.cr
@@ -29,4 +29,5 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_set_name_np(PthreadT, Char*)
 end
diff --git a/src/lib_c/x86_64-linux-gnu/c/pthread.cr b/src/lib_c/x86_64-linux-gnu/c/pthread.cr
index ab943b23587d..33274a6cf51d 100644
--- a/src/lib_c/x86_64-linux-gnu/c/pthread.cr
+++ b/src/lib_c/x86_64-linux-gnu/c/pthread.cr
@@ -35,4 +35,5 @@ lib LibC
   fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/x86_64-linux-musl/c/pthread.cr b/src/lib_c/x86_64-linux-musl/c/pthread.cr
index c318bb5f4357..6ee1a20d90a6 100644
--- a/src/lib_c/x86_64-linux-musl/c/pthread.cr
+++ b/src/lib_c/x86_64-linux-musl/c/pthread.cr
@@ -27,4 +27,5 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*) : Int
 end
diff --git a/src/lib_c/x86_64-netbsd/c/pthread.cr b/src/lib_c/x86_64-netbsd/c/pthread.cr
index 133d4922c57f..e0f477018777 100644
--- a/src/lib_c/x86_64-netbsd/c/pthread.cr
+++ b/src/lib_c/x86_64-netbsd/c/pthread.cr
@@ -35,5 +35,6 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_setname_np(PthreadT, Char*, Void*) : Int
   fun pthread_setspecific(PthreadKeyT, Void*) : Int
 end
diff --git a/src/lib_c/x86_64-openbsd/c/pthread.cr b/src/lib_c/x86_64-openbsd/c/pthread.cr
index 788823c40a31..15773336f239 100644
--- a/src/lib_c/x86_64-openbsd/c/pthread.cr
+++ b/src/lib_c/x86_64-openbsd/c/pthread.cr
@@ -30,6 +30,7 @@ lib LibC
   fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int
   fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int
   fun pthread_self : PthreadT
+  fun pthread_set_name_np(PthreadT, Char*)
   fun pthread_setspecific(PthreadKeyT, Void*) : Int
   fun pthread_stackseg_np(PthreadT, StackT*) : Int
 end
diff --git a/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr b/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr
index 9c22d4530c81..efa684075162 100644
--- a/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr
+++ b/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr
@@ -50,6 +50,9 @@ lib LibC
                      bInheritHandles : BOOL, dwCreationFlags : DWORD,
                      lpEnvironment : Void*, lpCurrentDirectory : LPWSTR,
                      lpStartupInfo : STARTUPINFOW*, lpProcessInformation : PROCESS_INFORMATION*) : BOOL
+  {% if LibC::WIN32_WINNT >= LibC::WIN32_WINNT_WIN10 %}
+    fun SetThreadDescription(hThread : HANDLE, lpThreadDescription : LPWSTR) : LONG
+  {% end %}
   fun SetThreadStackGuarantee(stackSizeInBytes : DWORD*) : BOOL
   fun GetProcessTimes(hProcess : HANDLE, lpCreationTime : FILETIME*, lpExitTime : FILETIME*,
                       lpKernelTime : FILETIME*, lpUserTime : FILETIME*) : BOOL

From e6d4998b5580456e3b9ecbffb40395f2699f3d69 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Wed, 31 Jan 2024 03:13:16 +0800
Subject: [PATCH 086/105] Add `ReferenceStorage` for manual allocation of
 references (#14270)

---
 .../semantic/reference_storage_spec.cr        | 72 +++++++++++++++++++
 spec/primitives/reference_spec.cr             |  4 +-
 src/compiler/crystal/codegen/llvm_typer.cr    |  4 ++
 .../crystal/semantic/top_level_visitor.cr     | 70 +++++++++++++++---
 src/compiler/crystal/types.cr                 | 29 +++++++-
 src/prelude.cr                                |  1 +
 src/reference_storage.cr                      | 55 ++++++++++++++
 7 files changed, 221 insertions(+), 14 deletions(-)
 create mode 100644 spec/compiler/semantic/reference_storage_spec.cr
 create mode 100644 src/reference_storage.cr

diff --git a/spec/compiler/semantic/reference_storage_spec.cr b/spec/compiler/semantic/reference_storage_spec.cr
new file mode 100644
index 000000000000..a0c0f2343260
--- /dev/null
+++ b/spec/compiler/semantic/reference_storage_spec.cr
@@ -0,0 +1,72 @@
+require "../../spec_helper"
+
+describe "Semantic: ReferenceStorage" do
+  it "errors if T is a struct type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Foo (T must be a reference type)"
+      @[Primitive(:ReferenceStorageType)]
+      struct ReferenceStorage(T) < Value
+      end
+
+      struct Foo
+        @x = 1
+      end
+
+      ReferenceStorage(Foo)
+      CRYSTAL
+  end
+
+  it "errors if T is a value type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Int32 (T must be a reference type)"
+      @[Primitive(:ReferenceStorageType)]
+      struct ReferenceStorage(T) < Value
+      end
+
+      ReferenceStorage(Int32)
+      CRYSTAL
+  end
+
+  it "errors if T is a union type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Bar | Foo) (T must be a reference type)"
+      @[Primitive(:ReferenceStorageType)]
+      struct ReferenceStorage(T) < Value
+      end
+
+      class Foo
+      end
+
+      class Bar
+      end
+
+      ReferenceStorage(Foo | Bar)
+      CRYSTAL
+  end
+
+  it "errors if T is a nilable type" do
+    assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Foo | Nil) (T must be a reference type)"
+      @[Primitive(:ReferenceStorageType)]
+      struct ReferenceStorage(T) < Value
+      end
+
+      class Foo
+      end
+
+      ReferenceStorage(Foo?)
+      CRYSTAL
+  end
+
+  it "allows a different name" do
+    assert_type(<<-CRYSTAL) { types["Foo"].metaclass }
+      @[Primitive(:ReferenceStorageType)]
+      struct MyRef(U) < Value
+        def u
+          U
+        end
+      end
+
+      class Foo
+      end
+
+      MyRef(Foo).new.u
+      CRYSTAL
+  end
+end
diff --git a/spec/primitives/reference_spec.cr b/spec/primitives/reference_spec.cr
index b73553748b65..52f179296ee8 100644
--- a/spec/primitives/reference_spec.cr
+++ b/spec/primitives/reference_spec.cr
@@ -43,9 +43,7 @@ describe "Primitives: reference" do
     end
 
     it "works when address is on the stack" do
-      # suitably aligned, sufficient storage for type ID + i64 + ptr
-      # TODO: use `ReferenceStorage` instead
-      foo_buffer = uninitialized UInt64[3]
+      foo_buffer = uninitialized ReferenceStorage(Foo)
       foo = Foo.pre_initialize(pointerof(foo_buffer))
       pointerof(foo_buffer).as(typeof(Foo.crystal_instance_type_id)*).value.should eq(Foo.crystal_instance_type_id)
       foo.str.should eq("abc")
diff --git a/src/compiler/crystal/codegen/llvm_typer.cr b/src/compiler/crystal/codegen/llvm_typer.cr
index d20fbd59fa9a..d72a25ecd3cb 100644
--- a/src/compiler/crystal/codegen/llvm_typer.cr
+++ b/src/compiler/crystal/codegen/llvm_typer.cr
@@ -245,6 +245,10 @@ module Crystal
       llvm_type(type.remove_alias, wants_size)
     end
 
+    private def create_llvm_type(type : ReferenceStorageType, wants_size)
+      llvm_struct_type(type.reference_type, wants_size)
+    end
+
     private def create_llvm_type(type : NonGenericModuleType | GenericClassType, wants_size)
       # This can only be reached if the module or generic class don't have implementors
       @llvm_context.int1
diff --git a/src/compiler/crystal/semantic/top_level_visitor.cr b/src/compiler/crystal/semantic/top_level_visitor.cr
index 9b7eedb2a876..98ceb23df6b3 100644
--- a/src/compiler/crystal/semantic/top_level_visitor.cr
+++ b/src/compiler/crystal/semantic/top_level_visitor.cr
@@ -41,6 +41,11 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
 
   @last_doc : String?
 
+  # special types recognized for `@[Primitive]`
+  private enum PrimitiveType
+    ReferenceStorageType
+  end
+
   def visit(node : ClassDef)
     check_outside_exp node, "declare class"
 
@@ -48,6 +53,27 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
 
     annotations = read_annotations
 
+    special_type = nil
+    process_annotations(annotations) do |annotation_type, ann|
+      case annotation_type
+      when @program.primitive_annotation
+        if ann.args.size != 1
+          ann.raise "expected Primitive annotation to have one argument"
+        end
+
+        arg = ann.args.first
+        unless arg.is_a?(SymbolLiteral)
+          arg.raise "expected Primitive argument to be a symbol literal"
+        end
+
+        value = arg.value
+        special_type = PrimitiveType.parse?(value)
+        unless special_type
+          arg.raise "BUG: Unknown primitive type #{value.inspect}"
+        end
+      end
+    end
+
     created_new_type = false
 
     if type
@@ -70,14 +96,34 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
       end
     else
       created_new_type = true
-      if type_vars = node.type_vars
-        type = GenericClassType.new @program, scope, name, nil, type_vars, false
-        type.splat_index = node.splat_index
-      else
-        type = NonGenericClassType.new @program, scope, name, nil, false
+      case special_type
+      in Nil
+        if type_vars = node.type_vars
+          type = GenericClassType.new @program, scope, name, nil, type_vars, false
+          type.splat_index = node.splat_index
+        else
+          type = NonGenericClassType.new @program, scope, name, nil, false
+        end
+        type.abstract = node.abstract?
+        type.struct = node.struct?
+      in .reference_storage_type?
+        type_vars = node.type_vars
+        case
+        when !node.struct?
+          node.raise "BUG: Expected ReferenceStorageType to be a struct type"
+        when node.abstract?
+          node.raise "BUG: Expected ReferenceStorageType to be a non-abstract type"
+        when !type_vars
+          node.raise "BUG: Expected ReferenceStorageType to be a generic type"
+        when type_vars.size != 1
+          node.raise "BUG: Expected ReferenceStorageType to have a single generic type parameter"
+        when node.splat_index
+          node.raise "BUG: Expected ReferenceStorageType to have no splat parameter"
+        end
+        type = GenericReferenceStorageType.new @program, scope, name, @program.value, type_vars
+        type.declare_instance_var("@type_id", @program.int32)
+        type.can_be_stored = false
       end
-      type.abstract = node.abstract?
-      type.struct = node.struct?
     end
 
     type.private = true if node.visibility.private?
@@ -133,6 +179,10 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
       if superclass.struct? && !superclass.abstract?
         node.raise "can't extend non-abstract struct #{superclass}"
       end
+
+      if type.is_a?(GenericReferenceStorageType) && superclass != @program.value
+        node.raise "BUG: Expected reference_storage_type to inherit from Value"
+      end
     end
 
     if created_new_type
@@ -375,7 +425,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
 
     process_def_annotations(node, annotations) do |annotation_type, ann|
       if annotation_type == @program.primitive_annotation
-        process_primitive_annotation(node, ann)
+        process_def_primitive_annotation(node, ann)
       end
 
       node.add_annotation(annotation_type, ann)
@@ -460,7 +510,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
     false
   end
 
-  private def process_primitive_annotation(node, ann)
+  private def process_def_primitive_annotation(node, ann)
     if ann.args.size != 1
       ann.raise "expected Primitive annotation to have one argument"
     end
@@ -926,7 +976,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
       if annotation_type == @program.call_convention_annotation
         call_convention = parse_call_convention(ann, call_convention)
       elsif annotation_type == @program.primitive_annotation
-        process_primitive_annotation(external, ann)
+        process_def_primitive_annotation(external, ann)
       else
         ann.raise "funs can only be annotated with: NoInline, AlwaysInline, Naked, ReturnsTwice, Raises, CallConvention"
       end
diff --git a/src/compiler/crystal/types.cr b/src/compiler/crystal/types.cr
index ad9f3d391fa6..5d903b763050 100644
--- a/src/compiler/crystal/types.cr
+++ b/src/compiler/crystal/types.cr
@@ -555,7 +555,7 @@ module Crystal
            program.tuple, program.named_tuple,
            program.pointer, program.static_array,
            program.union, program.enum, program.proc,
-           PrimitiveType
+           PrimitiveType, GenericReferenceStorageType
         false
       else
         true
@@ -2642,6 +2642,33 @@ module Crystal
     end
   end
 
+  # The non-instantiated ReferenceStorage(T) type.
+  class GenericReferenceStorageType < GenericClassType
+    @struct = true
+
+    def new_generic_instance(program, generic_type, type_vars)
+      type_param = self.type_vars.first
+      t = type_vars[type_param].type
+
+      unless t.is_a?(TypeParameter) || (t.class? && !t.struct?)
+        raise TypeException.new "Can't instantiate ReferenceStorage(#{type_param}) with #{type_param} = #{t} (#{type_param} must be a reference type)"
+      end
+
+      ReferenceStorageType.new program, t, self, type_param
+    end
+  end
+
+  class ReferenceStorageType < GenericClassInstanceType
+    getter reference_type : Type
+
+    def initialize(program, @reference_type, generic_type, type_param)
+      t_var = Var.new("T", @reference_type)
+      t_var.bind_to t_var
+
+      super(program, generic_type, program.value, {type_param => t_var} of String => ASTNode)
+    end
+  end
+
   # A lib type, like `lib LibC`.
   class LibType < ModuleType
     getter link_annotations : Array(LinkAnnotation)?
diff --git a/src/prelude.cr b/src/prelude.cr
index f06f5bc87015..f84bb86cb3c1 100644
--- a/src/prelude.cr
+++ b/src/prelude.cr
@@ -65,6 +65,7 @@ require "raise"
 require "random"
 require "range"
 require "reference"
+require "reference_storage"
 require "regex"
 require "set"
 {% unless flag?(:wasm32) %}
diff --git a/src/reference_storage.cr b/src/reference_storage.cr
new file mode 100644
index 000000000000..2ca3edc171aa
--- /dev/null
+++ b/src/reference_storage.cr
@@ -0,0 +1,55 @@
+# `ReferenceStorage(T)` provides the minimum storage for the instance data of
+# an object of type `T`. The compiler guarantees that
+# `sizeof(ReferenceStorage(T)) == instance_sizeof(T)` and
+# `alignof(ReferenceStorage(T)) == instance_alignof(T)` always hold, which means
+# `Pointer(ReferenceStorage(T))` and `T` are binary-compatible.
+#
+# `T` must be a non-union reference type.
+#
+# WARNING: `ReferenceStorage` is only necessary for manual memory management,
+# such as creating instances of `T` with a non-default allocator. Therefore,
+# this type is unsafe and no public constructors are defined.
+#
+# WARNING: `ReferenceStorage` is unsuitable when instances of `T` require more
+# than `instance_sizeof(T)` bytes, such as `String` and `Log::Metadata`.
+@[Experimental("This type's API is still under development. Join the discussion about custom reference allocation at [#13481](https://github.com/crystal-lang/crystal/issues/13481).")]
+@[Primitive(:ReferenceStorageType)]
+struct ReferenceStorage(T) < Value
+  private def initialize
+  end
+
+  # Returns whether `self` and *other* are bytewise equal.
+  #
+  # NOTE: This does not call `T#==`, so it works even if `self` or *other* does
+  # not represent a valid instance of `T`. If validity is guaranteed, call
+  # `to_reference == other.to_reference` instead to use `T#==`.
+  def ==(other : ReferenceStorage(T)) : Bool
+    to_bytes == other.to_bytes
+  end
+
+  def ==(other) : Bool
+    false
+  end
+
+  def hash(hasher)
+    to_bytes.hash(hasher)
+  end
+
+  def to_s(io : IO) : Nil
+    io << "ReferenceStorage(#<" << T << ":0x"
+    pointerof(@type_id).address.to_s(io, 16)
+    io << ">)"
+  end
+
+  # Returns a `T` whose instance data refers to `self`.
+  #
+  # WARNING: The caller is responsible for ensuring that the instance data is
+  # correctly initialized and outlives the returned `T`.
+  def to_reference : T
+    pointerof(@type_id).as(T)
+  end
+
+  protected def to_bytes
+    Slice.new(pointerof(@type_id).as(UInt8*), instance_sizeof(T))
+  end
+end

From 9890b17d97a46522c825edb8651607f6f53fd108 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Wed, 31 Jan 2024 03:13:31 +0800
Subject: [PATCH 087/105] Fix end locations of `Alias` nodes (#14271)

---
 spec/compiler/parser/parser_spec.cr   | 1 +
 src/compiler/crystal/syntax/parser.cr | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr
index 9f4ec5faccf7..c9a28d87c33f 100644
--- a/spec/compiler/parser/parser_spec.cr
+++ b/spec/compiler/parser/parser_spec.cr
@@ -2252,6 +2252,7 @@ module Crystal
       assert_end_location "class Foo; end"
       assert_end_location "struct Foo; end"
       assert_end_location "module Foo; end"
+      assert_end_location "alias Foo = Bar"
       assert_end_location "->{ }"
       assert_end_location "macro foo;end"
       assert_end_location "macro foo; 123; end"
diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr
index e3f4c2605ed6..16a45eaf5e22 100644
--- a/src/compiler/crystal/syntax/parser.cr
+++ b/src/compiler/crystal/syntax/parser.cr
@@ -5854,9 +5854,10 @@ module Crystal
       next_token_skip_space_or_newline
 
       value = parse_bare_proc_type
+      end_location = value.end_location
       skip_space
 
-      alias_node = Alias.new(name, value)
+      alias_node = Alias.new(name, value).at_end(end_location)
       alias_node.doc = doc
       alias_node
     end

From 14f69e38cadf06ff5594b562d22d3b38689c3d4d Mon Sep 17 00:00:00 2001
From: Julien Portalier <julien@portalier.com>
Date: Wed, 31 Jan 2024 12:42:24 +0100
Subject: [PATCH 088/105] Interpreter: fix fiber's resumable property (#14252)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
Co-authored-by: Johannes Müller <straightshoota@gmail.com>
---
 spec/interpreter_std_spec.cr                  |  1 +
 spec/std/fiber_spec.cr                        | 21 +++++++++++++++++++
 .../crystal/interpreter/instructions.cr       |  5 +++++
 .../crystal/interpreter/interpreter.cr        | 11 ++++++++--
 .../crystal/interpreter/primitives.cr         |  3 +++
 src/crystal/interpreter.cr                    |  5 +++++
 src/crystal/scheduler.cr                      |  8 -------
 src/fiber/context.cr                          | 20 ++++++++++++++++--
 src/fiber/context/interpreted.cr              |  4 ++--
 9 files changed, 64 insertions(+), 14 deletions(-)
 create mode 100644 spec/std/fiber_spec.cr

diff --git a/spec/interpreter_std_spec.cr b/spec/interpreter_std_spec.cr
index 3cdcc55cbd61..8638b0a83f7f 100644
--- a/spec/interpreter_std_spec.cr
+++ b/spec/interpreter_std_spec.cr
@@ -72,6 +72,7 @@ require "./std/env_spec.cr"
 require "./std/errno_spec.cr"
 # require "./std/exception/call_stack_spec.cr" (failed to run)
 # require "./std/exception_spec.cr" (failed to run)
+require "./std/fiber_spec.cr"
 require "./std/file_spec.cr"
 require "./std/file/tempfile_spec.cr"
 require "./std/file_utils_spec.cr"
diff --git a/spec/std/fiber_spec.cr b/spec/std/fiber_spec.cr
new file mode 100644
index 000000000000..5c85d1a7475d
--- /dev/null
+++ b/spec/std/fiber_spec.cr
@@ -0,0 +1,21 @@
+require "spec"
+
+describe Fiber do
+  it "#resumable?" do
+    done = false
+    resumable = nil
+
+    fiber = spawn do
+      resumable = Fiber.current.resumable?
+      done = true
+    end
+
+    fiber.resumable?.should be_true
+
+    until done
+      Fiber.yield
+    end
+
+    resumable.should be_false
+  end
+end
diff --git a/src/compiler/crystal/interpreter/instructions.cr b/src/compiler/crystal/interpreter/instructions.cr
index 67966277bf15..f2b8abcb9a51 100644
--- a/src/compiler/crystal/interpreter/instructions.cr
+++ b/src/compiler/crystal/interpreter/instructions.cr
@@ -1649,6 +1649,11 @@ require "./repl"
         pop_values: [current_context : Void*, new_context : Void*],
         code:       swapcontext(current_context, new_context),
       },
+      interpreter_fiber_resumable: {
+        pop_values: [context : Void*],
+        push:       true,
+        code:       fiber_resumable(context),
+      },
 
       {% if flag?(:bits64) %}
         interpreter_intrinsics_memcpy: {
diff --git a/src/compiler/crystal/interpreter/interpreter.cr b/src/compiler/crystal/interpreter/interpreter.cr
index 608fb6d85d1a..eca73ecae6bc 100644
--- a/src/compiler/crystal/interpreter/interpreter.cr
+++ b/src/compiler/crystal/interpreter/interpreter.cr
@@ -1154,6 +1154,7 @@ class Crystal::Repl::Interpreter
         nil
       end
     end
+    spawned_fiber.@context.resumable = 1
     spawned_fiber.as(Void*)
   end
 
@@ -1161,11 +1162,17 @@ class Crystal::Repl::Interpreter
     # current_fiber = current_context.as(Fiber*).value
     new_fiber = new_context.as(Fiber*).value
 
-    # We directly resume the next fiber.
-    # TODO: is this okay? We totally ignore the scheduler here!
+    # delegates the context switch to the interpreter's scheduler, so we update
+    # the current fiber reference, set the GC stack bottom, and so on (aka
+    # there's more to switching context than `Fiber.swapcontext`):
     new_fiber.resume
   end
 
+  private def fiber_resumable(context : Void*) : LibC::Long
+    fiber = context.as(Fiber*).value
+    fiber.@context.resumable
+  end
+
   private def pry(ip, instructions, stack_bottom, stack)
     offset = (ip - instructions.instructions.to_unsafe).to_i32
     node = instructions.nodes[offset]?
diff --git a/src/compiler/crystal/interpreter/primitives.cr b/src/compiler/crystal/interpreter/primitives.cr
index 1d50568c5d62..968361fb6c1d 100644
--- a/src/compiler/crystal/interpreter/primitives.cr
+++ b/src/compiler/crystal/interpreter/primitives.cr
@@ -402,6 +402,9 @@ class Crystal::Repl::Compiler
     when "interpreter_fiber_swapcontext"
       accept_call_args(node)
       interpreter_fiber_swapcontext(node: node)
+    when "interpreter_fiber_resumable"
+      accept_call_args(node)
+      interpreter_fiber_resumable(node: node)
     when "interpreter_intrinsics_memcpy"
       accept_call_args(node)
       interpreter_intrinsics_memcpy(node: node)
diff --git a/src/crystal/interpreter.cr b/src/crystal/interpreter.cr
index 2a9a6b23c5f8..d3b3589d50cb 100644
--- a/src/crystal/interpreter.cr
+++ b/src/crystal/interpreter.cr
@@ -19,5 +19,10 @@ module Crystal
     @[Primitive(:interpreter_spawn)]
     def self.spawn(fiber : Fiber, fiber_main : Void*) : Void*
     end
+
+    # Returns the resumable value from the interpreter's fiber.
+    @[Primitive(:interpreter_fiber_resumable)]
+    def self.fiber_resumable(context) : LibC::Long
+    end
   end
 end
diff --git a/src/crystal/scheduler.cr b/src/crystal/scheduler.cr
index 101a287d23bb..1728a9b7f335 100644
--- a/src/crystal/scheduler.cr
+++ b/src/crystal/scheduler.cr
@@ -125,14 +125,6 @@ class Crystal::Scheduler
     {% end %}
 
     current, @current = @current, fiber
-
-    {% if flag?(:interpreted) %}
-      # TODO: ideally we could set this in the interpreter if the
-      # @context had a pointer back to the fiber.
-      # I also wonder why this isn't done always like that instead of in asm.
-      current.@context.resumable = 1
-    {% end %}
-
     Fiber.swapcontext(pointerof(current.@context), pointerof(fiber.@context))
 
     {% if flag?(:preview_mt) %}
diff --git a/src/fiber/context.cr b/src/fiber/context.cr
index 28b54458fe66..eab06d886de6 100644
--- a/src/fiber/context.cr
+++ b/src/fiber/context.cr
@@ -7,10 +7,26 @@ class Fiber
   @[Extern]
   struct Context
     property stack_top : Void*
-    property resumable : LibC::Long
+
+    {% if flag?(:interpreted) %}
+      # In interpreted mode, the interpreted fibers will be backed by a real
+      # fiber run by the interpreter. The fiber context is thus fake.
+      #
+      # The `stack_top` property is actually a pointer to the real Fiber
+      # running in the interpreter.
+      #
+      # The `resumable` property is also delegated to the real fiber. Only the
+      # getter is defined (so we know the real state of the fiber); we don't
+      # declare a setter because only the interpreter can manipulate it (in the
+      # `makecontext` and `swapcontext` primitives).
+      def resumable : LibC::Long
+        Crystal::Interpreter.fiber_resumable(pointerof(@stack_top))
+      end
+    {% else %}
+      property resumable : LibC::Long = 0
+    {% end %}
 
     def initialize(@stack_top = Pointer(Void).null)
-      @resumable = 0
     end
   end
 
diff --git a/src/fiber/context/interpreted.cr b/src/fiber/context/interpreted.cr
index 55b9354a1a57..900ad6f3111c 100644
--- a/src/fiber/context/interpreted.cr
+++ b/src/fiber/context/interpreted.cr
@@ -5,9 +5,9 @@ require "crystal/interpreter"
 class Fiber
   # :nodoc:
   def makecontext(stack_ptr, fiber_main) : Nil
-    # In interpreted mode the stack_top variable actually points to a fiber
+    # In interpreted mode the stack_top variable actually points to the actual
+    # fiber running on the interpreter
     @context.stack_top = Crystal::Interpreter.spawn(self, fiber_main.pointer)
-    @context.resumable = 1
   end
 
   # :nodoc:

From 202c655008e9b191aca30701ef678e54503ef1b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 31 Jan 2024 13:20:49 +0100
Subject: [PATCH 089/105] Add `crystal tool flags` (#14234)

---
 etc/completion.bash                       |   2 +-
 etc/completion.fish                       |   4 +-
 etc/completion.zsh                        |   7 ++
 man/crystal.1                             |   4 +-
 spec/compiler/crystal/tools/flags_spec.cr |  44 +++++++++
 src/compiler/crystal/command.cr           |   4 +
 src/compiler/crystal/tools/flags.cr       | 104 ++++++++++++++++++++++
 7 files changed, 166 insertions(+), 3 deletions(-)
 create mode 100644 spec/compiler/crystal/tools/flags_spec.cr
 create mode 100644 src/compiler/crystal/tools/flags.cr

diff --git a/etc/completion.bash b/etc/completion.bash
index d8731c65bff7..9263289b5b4e 100644
--- a/etc/completion.bash
+++ b/etc/completion.bash
@@ -66,7 +66,7 @@ _crystal()
                 _crystal_compgen_options "${opts}" "${cur}"
             else
                 if [[ "${prev}" == "tool" ]] ; then
-                    local subcommands="context dependencies format hierarchy implementations types"
+                    local subcommands="context dependencies flags format hierarchy implementations types"
                     _crystal_compgen_options "${subcommands}" "${cur}"
                 else
                     _crystal_compgen_sources "${cur}"
diff --git a/etc/completion.fish b/etc/completion.fish
index 150dd37108d8..64fc6a97b45a 100644
--- a/etc/completion.fish
+++ b/etc/completion.fish
@@ -1,5 +1,5 @@
 set -l crystal_commands init build clear_cache docs env eval i interactive play run spec tool help version
-set -l tool_subcommands context expand format hierarchy implementations types
+set -l tool_subcommands context expand flags format hierarchy implementations types
 
 complete -c crystal -s h -l help -d "Show help" -x
 
@@ -173,6 +173,8 @@ complete -c crystal -n "__fish_seen_subcommand_from expand" -s p -l progress -d
 complete -c crystal -n "__fish_seen_subcommand_from expand" -s t -l time -d "Enable execution time output"
 complete -c crystal -n "__fish_seen_subcommand_from expand" -l stdin-filename -d "Source file name to be read from STDIN"
 
+complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "flags" -d "print all macro 'flag?' values" -x
+
 complete -c crystal -n "__fish_seen_subcommand_from tool; and not __fish_seen_subcommand_from $tool_subcommands" -a "format" -d "format project, directories and/or files" -x
 complete -c crystal -n "__fish_seen_subcommand_from format" -l check -d "Checks that formatting code produces no changes"
 complete -c crystal -n "__fish_seen_subcommand_from format" -s i -l include -d "Include path"
diff --git a/etc/completion.zsh b/etc/completion.zsh
index bf57d80208df..ffa12798ca18 100644
--- a/etc/completion.zsh
+++ b/etc/completion.zsh
@@ -165,6 +165,7 @@ _crystal-tool() {
         "context:show context for given location"
         "dependencies:show tree of required source files"
         "expand:show macro expansion for given location"
+        "flags:print all macro 'flag?' values"
         "format:format project, directories and/or files"
         "hierarchy:show type hierarchy"
         "implementations:show implementations for given call in location"
@@ -211,6 +212,12 @@ _crystal-tool() {
             $cursor_args
         ;;
 
+        (flags)
+          _arguments \
+            $programfile \
+            $help_args
+        ;;
+
         (format)
           _arguments \
             $programfile \
diff --git a/man/crystal.1 b/man/crystal.1
index ef23beac77c3..15fed461c26c 100644
--- a/man/crystal.1
+++ b/man/crystal.1
@@ -369,7 +369,7 @@ Disable colored output.
 .Op --
 .Op arguments
 .Pp
-Run a tool. The available tools are: context, dependencies, format, hierarchy, implementations, and types.
+Run a tool. The available tools are: context, dependencies, flags, format, hierarchy, implementations, and types.
 .Pp
 Tools:
 .Bl -tag -offset indent
@@ -398,6 +398,8 @@ Show skipped and heads of filtered paths
 .El
 .It Cm expand
 Show macro expansion for given location.
+.It Cm flags
+Print all macro 'flag?' values
 .It Cm format
 Format project, directories and/or files with the coding style used in the standard library. You can use the
 .Fl -check
diff --git a/spec/compiler/crystal/tools/flags_spec.cr b/spec/compiler/crystal/tools/flags_spec.cr
new file mode 100644
index 000000000000..c295439e0547
--- /dev/null
+++ b/spec/compiler/crystal/tools/flags_spec.cr
@@ -0,0 +1,44 @@
+require "../../../spec_helper"
+include Crystal
+
+private def parse_flags(source)
+  Crystal::Command::FlagsVisitor.new.tap do |visitor|
+    Parser.parse(source).accept(visitor)
+  end
+end
+
+describe Crystal::Command::FlagsVisitor do
+  it "different flags" do
+    visitor = parse_flags <<-CRYSTAL
+      {%
+        flag?(:foo)
+        flag?("bar")
+        flag?(1)
+        flag?(true)
+      %}
+      CRYSTAL
+    visitor.flag_names.should eq %w[1 bar foo true]
+  end
+
+  it "unique flags" do
+    visitor = parse_flags <<-CRYSTAL
+      {%
+        flag?(:foo)
+        flag?("foo")
+        flag?(:foo)
+      %}
+      CRYSTAL
+    visitor.flag_names.should eq %w[foo]
+  end
+
+  it "only macro" do
+    visitor = parse_flags <<-CRYSTAL
+      flag?(:flag)
+      f.flag?(:foo)
+      F.flag?(:bar)
+      {% f.flag?(:baz) %}
+      {% f.flag?(:qux, other: true) %}
+      CRYSTAL
+    visitor.flag_names.should eq %w[]
+  end
+end
diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr
index 18def74ebbd0..178a307a54b8 100644
--- a/src/compiler/crystal/command.cr
+++ b/src/compiler/crystal/command.cr
@@ -41,6 +41,7 @@ class Crystal::Command
     Tool:
         context                  show context for given location
         expand                   show macro expansion for given location
+        flags                    print all macro `flag?` values
         format                   format project, directories and/or files
         hierarchy                show type hierarchy
         dependencies             show file dependency tree
@@ -177,6 +178,9 @@ class Crystal::Command
     when "format".starts_with?(tool)
       options.shift
       format
+    when "flags" == tool
+      options.shift
+      flags
     when "expand".starts_with?(tool)
       options.shift
       expand
diff --git a/src/compiler/crystal/tools/flags.cr b/src/compiler/crystal/tools/flags.cr
new file mode 100644
index 000000000000..17bb15007021
--- /dev/null
+++ b/src/compiler/crystal/tools/flags.cr
@@ -0,0 +1,104 @@
+require "colorize"
+require "../syntax/ast"
+
+class Crystal::Command
+  private def flags
+    OptionParser.parse(@options) do |opts|
+      opts.banner = "Usage: crystal tool flags [path...]\n\nOptions:"
+
+      opts.on("-h", "--help", "Show this message") do
+        puts opts
+        exit
+      end
+
+      opts.on("--no-color", "Disable colored output") do
+        @color = false
+      end
+    end
+
+    visitor = FlagsVisitor.new
+    find_sources(options) do |source|
+      Parser.parse(source.code).accept(visitor)
+    end
+    visitor.flag_names.each do |flag|
+      puts flag
+    end
+  end
+
+  def find_sources(
+    paths : Array(String),
+    stdin : IO = STDIN,
+    & : Compiler::Source ->
+  ) : Nil
+    stdin_content = nil
+    paths.each do |path|
+      if path == "-"
+        stdin_content ||= stdin.gets_to_end
+        yield Compiler::Source.new(path, stdin_content)
+      elsif File.file?(path)
+        yield Compiler::Source.new(path, File.read(path))
+      elsif Dir.exists?(path)
+        Dir.glob(::Path[path].to_posix.join("**/*.cr")) do |dir_path|
+          if File.file?(dir_path)
+            yield Compiler::Source.new(path, File.read(dir_path))
+          end
+        end
+      else
+        Crystal.error "file or directory does not exist: #{path}", @color, leading_error: false
+      end
+    end
+  end
+
+  class FlagsVisitor < Visitor
+    @in_macro_expression = false
+
+    getter all_flags = [] of ASTNode
+
+    def initialize(@flag_name : String = "flag?")
+    end
+
+    def flag_names
+      all_flags.map { |flag| string_flag(flag) }.uniq!.sort!
+    end
+
+    private def string_flag(node)
+      case node
+      when StringLiteral, SymbolLiteral
+        node.value
+      else
+        node.to_s
+      end
+    end
+
+    def visit(node)
+      true
+    end
+
+    def visit(node : Crystal::MacroExpression | Crystal::MacroIf | Crystal::MacroFor)
+      @in_macro_expression = true
+
+      true
+    end
+
+    def end_visit(node : Crystal::MacroExpression | Crystal::MacroIf | Crystal::MacroFor)
+      @in_macro_expression = false
+    end
+
+    def visit(node : Crystal::Call)
+      check_call(node)
+      true
+    end
+
+    private def check_call(node)
+      return unless @in_macro_expression
+      return unless node.name == @flag_name
+      return unless node.obj.nil? && node.block.nil? && node.named_args.nil?
+
+      args = node.args
+      return unless args.size == 1
+      arg = args[0]
+
+      all_flags << arg
+    end
+  end
+end

From 2f48d297feb527b1a29a3108d05da98f33a5a434 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Wed, 31 Jan 2024 21:04:09 +0100
Subject: [PATCH 090/105] Document builtin constants (#14276)

---
 src/compiler/crystal/program.cr | 91 ++++++++++++++++++++++++---------
 1 file changed, 66 insertions(+), 25 deletions(-)

diff --git a/src/compiler/crystal/program.cr b/src/compiler/crystal/program.cr
index 936fc6a0a270..675202ee0144 100644
--- a/src/compiler/crystal/program.cr
+++ b/src/compiler/crystal/program.cr
@@ -275,36 +275,77 @@ module Crystal
     # Defines a predefined constant in the Crystal module, such as BUILD_DATE and VERSION.
     private def define_crystal_constants
       if build_commit = Crystal::Config.build_commit
-        define_crystal_string_constant "BUILD_COMMIT", build_commit
+        build_commit_const = define_crystal_string_constant "BUILD_COMMIT", build_commit
       else
-        define_crystal_nil_constant "BUILD_COMMIT"
+        build_commit_const = define_crystal_nil_constant "BUILD_COMMIT"
       end
-
-      define_crystal_string_constant "BUILD_DATE", Crystal::Config.date
-      define_crystal_string_constant "CACHE_DIR", CacheDir.instance.dir
-      define_crystal_string_constant "DEFAULT_PATH", Crystal::Config.path
-      define_crystal_string_constant "DESCRIPTION", Crystal::Config.description
-      define_crystal_string_constant "PATH", Crystal::CrystalPath.default_path
-      define_crystal_string_constant "LIBRARY_PATH", Crystal::CrystalLibraryPath.default_path
-      define_crystal_string_constant "LIBRARY_RPATH", Crystal::CrystalLibraryPath.default_rpath
-      define_crystal_string_constant "VERSION", Crystal::Config.version
-      define_crystal_string_constant "LLVM_VERSION", Crystal::Config.llvm_version
-      define_crystal_string_constant "HOST_TRIPLE", Crystal::Config.host_target.to_s
-      define_crystal_string_constant "TARGET_TRIPLE", Crystal::Config.host_target.to_s
-    end
-
-    private def define_crystal_string_constant(name, value)
-      define_crystal_constant name, StringLiteral.new(value).tap(&.set_type(string))
-    end
-
-    private def define_crystal_nil_constant(name)
-      define_crystal_constant name, NilLiteral.new.tap(&.set_type(self.nil))
-    end
-
-    private def define_crystal_constant(name, value)
+      build_commit_const.doc = <<-MD if wants_doc?
+        The build commit identifier of the Crystal compiler.
+        MD
+
+      define_crystal_string_constant "BUILD_DATE", Crystal::Config.date, <<-MD
+        The build date of the Crystal compiler.
+        MD
+      define_crystal_string_constant "CACHE_DIR", CacheDir.instance.dir, <<-MD
+        The cache directory configured for the Crystal compiler.
+
+        The value is defined by the environment variable `CRYSTAL_CACHE_DIR` and
+        defaults to the user's configured cache directory.
+        MD
+      define_crystal_string_constant "DEFAULT_PATH", Crystal::Config.path, <<-MD
+        The default Crystal path configured in the compiler. This value is baked
+        into the compiler and usually points to the accompanying version of the
+        standard library.
+        MD
+      define_crystal_string_constant "DESCRIPTION", Crystal::Config.description, <<-MD
+        Full version information of the Crystal compiler. Equivalent to `crystal --version`.
+        MD
+      define_crystal_string_constant "PATH", Crystal::CrystalPath.default_path, <<-MD
+        Colon-separated paths where the compiler searches for required source files.
+
+        The value is defined by the environment variable `CRYSTAL_PATH`
+        and defaults to `DEFAULT_PATH`.
+        MD
+      define_crystal_string_constant "LIBRARY_PATH", Crystal::CrystalLibraryPath.default_path, <<-MD
+        Colon-separated paths where the compiler searches for (binary) libraries.
+
+        The value is defined by the environment variables `CRYSTAL_LIBRARY_PATH`.
+        MD
+      define_crystal_string_constant "LIBRARY_RPATH", Crystal::CrystalLibraryPath.default_rpath, <<-MD
+        Colon-separated paths where the loader searches for dynamic libraries at runtime.
+
+        The value is defined by the environment variables `CRYSTAL_LIBRARY_RPATH`.
+        MD
+      define_crystal_string_constant "VERSION", Crystal::Config.version, <<-MD
+        The version of the Crystal compiler.
+        MD
+      define_crystal_string_constant "LLVM_VERSION", Crystal::Config.llvm_version, <<-MD
+        The version of LLVM used by the Crystal compiler.
+        MD
+      define_crystal_string_constant "HOST_TRIPLE", Crystal::Config.host_target.to_s, <<-MD
+        The LLVM target triple of the host system (the machine that the compiler runs on).
+        MD
+      define_crystal_string_constant "TARGET_TRIPLE", Crystal::Config.host_target.to_s, <<-MD
+        The LLVM target triple of the target system (the machine that the compiler builds for).
+        MD
+    end
+
+    private def define_crystal_string_constant(name, value, doc = nil)
+      define_crystal_constant name, StringLiteral.new(value).tap(&.set_type(string)), doc
+    end
+
+    private def define_crystal_nil_constant(name, doc = nil)
+      define_crystal_constant name, NilLiteral.new.tap(&.set_type(self.nil)), doc
+    end
+
+    private def define_crystal_constant(name, value, doc = nil) : Const
       crystal.types[name] = const = Const.new self, crystal, name, value
       const.no_init_flag = true
+      if doc && wants_doc?
+        const.doc = doc
+      end
       predefined_constants << const
+      const
     end
 
     property(target_machine : LLVM::TargetMachine) { codegen_target.to_target_machine }

From b655c0f43d57e889ff3767635733396bd67455be Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Fri, 2 Feb 2024 21:22:39 +0800
Subject: [PATCH 091/105] Respect alignments above `alignof(Void*)` inside
 union values (#14279)

---
 spec/compiler/codegen/cast_spec.cr      | 27 +++++++++
 spec/compiler/codegen/sizeof_spec.cr    | 10 ++++
 src/compiler/crystal/codegen/codegen.cr |  4 +-
 src/compiler/crystal/codegen/unions.cr  | 78 ++++++++++++++++++-------
 4 files changed, 96 insertions(+), 23 deletions(-)

diff --git a/spec/compiler/codegen/cast_spec.cr b/spec/compiler/codegen/cast_spec.cr
index 32b265ea0415..fbe6cd78ac87 100644
--- a/spec/compiler/codegen/cast_spec.cr
+++ b/spec/compiler/codegen/cast_spec.cr
@@ -77,6 +77,33 @@ describe "Code gen: cast" do
       )).to_b.should be_true
   end
 
+  it "upcasts from union to union with different alignment" do
+    run(<<-CRYSTAL).to_i.should eq(1)
+      require "prelude"
+
+      a = 1 || 2_i64
+      a.as(Int32 | Int64 | Int128)
+      CRYSTAL
+  end
+
+  it "downcasts from union to union with different alignment" do
+    run(<<-CRYSTAL).to_i.should eq(1)
+      require "prelude"
+
+      a = 1 || 2_i64 || 3_i128
+      a.as(Int32 | Int64)
+      CRYSTAL
+  end
+
+  it "sidecasts from union to union with different alignment" do
+    run(<<-CRYSTAL).to_i.should eq(1)
+      require "prelude"
+
+      a = 1 || 2_i64
+      a.as(Int32 | Int128)
+      CRYSTAL
+  end
+
   it "casts from virtual to single type" do
     run(%(
       require "prelude"
diff --git a/spec/compiler/codegen/sizeof_spec.cr b/spec/compiler/codegen/sizeof_spec.cr
index 8139db8bc426..e90553d0b3c1 100644
--- a/spec/compiler/codegen/sizeof_spec.cr
+++ b/spec/compiler/codegen/sizeof_spec.cr
@@ -279,6 +279,16 @@ describe "Code gen: sizeof" do
         alignof(Foo)
         CRYSTAL
     end
+
+    it "gets alignof union" do
+      run("alignof(Int32 | Int8)").to_i.should eq(8)
+      run("alignof(Int32 | Int64)").to_i.should eq(8)
+    end
+
+    it "alignof mixed union is not less than alignof its variant types" do
+      # NOTE: `alignof(Int128) == 16` is not guaranteed
+      run("alignof(Int32 | Int128) >= alignof(Int128)").to_b.should be_true
+    end
   end
 
   describe "instance_alignof" do
diff --git a/src/compiler/crystal/codegen/codegen.cr b/src/compiler/crystal/codegen/codegen.cr
index e7128302a66e..441f3cfa09ae 100644
--- a/src/compiler/crystal/codegen/codegen.cr
+++ b/src/compiler/crystal/codegen/codegen.cr
@@ -2253,11 +2253,11 @@ module Crystal
       res
     end
 
-    def memcpy(dest, src, len, align, volatile)
+    def memcpy(dest, src, len, align, volatile, *, src_align = align)
       res = call c_memcpy_fun, [dest, src, len, volatile]
 
       LibLLVM.set_instr_param_alignment(res, 1, align)
-      LibLLVM.set_instr_param_alignment(res, 2, align)
+      LibLLVM.set_instr_param_alignment(res, 2, src_align)
 
       res
     end
diff --git a/src/compiler/crystal/codegen/unions.cr b/src/compiler/crystal/codegen/unions.cr
index 1f29763d504a..7ac58ff84887 100644
--- a/src/compiler/crystal/codegen/unions.cr
+++ b/src/compiler/crystal/codegen/unions.cr
@@ -28,20 +28,19 @@ module Crystal
           @structs[llvm_name] = a_struct
         end
 
-        max_size = 0
+        max_size = 0_u64
+        max_alignment = pointer_size.to_u32!
+
         type.expand_union_types.each do |subtype|
           unless subtype.void?
-            size = size_of(llvm_type(subtype, wants_size: true))
-            max_size = size if size > max_size
+            llvm_type = llvm_type(subtype, wants_size: true)
+            max_size = {size_of(llvm_type), max_size}.max
+            max_alignment = {align_of(llvm_type), max_alignment}.max
           end
         end
 
-        max_size /= pointer_size.to_f
-        max_size = max_size.ceil.to_i
-
-        max_size = 1 if max_size == 0
-
-        llvm_value_type = size_t.array(max_size)
+        value_size = {(max_size + (max_alignment - 1)) // max_alignment, 1_u64}.max
+        llvm_value_type = @llvm_context.int(max_alignment * 8).array(value_size)
 
         [@llvm_context.int32, llvm_value_type]
       end
@@ -109,23 +108,60 @@ module Crystal
       store type_id(@program.void), union_type_id(struct_type, union_pointer)
     end
 
-    def assign_distinct_union_types(target_pointer, target_type, value_type, value)
+    # this is needed if `union_type` and `value_type` have different alignments,
+    # i.e. their `#union_value`s do not have the same offsets
+    def store_union_in_union(union_type, union_pointer, value_type, value)
+      to_llvm_type = llvm_type(union_type)
+      from_llvm_type = llvm_type(value_type)
+      union_value_type = from_llvm_type.struct_element_types[1]
+
+      store type_id(value, value_type), union_type_id(to_llvm_type, union_pointer)
+
+      size = @llvm_typer.size_of(union_value_type)
+      size = @program.bits64? ? int64(size) : int32(size)
+      memcpy(
+        cast_to_void_pointer(union_value(to_llvm_type, union_pointer)),
+        cast_to_void_pointer(union_value(from_llvm_type, value)),
+        size,
+        align: @llvm_typer.align_of(to_llvm_type.struct_element_types[1]),
+        src_align: @llvm_typer.align_of(union_value_type),
+        volatile: int1(0),
+      )
+    end
+
+    def assign_distinct_union_types(to_pointer, to_type, from_type, from_pointer)
       # If we have:
-      # - target_pointer: Pointer(A | B | C)
-      # - target_type: A | B | C
-      # - value_type: A | B
-      # - value: Pointer(A | B)
+      # - to_pointer: Pointer(A | B | C)
+      # - to_type: A | B | C
+      # - from_type: A | B
+      # - from_pointer: Pointer(A | B)
       #
-      # Then we:
-      # - load the value, we get A | B
-      # - cast the target pointer to Pointer(A | B)
-      # - store the A | B from the first pointer into the casted target pointer
-      casted_target_pointer = cast_to_pointer target_pointer, value_type
-      store load(llvm_type(value_type), value), casted_target_pointer
+      # Then it might happen that from_type and to_type have the same alignment.
+      # In this case, the two pointers are interchangeable, so we can simply:
+      if align_of(to_type) == align_of(from_type)
+        # - load the value, we get A | B
+        # - cast the target pointer to Pointer(A | B)
+        # - store the A | B from the value pointer into the casted target pointer
+        casted_target_pointer = cast_to_pointer to_pointer, from_type
+        store load(llvm_type(from_type), from_pointer), casted_target_pointer
+      else
+        # Otherwise, the type ID and the value must be stored separately
+        store_union_in_union to_type, to_pointer, from_type, from_pointer
+      end
     end
 
     def downcast_distinct_union_types(value, to_type : MixedUnionType, from_type : MixedUnionType)
-      cast_to_pointer value, to_type
+      # If from_type and to_type have the same alignment, we don't need a
+      # separate value; just cast the larger value pointer to the smaller one
+      if align_of(to_type) == align_of(from_type)
+        cast_to_pointer value, to_type
+      else
+        # This is the same as upcasting and we need that separate, newly aligned
+        # union value
+        target_pointer = alloca llvm_type(to_type)
+        store_union_in_union to_type, target_pointer, from_type, value
+        target_pointer
+      end
     end
 
     def upcast_distinct_union_types(value, to_type : MixedUnionType, from_type : MixedUnionType)

From 3ba4291b0a0b8b7ae1b85cc0959d44d9c0a4d95b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 2 Feb 2024 14:22:54 +0100
Subject: [PATCH 092/105] Fix format for `asm` with comments (#14278)

Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
---
 spec/compiler/formatter/formatter_spec.cr | 38 +++++++++++++++++++++++
 src/compiler/crystal/tools/formatter.cr   | 19 +++++++++---
 2 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/spec/compiler/formatter/formatter_spec.cr b/spec/compiler/formatter/formatter_spec.cr
index ce2c7e72364c..df25062a0931 100644
--- a/spec/compiler/formatter/formatter_spec.cr
+++ b/spec/compiler/formatter/formatter_spec.cr
@@ -1695,6 +1695,44 @@ describe Crystal::Formatter do
   assert_format %(asm("a" : "b"(c) : "d"(e)\n        : "f",\n          "g"))
   assert_format %(asm("a" ::: "a"\n        : "volatile",\n          "intel"))
 
+  assert_format <<-CRYSTAL, <<-CRYSTAL
+    asm(
+    # foo
+    "nop"
+    # bar
+    )
+    CRYSTAL
+    asm(
+      # foo
+      "nop"
+      # bar
+    )
+    CRYSTAL
+
+  assert_format <<-CRYSTAL, <<-CRYSTAL
+    asm(
+      # the assembly template string, following the
+      # syntax for LLVM's integrated assembler
+      "nop" :               # output operands
+    "=r"(foo), "=r"(bar) : # input operands
+    "r"(1), "r"(baz) :     # names of clobbered registers
+    "eax", "memory" :      # optional flags, corresponding to the LLVM IR
+      # sideeffect / alignstack / inteldialect / unwind attributes
+    "volatile", "alignstack", "intel", "unwind"
+    )
+    CRYSTAL
+    asm(
+      # the assembly template string, following the
+      # syntax for LLVM's integrated assembler
+      "nop" :                # output operands
+      "=r"(foo), "=r"(bar) : # input operands
+      "r"(1), "r"(baz) :     # names of clobbered registers
+      "eax", "memory" :      # optional flags, corresponding to the LLVM IR
+      # sideeffect / alignstack / inteldialect / unwind attributes
+      "volatile", "alignstack", "intel", "unwind"
+    )
+    CRYSTAL
+
   assert_format "1 # foo\n1234 # bar", "1    # foo\n1234 # bar"
   assert_format "1234 # foo\n1 # bar", "1234 # foo\n1    # bar"
   assert_format "1#foo", "1 # foo"
diff --git a/src/compiler/crystal/tools/formatter.cr b/src/compiler/crystal/tools/formatter.cr
index a18634fe8232..f7ebf63be7d2 100644
--- a/src/compiler/crystal/tools/formatter.cr
+++ b/src/compiler/crystal/tools/formatter.cr
@@ -4370,6 +4370,7 @@ module Crystal
       skip_space
 
       if @token.type.newline?
+        @indent += 2
         consume_newlines
         has_newlines = true
       end
@@ -4378,7 +4379,7 @@ module Crystal
       string = StringLiteral.new(node.text)
 
       if has_newlines
-        write_indent(@indent + 2, string)
+        write_indent(@indent, string)
       else
         indent(@column, string)
       end
@@ -4386,8 +4387,8 @@ module Crystal
       skip_space
 
       if @token.type.newline?
+        consume_newlines
         if node.outputs || node.inputs
-          consume_newlines
           column += 4
           write_indent(column)
         end
@@ -4419,7 +4420,8 @@ module Crystal
           write_token :OP_COLON
           part_index += 1
         end
-        skip_space_or_newline
+        skip_space
+        consume_newlines
 
         case part_index
         when 1
@@ -4457,7 +4459,9 @@ module Crystal
       skip_space_or_newline
 
       if has_newlines
-        write_line
+        @indent -= 2
+
+        write_line unless @wrote_newline
         write_indent
       end
 
@@ -4480,7 +4484,12 @@ module Crystal
     end
 
     def visit_asm_parts(parts, colon_column, &) : Nil
-      write " "
+      if @wrote_newline
+        write_indent
+      else
+        write " "
+      end
+
       column = @column
 
       parts.each_with_index do |part, i|

From 3def4de48f34a95ccf02afede1372b0c2277a5a4 Mon Sep 17 00:00:00 2001
From: Kevin <apainintheneck@gmail.com>
Date: Fri, 2 Feb 2024 05:23:06 -0800
Subject: [PATCH 093/105] fix: `build --no-codegen` output file name error
 (#14239)

---
 src/compiler/crystal/command.cr | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/compiler/crystal/command.cr b/src/compiler/crystal/command.cr
index 178a307a54b8..b51f9405c4e6 100644
--- a/src/compiler/crystal/command.cr
+++ b/src/compiler/crystal/command.cr
@@ -372,6 +372,7 @@ class Crystal::Command
                               allowed_formats = ["text", "json"])
     compiler = new_compiler
     compiler.progress_tracker = @progress_tracker
+    compiler.no_codegen = no_codegen
     link_flags = [] of String
     filenames = [] of String
     has_stdin_filename = false
@@ -608,7 +609,7 @@ class Crystal::Command
       output_filename = "#{::Path[first_filename].stem}#{output_extension}"
 
       # Check if we'll overwrite the main source file
-      if !no_codegen && !run && first_filename == File.expand_path(output_filename)
+      if !compiler.no_codegen? && !run && first_filename == File.expand_path(output_filename)
         error "compilation will overwrite source file '#{Crystal.relative_filename(first_filename)}', either change its extension to '.cr' or specify an output file with '-o'"
       end
     end
@@ -620,7 +621,7 @@ class Crystal::Command
 
     error "maximum number of threads cannot be lower than 1" if compiler.n_threads < 1
 
-    if !no_codegen && !run && Dir.exists?(output_filename)
+    if !compiler.no_codegen? && !run && Dir.exists?(output_filename)
       error "can't use `#{output_filename}` as output filename because it's a directory"
     end
 
@@ -628,7 +629,7 @@ class Crystal::Command
       emit_base_filename = ::Path[sources.first.filename].stem
     end
 
-    combine_rpath = run && !no_codegen
+    combine_rpath = run && !compiler.no_codegen?
     @config = CompilerConfig.new compiler, sources, output_filename, emit_base_filename,
       arguments, specified_output, hierarchy_exp, cursor_location, output_format.not_nil!,
       combine_rpath, includes, excludes, verbose, check, tallies

From 54f185d0dffa48535f9975641261d5126b578964 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 3 Feb 2024 06:09:16 +0800
Subject: [PATCH 094/105] Allow calling `#[]=` with a block using method syntax
 (#14161)

---
 spec/compiler/formatter/formatter_spec.cr | 7 +++++++
 spec/compiler/parser/parser_spec.cr       | 6 +++---
 src/compiler/crystal/syntax/parser.cr     | 6 ------
 3 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/spec/compiler/formatter/formatter_spec.cr b/spec/compiler/formatter/formatter_spec.cr
index df25062a0931..bd992b78fa4a 100644
--- a/spec/compiler/formatter/formatter_spec.cr
+++ b/spec/compiler/formatter/formatter_spec.cr
@@ -1999,6 +1999,13 @@ describe Crystal::Formatter do
   assert_format "foo.[] = 1"
   assert_format "foo.[1, 2] = 3"
 
+  %w(<= == >= != []= ===).each do |operator|
+    assert_format "1.#{operator} { 3 }"
+    assert_format "1.#{operator}() { 3 }"
+    assert_format "1.#{operator}(2) { 3 }"
+    assert_format "1.#{operator} do\nend"
+  end
+
   assert_format "@foo : Int32 # comment\n\ndef foo\nend"
   assert_format "getter foo # comment\n\ndef foo\nend"
   assert_format "getter foo : Int32 # comment\n\ndef foo\nend"
diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr
index c9a28d87c33f..ea230d4e36ac 100644
--- a/spec/compiler/parser/parser_spec.cr
+++ b/spec/compiler/parser/parser_spec.cr
@@ -290,8 +290,6 @@ module Crystal
     assert_syntax_error "def foo=(*args); end", "setter method 'foo=' cannot have more than one parameter"
     assert_syntax_error "def foo=(**kwargs); end", "setter method 'foo=' cannot have more than one parameter"
     assert_syntax_error "def foo=(&block); end", "setter method 'foo=' cannot have a block"
-    assert_syntax_error "f.[]= do |a| end", "setter method '[]=' cannot be called with a block"
-    assert_syntax_error "f.[]= { |bar| }", "setter method '[]=' cannot be called with a block"
 
     # #10397
     %w(<= >= == != []= ===).each do |operator|
@@ -630,10 +628,12 @@ module Crystal
       it_parses "->Foo.#{op}(Int32)", ProcPointer.new("Foo".path, op, ["Int32".path] of ASTNode)
     end
 
-    ["bar", "+", "-", "*", "/", "<", "<=", "==", ">", ">=", "%", "|", "&", "^", "**", "===", "=~", "!~"].each do |name|
+    ["bar", "+", "-", "*", "/", "<", "<=", "==", ">", ">=", "%", "|", "&", "^", "**", "===", "=~", "!=", "[]=", "!~"].each do |name|
       it_parses "foo.#{name}", Call.new("foo".call, name)
       it_parses "foo.#{name} 1, 2", Call.new("foo".call, name, 1.int32, 2.int32)
       it_parses "foo.#{name}(1, 2)", Call.new("foo".call, name, 1.int32, 2.int32)
+      it_parses "foo.#{name}(1, 2) { 3 }", Call.new("foo".call, name, args: [1.int32, 2.int32] of ASTNode, block: Block.new(body: 3.int32))
+      it_parses "foo.#{name} do end", Call.new("foo".call, name, block: Block.new)
     end
 
     ["+", "-", "*", "/", "//", "%", "|", "&", "^", "**", "<<", ">>", "&+", "&-", "&*"].each do |op|
diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr
index 16a45eaf5e22..5d80b28ed20b 100644
--- a/src/compiler/crystal/syntax/parser.cr
+++ b/src/compiler/crystal/syntax/parser.cr
@@ -788,12 +788,6 @@ module Crystal
             end
 
             block = parse_block(block, stop_on_do: @stop_on_do)
-            if block || block_arg
-              if name == "[]="
-                raise "setter method '[]=' cannot be called with a block"
-              end
-            end
-
             atomic = Call.new atomic, name, (args || [] of ASTNode), block, block_arg, named_args
             atomic.has_parentheses = has_parentheses
             atomic.name_location = name_location

From 2bce8843d8e3d82549e675519b580ab95ae1c8f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 2 Feb 2024 23:09:35 +0100
Subject: [PATCH 095/105] Drop pinning Dwarf version 2 for android (#14243)

---
 src/compiler/crystal/codegen/debug.cr | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/src/compiler/crystal/codegen/debug.cr b/src/compiler/crystal/codegen/debug.cr
index 58d139ef2b3c..72555d074bb0 100644
--- a/src/compiler/crystal/codegen/debug.cr
+++ b/src/compiler/crystal/codegen/debug.cr
@@ -47,14 +47,6 @@ module Crystal
           "CodeView",
           mod.context.int32.const_int(1)
         )
-      elsif @program.has_flag?("osx") || @program.has_flag?("android")
-        # DebugInfo generation in LLVM by default uses a higher version of dwarf
-        # than OS X currently understands. Android has the same problem.
-        mod.add_flag(
-          LibLLVM::ModuleFlagBehavior::Warning,
-          "Dwarf Version",
-          mod.context.int32.const_int(2)
-        )
       end
 
       mod.add_flag(

From 592051e89ff95211f584c9619dc7104ad77e6ffb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 2 Feb 2024 23:09:47 +0100
Subject: [PATCH 096/105] [CI] Upgrade `resource_class` for `test_preview_mt`
 (#14274)

---
 .circleci/config.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 2eef408ee4ad..8c07a1005b70 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -116,6 +116,7 @@ jobs:
   test_preview_mt:
     machine:
       image: ubuntu-2004:202201-02
+    resource_class: large
     environment:
       <<: *env
       TRAVIS_OS_NAME: linux

From c67883c060dbb44b8b7365a2d028a0eb21636429 Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Mon, 5 Feb 2024 05:16:12 +0800
Subject: [PATCH 097/105] Support LLVM 18.1 (#14277)

---
 .github/workflows/win.yml      | 27 +++++----------------------
 etc/win-ci/build-llvm.ps1      |  2 +-
 src/llvm/ext/llvm-versions.txt |  2 +-
 src/llvm/lib_llvm.cr           |  2 +-
 4 files changed, 8 insertions(+), 25 deletions(-)

diff --git a/.github/workflows/win.yml b/.github/workflows/win.yml
index 9fce9f93aa44..3ef4cccb8739 100644
--- a/.github/workflows/win.yml
+++ b/.github/workflows/win.yml
@@ -7,7 +7,7 @@ concurrency:
   cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
 
 env:
-  CI_LLVM_VERSION: "17.0.2"
+  CI_LLVM_VERSION: "18.1.0-rc1"
 
 jobs:
   x86_64-windows-libs:
@@ -177,30 +177,13 @@ jobs:
           path: llvm
           key: llvm-libs-${{ env.CI_LLVM_VERSION }}-msvc
 
-      - name: Download LLVM
-        if: steps.cache-llvm-libs.outputs.cache-hit != 'true'
-        run: |
-          iwr https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ env.CI_LLVM_VERSION }}/llvm-${{ env.CI_LLVM_VERSION }}.src.tar.xz -OutFile llvm.tar.xz
-          (Get-FileHash -Algorithm SHA256 .\llvm.tar.xz).hash -eq "D820E63BC3A6F4F833EC69A1EF49A2E81992E90BC23989F98946914B061AB6C7"
-          7z x llvm.tar.xz
-          7z x llvm.tar
-          mv llvm-* llvm-src
-
-      - name: Download LLVM's CMake files
-        if: steps.cache-llvm-libs.outputs.cache-hit != 'true'
-        run: |
-          iwr https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ env.CI_LLVM_VERSION }}/cmake-${{ env.CI_LLVM_VERSION }}.src.tar.xz -OutFile cmake.tar.xz
-          (Get-FileHash -Algorithm SHA256 .\cmake.tar.xz).hash -eq "B6D83C91F12757030D8361DEDC5DD84357B3EDB8DA406B5D0850DF8B6F7798B1"
-          7z x cmake.tar.xz
-          7z x cmake.tar
-          mv cmake-* cmake
-
       - name: Build LLVM
         if: steps.cache-llvm-libs.outputs.cache-hit != 'true'
         run: |
+          git clone --config core.autocrlf=false -b llvmorg-${{ env.CI_LLVM_VERSION }} --depth 1 https://github.com/llvm/llvm-project.git
           mkdir llvm-build
           cd llvm-build
-          cmake ..\llvm-src -Thost=x64 -DLLVM_TARGETS_TO_BUILD="X86;AArch64" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DBUILD_SHARED_LIBS=OFF -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_ZSTD=OFF
+          cmake ..\llvm-project\llvm -Thost=x64 -DLLVM_TARGETS_TO_BUILD="X86;AArch64" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DBUILD_SHARED_LIBS=OFF -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_ZSTD=OFF
           cmake --build . --config Release
           cmake "-DCMAKE_INSTALL_PREFIX=$(pwd)\..\llvm" -P cmake_install.cmake
 
@@ -235,7 +218,7 @@ jobs:
     uses: ./.github/workflows/win_build_portable.yml
     with:
       release: false
-      llvm_version: "17.0.2"
+      llvm_version: "18.1.0-rc1"
 
   x86_64-windows-test:
     runs-on: windows-2022
@@ -288,7 +271,7 @@ jobs:
     uses: ./.github/workflows/win_build_portable.yml
     with:
       release: true
-      llvm_version: "17.0.2"
+      llvm_version: "18.1.0-rc1"
 
   x86_64-windows-installer:
     if: github.repository_owner == 'crystal-lang' && (startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/heads/ci/'))
diff --git a/etc/win-ci/build-llvm.ps1 b/etc/win-ci/build-llvm.ps1
index b544e9eba784..9335cfe9abe4 100644
--- a/etc/win-ci/build-llvm.ps1
+++ b/etc/win-ci/build-llvm.ps1
@@ -16,7 +16,7 @@ if (-not $Dynamic) {
 Setup-Git -Path $BuildTree -Url https://github.com/llvm/llvm-project.git -Ref llvmorg-$Version
 
 Run-InDirectory $BuildTree\build {
-    $args = "-Thost=x64 -DLLVM_TARGETS_TO_BUILD=""$($TargetsToBuild -join ';')"" -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_ZSTD=OFF"
+    $args = "-Thost=x64 -DLLVM_TARGETS_TO_BUILD=$($TargetsToBuild -join ';') -DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_ZSTD=OFF"
     if ($Dynamic) {
         $args = "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL $args"
     } else {
diff --git a/src/llvm/ext/llvm-versions.txt b/src/llvm/ext/llvm-versions.txt
index 7c8773c02212..92ae5ecbaa5a 100644
--- a/src/llvm/ext/llvm-versions.txt
+++ b/src/llvm/ext/llvm-versions.txt
@@ -1 +1 @@
-17.0 16.0 15.0 14.0 13.0 12.0 11.1 11.0 10.0 9.0 8.0
+18.1 17.0 16.0 15.0 14.0 13.0 12.0 11.1 11.0 10.0 9.0 8.0
diff --git a/src/llvm/lib_llvm.cr b/src/llvm/lib_llvm.cr
index d5e7c2488002..b68e212d2052 100644
--- a/src/llvm/lib_llvm.cr
+++ b/src/llvm/lib_llvm.cr
@@ -35,7 +35,7 @@
 
   @[Link(ldflags: {{ llvm_ldflags }})]
   lib LibLLVM
-    VERSION = {{ llvm_version.strip.gsub(/git/, "") }}
+    VERSION = {{ llvm_version.strip.gsub(/git/, "").gsub(/rc.*/, "") }}
     BUILT_TARGETS = {{ llvm_targets.strip.downcase.split(' ').map(&.id.symbolize) }}
   end
 {% end %}

From 9b7850b4582fe51693c4bd77bcbd33d291534d94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Tue, 6 Feb 2024 10:19:12 +0100
Subject: [PATCH 098/105] [CI] Upgrade from old machine images approaching EOL
 (#14275)

---
 .circleci/config.yml | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 8c07a1005b70..fe4e6dabaffd 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -39,7 +39,7 @@ defaults:
 jobs:
   test_linux:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     environment:
       <<: *env
       TRAVIS_OS_NAME: linux
@@ -70,7 +70,7 @@ jobs:
 
   test_alpine:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     environment:
       <<: *env
       TRAVIS_OS_NAME: linux
@@ -115,7 +115,7 @@ jobs:
 
   test_preview_mt:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     resource_class: large
     environment:
       <<: *env
@@ -264,7 +264,7 @@ jobs:
 
   dist_linux:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     steps:
       - attach_workspace:
           at: /tmp/workspace
@@ -347,7 +347,7 @@ jobs:
 
   dist_docker:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     steps:
       - attach_workspace:
           at: /tmp/workspace
@@ -363,7 +363,7 @@ jobs:
 
   publish_docker:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     steps:
       - attach_workspace:
           at: /tmp/workspace
@@ -418,7 +418,7 @@ jobs:
 
   dist_docs:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     steps:
       - attach_workspace:
           at: /tmp/workspace
@@ -464,7 +464,7 @@ jobs:
 
   test_dist_linux_on_docker:
     machine:
-      image: ubuntu-2004:202201-02
+      image: default
     environment:
       <<: *env
       TRAVIS_OS_NAME: linux

From b6fc5d5d5f7d9aca34ab459ce9aa71cfc2f8796a Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Thu, 8 Feb 2024 08:01:19 +0800
Subject: [PATCH 099/105] Relax `delegate`'s setter detection (#14282)

---
 spec/std/object_spec.cr | 36 +++++++++++++++++++++++++++++++++++-
 src/object.cr           | 41 +++++++++++++++++++++++++++++++----------
 2 files changed, 66 insertions(+), 11 deletions(-)

diff --git a/spec/std/object_spec.cr b/spec/std/object_spec.cr
index 3df134513ae2..43d1c009a19e 100644
--- a/spec/std/object_spec.cr
+++ b/spec/std/object_spec.cr
@@ -11,6 +11,8 @@ private class StringWrapper
   end
 end
 
+private EQ_OPERATORS = %w(<= >= == != []= ===)
+
 private class TestObject
   getter getter1
   getter getter2 : Int32
@@ -113,6 +115,19 @@ private class TestObject
     {key, value}
   end
 
+  # NOTE: these methods are a syntax error in older versions
+  {% if compare_versions(Crystal::VERSION, "1.12.0-dev") >= 0 %}
+    {% for op in EQ_OPERATORS %}
+      def {{ op.id }}(*args, **opts)
+        [args, opts]
+      end
+
+      def {{ op.id }}(*args, **opts, &)
+        [args, opts, yield]
+      end
+    {% end %}
+  {% end %}
+
   annotation TestAnnotation
   end
 
@@ -130,7 +145,10 @@ end
 
 private class DelegatedTestObject
   delegate :property1=, to: @test_object
-  delegate :[]=, to: @test_object
+
+  {% for op in EQ_OPERATORS %}
+    delegate {{ op.id.symbolize }}, to: @test_object
+  {% end %}
 
   def initialize(@test_object : TestObject)
   end
@@ -206,6 +224,22 @@ describe Object do
       delegated = DelegatedTestObject.new(test_object)
       (delegated["foo"] = "bar").should eq({"foo", "bar"})
     end
+
+    {% if compare_versions(Crystal::VERSION, "1.12.0-dev") >= 0 %}
+      {% for op in EQ_OPERATORS %}
+        it "forwards \#{{ op.id }} with multiple parameters" do
+          test_object = TestObject.new
+          delegated = DelegatedTestObject.new(test_object)
+          delegated.{{ op.id }}(1, 2, a: 3, b: 4).should eq [{1, 2}, {a: 3, b: 4}]
+        end
+
+        it "forwards \#{{ op.id }} with multiple parameters and block parameter" do
+          test_object = TestObject.new
+          delegated = DelegatedTestObject.new(test_object)
+          delegated.{{ op.id }}(1, 2, a: 3, b: 4) { 5 }.should eq [{1, 2}, {a: 3, b: 4}, 5]
+        end
+      {% end %}
+    {% end %}
   end
 
   describe "getter" do
diff --git a/src/object.cr b/src/object.cr
index 6687e19f424a..ba818ac2979e 100644
--- a/src/object.cr
+++ b/src/object.cr
@@ -1293,17 +1293,18 @@ class Object
   # wrapper.capitalize     # => "Hello"
   # ```
   macro delegate(*methods, to object)
-    {% for method in methods %}
-      {% if method.id.ends_with?('=') && method.id != "[]=" %}
-        def {{method.id}}(arg)
-          {{object.id}}.{{method.id}} arg
-        end
-      {% else %}
-        def {{method.id}}(*args, **options)
-          {{object.id}}.{{method.id}}(*args, **options)
-        end
+    {% if compare_versions(Crystal::VERSION, "1.12.0-dev") >= 0 %}
+      {% eq_operators = %w(<= >= == != []= ===) %}
+      {% for method in methods %}
+        {% if method.id.ends_with?('=') && !eq_operators.includes?(method.id.stringify) %}
+          def {{method.id}}(arg)
+            {{object.id}}.{{method.id}} arg
+          end
+        {% else %}
+          def {{method.id}}(*args, **options)
+            {{object.id}}.{{method.id}}(*args, **options)
+          end
 
-        {% if method.id != "[]=" %}
           def {{method.id}}(*args, **options)
             {{object.id}}.{{method.id}}(*args, **options) do |*yield_args|
               yield *yield_args
@@ -1311,6 +1312,26 @@ class Object
           end
         {% end %}
       {% end %}
+    {% else %}
+      {% for method in methods %}
+        {% if method.id.ends_with?('=') && method.id != "[]=" %}
+          def {{method.id}}(arg)
+            {{object.id}}.{{method.id}} arg
+          end
+        {% else %}
+          def {{method.id}}(*args, **options)
+            {{object.id}}.{{method.id}}(*args, **options)
+          end
+
+          {% if method.id != "[]=" %}
+            def {{method.id}}(*args, **options)
+              {{object.id}}.{{method.id}}(*args, **options) do |*yield_args|
+                yield *yield_args
+              end
+            end
+          {% end %}
+        {% end %}
+      {% end %}
     {% end %}
   end
 

From 1d9042b6853eed540bd89f60254a16c689e5375c Mon Sep 17 00:00:00 2001
From: Quinton Miller <nicetas.c@gmail.com>
Date: Sat, 10 Feb 2024 01:11:40 +0800
Subject: [PATCH 100/105] Fix stack corruption in union-to-union casts (#14289)

---
 spec/compiler/codegen/cast_spec.cr     | 35 ++++++++++++++++++++++++++
 src/compiler/crystal/codegen/unions.cr | 12 ++++++---
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/spec/compiler/codegen/cast_spec.cr b/spec/compiler/codegen/cast_spec.cr
index fbe6cd78ac87..dd6653f036c9 100644
--- a/spec/compiler/codegen/cast_spec.cr
+++ b/spec/compiler/codegen/cast_spec.cr
@@ -104,6 +104,41 @@ describe "Code gen: cast" do
       CRYSTAL
   end
 
+  it "doesn't corrupt stack when downcasting union to union with different alignment (#14285)" do
+    run(<<-CRYSTAL).to_b.should be_true
+      struct Time2
+        def initialize(@seconds : Int64)
+          @nanoseconds = uninitialized UInt32[3]
+        end
+
+        def <(other : Time2) : Bool
+          @seconds < other.@seconds
+        end
+      end
+
+      class Constraints::Range
+        def initialize(@min : Int128 | Time2 | Nil)
+        end
+      end
+
+      def validate(value : Time2, constraint) : Bool
+        min = constraint.@min
+        if min.is_a?(Time2?)
+          if min
+            if value < min
+              return false
+            end
+          end
+        end
+        true
+      end
+
+      value = Time2.new(123)
+      constraint = Constraints::Range.new(Time2.new(45))
+      validate(value, constraint)
+      CRYSTAL
+  end
+
   it "casts from virtual to single type" do
     run(%(
       require "prelude"
diff --git a/src/compiler/crystal/codegen/unions.cr b/src/compiler/crystal/codegen/unions.cr
index 7ac58ff84887..bcef273a8010 100644
--- a/src/compiler/crystal/codegen/unions.cr
+++ b/src/compiler/crystal/codegen/unions.cr
@@ -113,18 +113,22 @@ module Crystal
     def store_union_in_union(union_type, union_pointer, value_type, value)
       to_llvm_type = llvm_type(union_type)
       from_llvm_type = llvm_type(value_type)
-      union_value_type = from_llvm_type.struct_element_types[1]
+      to_value_type = to_llvm_type.struct_element_types[1]
+      from_value_type = from_llvm_type.struct_element_types[1]
 
       store type_id(value, value_type), union_type_id(to_llvm_type, union_pointer)
 
-      size = @llvm_typer.size_of(union_value_type)
+      size = {
+        @llvm_typer.size_of(from_value_type),
+        @llvm_typer.size_of(to_value_type),
+      }.min
       size = @program.bits64? ? int64(size) : int32(size)
       memcpy(
         cast_to_void_pointer(union_value(to_llvm_type, union_pointer)),
         cast_to_void_pointer(union_value(from_llvm_type, value)),
         size,
-        align: @llvm_typer.align_of(to_llvm_type.struct_element_types[1]),
-        src_align: @llvm_typer.align_of(union_value_type),
+        align: @llvm_typer.align_of(to_value_type),
+        src_align: @llvm_typer.align_of(from_value_type),
         volatile: int1(0),
       )
     end

From 01bf92147a08073343981316493cb097d034eb78 Mon Sep 17 00:00:00 2001
From: Julien Portalier <julien@portalier.com>
Date: Fri, 9 Feb 2024 18:11:49 +0100
Subject: [PATCH 101/105] Fix: don't run thread specs with the interpreter
 (#14287)

---
 spec/interpreter_std_spec.cr | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/spec/interpreter_std_spec.cr b/spec/interpreter_std_spec.cr
index 8638b0a83f7f..79b8bab3edbc 100644
--- a/spec/interpreter_std_spec.cr
+++ b/spec/interpreter_std_spec.cr
@@ -235,9 +235,9 @@ require "./std/system_error_spec.cr"
 require "./std/system/group_spec.cr"
 # require "./std/system_spec.cr" (failed to run)
 require "./std/system/user_spec.cr"
-require "./std/thread/condition_variable_spec.cr"
-require "./std/thread/mutex_spec.cr"
-# require "./std/thread_spec.cr" (failed to run)
+# require "./std/thread/condition_variable_spec.cr" (interpreter must support threads)
+# require "./std/thread/mutex_spec.cr" (interpreter must support threads)
+# require "./std/thread_spec.cr" (interpreter must support threads)
 require "./std/time/custom_formats_spec.cr"
 require "./std/time/format_spec.cr"
 require "./std/time/location_spec.cr"

From 8d3722ca98ab86f7740be24da3639fa5beefc03a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 9 Feb 2024 18:12:02 +0100
Subject: [PATCH 102/105] Mention RFC process in contribution instructions
 (#14291)

---
 .github/ISSUE_TEMPLATE/feature-request.md | 4 ++++
 CONTRIBUTING.md                           | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
index 756c4cfd2816..e6665a621eaa 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -10,3 +10,7 @@ labels: kind:feature
 - Describe the feature you would like, optionally illustrated by examples, and how it will solve the above problem.
 - Describe considered alternative solutions, and the reasons why you have not proposed them as a solution here.
 - Does it break backward compatibility, if yes then what's the migration path?
+
+In case this proposal includes a substantial change to the language, we ask you to go through an [RFC process](https://github.com/crystal-lang/rfcs).
+
+The best place to start an open discussion about potential changes is the [Crystal forum](https://forum.crystal-lang.org/c/crystal-contrib/6).
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 77ad67860f4b..640c980909ee 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -15,6 +15,10 @@ there's no more room for discussion. We'll anyway close the issue after some day
 
 If something is missing from the language it might be that it's not yet implemented or that it was purposely left out. If in doubt, just ask.
 
+Substantial changes go through an [RFC process](https://github.com/crystal-lang/rfcs).
+
+The best place to start an open discussion about potential changes is the [Crystal forum](https://forum.crystal-lang.org/c/crystal-contrib/6).
+
 ### What's needed right now
 
 You can find a list of tasks that we consider suitable for a first time contribution at

From a3e8d12f5af17ddbf45aeb0a59c818541fe4dd78 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Fri, 9 Feb 2024 18:14:15 +0100
Subject: [PATCH 103/105] Drop Nikola sponsor mention from Readme (#14290)

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 70577b822fdc..19d8e09ee853 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ Project Status
 
 Within a major version, language features won't be removed or changed in any way that could prevent a Crystal program written with that version from compiling and working. The built-in standard library might be enriched, but it will always be done with backwards compatibility in mind.
 
-Development of the Crystal language is possible thanks to the community's effort and the continued support of [84codes](https://www.84codes.com/), [Nikola Motor Company](https://nikolamotor.com/) and every other [sponsor](https://crystal-lang.org/sponsors).
+Development of the Crystal language is possible thanks to the community's effort and the continued support of [84codes](https://www.84codes.com/) and every other [sponsor](https://crystal-lang.org/sponsors).
 
 Installing
 ----------

From db67d71341f54d11933a33b667e141819c2af33a Mon Sep 17 00:00:00 2001
From: Jamie Gaskins <jgaskins@hey.com>
Date: Sat, 10 Feb 2024 06:22:35 -0600
Subject: [PATCH 104/105] Add memory barrier to `Mutex#unlock` on aarch64
 (#14272)

---
 src/mutex.cr | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/mutex.cr b/src/mutex.cr
index 6bdd9a98fd25..83dd4bb53429 100644
--- a/src/mutex.cr
+++ b/src/mutex.cr
@@ -107,6 +107,9 @@ class Mutex
       @mutex_fiber = nil
     end
 
+    {% if flag?(:aarch64) %}
+      Atomic::Ops.fence :sequentially_consistent, false
+    {% end %}
     @state.lazy_set(0)
 
     if @queue_count.get == 0

From c0270c60a685760af2b756dd65921346e172be81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20M=C3=BCller?= <straightshoota@gmail.com>
Date: Sat, 10 Feb 2024 13:22:49 +0100
Subject: [PATCH 105/105] Enhance changelog script to pull milestone info from
 GitHub (#14230)

---
 scripts/github-changelog.cr | 47 +++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 10 deletions(-)

diff --git a/scripts/github-changelog.cr b/scripts/github-changelog.cr
index 7397440c3676..f2d277f258e7 100755
--- a/scripts/github-changelog.cr
+++ b/scripts/github-changelog.cr
@@ -31,6 +31,10 @@ def query_prs(api_token, repository, milestone)
       repository(owner: $owner, name: $repository) {
         milestones(query: $milestone, first: 1) {
           nodes {
+            closedAt
+            description
+            dueOn
+            title
             pullRequests(first: 300) {
               nodes {
                 number
@@ -81,6 +85,28 @@ module LabelNameConverter
   end
 end
 
+record Milestone,
+  closed_at : Time?,
+  description : String,
+  due_on : Time?,
+  title : String,
+  pull_requests : Array(PullRequest) do
+  include JSON::Serializable
+
+  @[JSON::Field(key: "dueOn")]
+  @due_on : Time?
+
+  @[JSON::Field(key: "closedAt")]
+  @closed_at : Time?
+
+  @[JSON::Field(key: "pullRequests", root: "nodes")]
+  @pull_requests : Array(PullRequest)
+
+  def release_date
+    closed_at || due_on
+  end
+end
+
 record PullRequest,
   number : Int32,
   title : String,
@@ -245,24 +271,20 @@ end
 
 response = query_prs(api_token, repository, milestone)
 parser = JSON::PullParser.new(response.body)
-array = parser.on_key! "data" do
+milestone = parser.on_key! "data" do
   parser.on_key! "repository" do
     parser.on_key! "milestones" do
       parser.on_key! "nodes" do
         parser.read_begin_array
-        a = parser.on_key! "pullRequests" do
-          parser.on_key! "nodes" do
-            Array(PullRequest).new(parser)
-          end
-        end
+        milestone = Milestone.new(parser)
         parser.read_end_array
-        a
+        milestone
       end
     end
   end
 end
 
-sections = array.group_by(&.section)
+sections = milestone.pull_requests.group_by(&.section)
 
 SECTION_TITLES = {
   "breaking"    => "Breaking changes",
@@ -279,9 +301,14 @@ SECTION_TITLES = {
 
 TOPIC_ORDER = %w[lang stdlib compiler tools other]
 
-puts "## [#{milestone}] (#{Time.local.to_s("%F")})"
+puts "## [#{milestone.title}] (#{milestone.release_date.try(&.to_s("%F")) || "unreleased"})"
+if description = milestone.description.presence
+  puts
+  print "_", description
+  puts "_"
+end
 puts
-puts "[#{milestone}]: https://github.com/crystal-lang/crystal/releases/#{milestone}"
+puts "[#{milestone.title}]: https://github.com/crystal-lang/crystal/releases/#{milestone.title}"
 puts
 
 SECTION_TITLES.each do |id, title|