Rust 1.97 zapnul nové kódování symbolů, backtrace konečně dává smysl
Vydání Rustu 1.97 z 9. července přepnulo výchozí kódování symbolů na schéma v0. Výpisy zásobníku i profilery díky tomu ukážou, s jakými konkrétními typy byla obecná funkce zavolaná, místo aby to schovaly za hash. Zmizelo i tiché polykání hlášek linkeru.

Rust 1.97 vyšel 9. července a na první pohled je to nezajímavé vydání: pár nových metod na celých číslech, drobnost v Cargu. Jenže obsahuje jednu změnu, kterou pozná každý, kdo někdy ladil pád aplikace v uvolněném sestavení. Kompilátor od této verze používá jako výchozí kódování symbolů schéma v0.
Co je kódování symbolů a proč na něm záleží
Když překladač vyrobí binárku, musí každou funkci pojmenovat jedním řetězcem v tabulce symbolů. To jméno smí obsahovat jen omezenou sadu znaků, takže se cesta k funkci i její typové parametry zakódují do jednoho slova. Tomu se říká mangling, tedy zkomolení jména.
Podle tohoto jména se pak orientuje ladicí program, profiler i výpis zásobníku po pádu. Když je kódování špatné, ladicí nástroje zobrazí místo funkce jen shluk znaků a vývojář hádá.
Rust do teď používal starší schéma, které si s obecným kódem neporadilo. Pokud jste měli funkci s typovým parametrem a zavolali ji pro deset různých typů, vzniklo deset různých funkcí, jenže jejich konkrétní typy se do jména nedostaly. Nahradil je hash. Ve výpisu jste tedy viděli, že spadla nějaká varianta obecné funkce, ale ne která.
Co dělá v0 jinak
Schéma v0 vzniklo podle návrhu RFC 2603 a jeho hlavní vlastnost je obousměrnost. Kódování je navržené tak, aby z výsledného jména šlo zpětně přečíst, co v něm bylo, včetně typových parametrů. Oznámení k vydání to shrnuje jednou větou: dosazení obecných parametrů si zachovává své hodnoty, místo aby bylo sledované jen za hashem.
Kromě typů umí v0 zakódovat i životnosti, konstantní generické parametry, meze s vyšším řádem, uzávěry a další konstrukce, na které starší schéma nemyslelo. Jména používají jen znaky A–Z, a–z, 0–9 a podtržítko, takže projdou beze změny každým linkerem. Aby přitom nebyla nekonečně dlouhá, používá formát zpětné odkazy na už zakódované části.
Ukázkový symbol ve formátu v0 vypadá takto:
_RNvMsr_NtCs3ssYzQotkvD_3std4pathNtB5_7PathBuf3newCs15kBYyAo9fc_7mycrate
Po rozkódování je z něj čitelné <std::path::PathBuf>::new.
Samotné schéma není novinka. Zapnout se dalo ručně přepínačem od verze 1.59, tedy od února 2022. Novinkou je, že se čtyři a půl roku poté stalo výchozím.
Na co si dát pozor
Dokumentace kompilátoru na dvou místech mírní očekávání. Zaprvé: v0 není stabilní binární rozhraní Rustu. Je definované natolik, aby z něj šlo vyrobit čitelný tvar, ne aby se na jeho podobu daly vázat cizí nástroje.
Zadruhé: neexistuje jediný předepsaný způsob, jak symbol zobrazit. Dokumentace doporučuje oddělovat cesty dvojtečkami, psát implementace vlastností jako <Typ as Vlastnost> a uzávěry jako {closure#N}, ale je to doporučení, ne norma. Dva profilery tedy mohou tentýž symbol vypsat jinak.
Nástroje, které rozkódování zvládají, mají podle dokumentace při setkání s neznámou značkou raději vypsat původní zkomolené jméno než spadnout. Kdo používá starší verzi ladicího programu nebo vlastní nástroj nad tabulkou symbolů, měl by po přechodu na 1.97 zkontrolovat, že to skutečně dělá.
Zbytek vydání
Druhá praktická změna se týká linkeru. Jeho hlášky se dosud zahazovaly; nově se zobrazují jako varování pod kontrolou lintu linker_messages. Potíže s linkováním se tak nebudou projevovat až záhadným chováním výsledné binárky.
Cargo umí nově řídit chování varování přes proměnnou prostředí CARGO_BUILD_WARNINGS s hodnotami allow, warn a deny. Podstatné je, že změna této hodnoty neshodí vyrovnávací paměť sestavení, takže přepnutí na deny v průběžné integraci nestojí celý překlad znovu.
Ze standardní knihovny přibyly metody pro práci s bity celých čísel: isolate_highest_one, isolate_lowest_one, highest_one, lowest_one a u typů bez znaménka bit_width. Stejná sada je i na typech NonZero. Metoda char::is_control je nově použitelná v konstantním kontextu.
O týden později, 16. července, vyšla opravná verze 1.97.1.
Zdroje: oznámení vydání na blogu projektu Rust a kapitola o kódování v0 v příručce kompilátoru.