v0 符号格式

v0 符号修饰格式在 RFC 2603 中引入。它具有以下属性

  • 它为所有可能最终出现在二进制文件的符号表中的内容提供了明确的字符串编码。
  • 它以可逆的方式编码有关泛型参数的信息。
  • 修饰后的符号是可解码的,使得反修饰后的形式应易于识别为例如多态函数的某个具体实例。
  • 它具有一致的定义,不依赖于对某些语言结构的漂亮打印。
  • 符号可以被限制为仅由字符 A-Za-z0-9_ 组成。这有助于确保它是平台无关的,因为其他字符在某些上下文中可能具有特殊含义(例如,MSVC DEF 文件中的 .)。可选支持 Unicode 符号。
  • 它力求保持高效,避免不必要的长名称,并避免计算成本高的反修饰操作。

v0 格式不打算与其他修饰方案(如 C++)兼容。

v0 格式不作为 Rust 的稳定 ABI 呈现。此格式目前旨在足够明确,以使反修饰器可以生成符号的合理人类可读形式。存在几个实现定义的 部分,导致无法完全预测给定 Rust 实体将如何编码。

以下部分定义了 v0 符号的编码。符号没有标准化的反修饰形式,尽管提供了有关如何反修饰符号的建议。实现者可以选择以不同的方式进行反修饰。

扩展

将来可能会扩展此格式以添加新标签,因为 Rust 会扩展为新的语言项。为了实现向前兼容性,反修饰器应优雅地处理符号,这些符号的编码中遇到了本文档中未描述的标签字符。例如,他们可以回退到显示修饰后的符号。该格式可以扩展到存在标签字符的任何位置,例如类型规则。现有标签和编码的含义不会更改。

语法表示法

编码符号的格式以扩展的类 BNF 语法中的上下文无关文法表示。可以在符号语法总结中找到统一的摘要。

名称语法示例描述
规则A → B C一个产生式。
串联空格A → B C D按从左到右的顺序排列的单个元素。
备选方案|A → B | C匹配其中一个或另一个。
分组()A → B (C | D) E将多个元素分组为一个。
重复{}A → {B}重复封闭的零次或多次。
选项可选A → B可选 C一个可选元素。
字面量等宽字体A → G区分大小写的匹配确切字符的终端。

符号名称

symbol-name → _R 十进制数可选 路径 实例化箱可选 特定于供应商的后缀可选

修饰的符号以两个字符 _R 开头,这是一个前缀,用于将符号标识为 Rust 符号。该前缀可以选择后跟一个十进制数,该数字指定编码版本。此数字当前未使用,并且在当前编码中永远不会出现。紧随其后的是一个 路径,它对实体的路径进行编码。路径后跟一个可选的 实例化箱,它有助于消除可能在单独的箱中多次实例化的实体的歧义。最后一部分是可选的 特定于供应商的后缀

推荐的反修饰

一个 symbol-name 应显示为 路径。通常不需要显示 实例化箱特定于供应商的后缀

示例

std::path::PathBuf::new();

mycratePathBuf::new 的符号是

_RNvMsr_NtCs3ssYzQotkvD_3std4pathNtB5_7PathBuf3newCs15kBYyAo9fc_7mycrate
├┘└───────────────────────┬──────────────────────┘└──────────┬─────────┘
│                         │                                  │
│                         │                                  └── instantiating-crate path "mycrate"
│                         └───────────────────────────────────── path to std::path::PathBuf::new
└─────────────────────────────────────────────────────────────── `_R` symbol prefix

推荐的反修饰:<std::path::PathBuf>::new

符号路径

path →
      箱根
   | 固有实现
   | 特征实现
   | 特征定义
   | 嵌套路径
   | 泛型参数
   | 反向引用

一个 path 表示某个实体的 Rust 路径 的变体。除了使用标识符的典型 Rust 路径段之外,它还使用额外的元素来表示不可命名实体(如 impl)或单态化项的泛型参数。

初始标签字符可用于确定它表示哪种路径

标签规则描述
C箱根箱路径的根。
M固有实现一个固有实现。
X特征实现一个特征实现。
Y特征定义一个特征定义。
N嵌套路径一个嵌套路径。
I泛型参数泛型参数。
B反向引用一个反向引用。

路径:箱根

crate-root → C 标识符

一个 crate-root 指示引用箱的模块树根的路径。它由字符 C 后跟箱名称作为 标识符 组成。

箱名称是从定义箱中看到的名称。由于 Rust 支持链接多个名称相同的箱,因此使用歧义消除器来使名称在整个箱图中是唯一的。

推荐的反修饰

一个 crate-root 可以显示为标识符,例如 mycrate

通常不需要显示标识符中的歧义消除器,但是作为替代形式,歧义消除器可以用十六进制显示,例如 mycrate[ca63f166dbe9294]

示例

fn example() {}

mycrateexample 的符号是

_RNvCs15kBYyAo9fc_7mycrate7example
    │└────┬─────┘││└──┬──┘
    │     │      ││   │
    │     │      ││   └── crate-root identifier "mycrate"
    │     │      │└────── length 7 of "mycrate"
    │     │      └─────── end of base-62-number
    │     └────────────── disambiguator for crate-root "mycrate" 0xca63f166dbe9293 + 1
    └──────────────────── crate-root

推荐的反修饰:mycrate::example

注意:编译器可能会重用 crate-root 形式来表示任意未作用域、未消除歧义的标识符,例如用于尚未添加到语法中的新基本类型。为此,它将发出一个没有显式歧义消除器的 crate-root,依赖于这种未消除歧义的箱名称实际上不会发生的事实。例如,基本类型 f128 将编码为 C4f128。为了达到预期的效果,反修饰器应永远不渲染箱根的零歧义消除器。也就是说,C4f128 应该显示为 f128 而不是 f128[0]

路径:固有实现

inherent-impl → M 实现路径 类型

一个 inherent-impl 指示指向固有实现的路径。它由字符 M 后跟一个 实现路径 组成,该路径唯一标识定义该项的 impl 块。紧随其后的是一个 类型,表示 impl 的 Self 类型。

推荐的反修饰

一个 inherent-impl 可以显示为尖括号内 类型 的限定路径段。通常不需要显示 实现路径

示例

struct Example;
impl Example {
    fn foo() {}
}

Example 的 impl 中的 foo 的符号是

_RNvMs_Cs4Cv8Wi1oAIB_7mycrateNtB4_7Example3foo
    │├┘└─────────┬──────────┘└────┬──────┘
    ││           │                │
    ││           │                └── Self type "Example"
    ││           └─────────────────── path to the impl's parent "mycrate"
    │└─────────────────────────────── disambiguator 1
    └──────────────────────────────── inherent-impl

推荐的反修饰:<mycrate::Example>::foo

路径:特征实现

trait-impl → X 实现路径 类型 路径

一个 trait-impl 指示指向特征实现的路径。它由字符 X 后跟一个指向 impl 父级的 实现路径,后跟一个表示 impl 的 Self 类型的 类型,后跟一个指向该特征的 路径 组成。

推荐的反修饰

一个 trait-impl 可以使用 < type as path > 语法显示为限定路径段。通常不需要显示 实现路径

示例

struct Example;
trait Trait {
    fn foo();
}
impl Trait for Example {
    fn foo() {}
}

Example 的特征 impl 中的 foo 的符号是

_RNvXCs15kBYyAo9fc_7mycrateNtB2_7ExampleNtB2_5Trait3foo
    │└─────────┬──────────┘└─────┬─────┘└────┬────┘
    │          │                 │           │
    │          │                 │           └── path to the trait "Trait"
    │          │                 └────────────── Self type "Example"
    │          └──────────────────────────────── path to the impl's parent "mycrate"
    └─────────────────────────────────────────── trait-impl

推荐的反修饰:<mycrate::Example as mycrate::Trait>::foo

路径:Impl

impl-path → 歧义消除器可选 路径

一个 impl-path 是用于 固有实现特征实现 的路径,用于指示指向实现父级的路径。它由一个可选的 歧义消除器 后跟一个 路径 组成。路径是指向包含 impl 的父级的路径。歧义消除器可用于区分同一父级内的多个 impl。

推荐的反修饰

通常不需要显示 impl-path(除非需要 impl 的位置)。

示例

struct Example;
impl Example {
    fn foo() {}
}
impl Example {
    fn bar() {}
}

Example 的 impl 中的 foo 的符号是

_RNvMCs7qp2U7fqm6G_7mycrateNtB2_7Example3foo
     └─────────┬──────────┘
               │
               └── path to the impl's parent crate-root "mycrate"

bar 的符号类似,但它有一个歧义消除器来表示它在不同的 impl 块中。

_RNvMs_Cs7qp2U7fqm6G_7mycrateNtB4_7Example3bar
     ├┘└─────────┬──────────┘
     │           │
     │           └── path to the impl's parent crate-root "mycrate"
     └────────────── disambiguator 1

推荐的反修饰

  • foo<mycrate::Example>::foo
  • bar<mycrate::Example>::bar

路径:特征定义

trait-definition → Y 类型 路径

一个 trait-definition 是指向特征定义的路径。它由字符 Y 后跟 类型 组成,该类型是引用者的 Self 类型,后跟指向特征定义的 路径

推荐的反修饰

一个 trait-definition 可以使用 < type as path > 语法显示为限定路径段。

示例

trait Trait {
    fn example() {}
}
struct Example;
impl Trait for Example {}

Example 实现的特征 Trait 中的 example 的符号是

_RNvYNtCs15kBYyAo9fc_7mycrate7ExampleNtB4_5Trait7exampleB4_
    │└──────────────┬───────────────┘└────┬────┘
    │               │                     │
    │               │                     └── path to the trait "Trait"
    │               └──────────────────────── path to the implementing type "mycrate::Example"
    └──────────────────────────────────────── trait-definition

推荐的反修饰:<mycrate::Example as mycrate::Trait>::example

路径:嵌套路径

nested-path → N 命名空间 路径 标识符

一个 nested-path 是表示可选命名实体的路径。它由字符 N 后跟一个 命名空间(指示实体的命名空间)、后跟一个 路径(该路径是表示实体父级的路径),后跟实体的 标识符 组成。

当实体未命名时,实体的标识符的长度可能为 0。例如,诸如闭包、类似元组的结构构造函数和匿名常量之类的实体可能没有名称。除非歧义消除器为 0,否则标识符可能仍然具有歧义消除器。

推荐的反修饰

可以通过首先显示 路径,然后是 :: 分隔符,然后是 标识符 来显示 nested-path。如果 标识符 为空,则不应显示分隔 ::

如果指定了 命名空间,则可以添加额外的上下文,例如
路径 ::{ 命名空间 (: 标识符)可选 # 歧义消除器作为以 10 为底的数字 }

在这里,命名空间 C 可以打印为 closure,而 S 可以打印为 shim。其他命名空间可以按照其字符标签打印。如果 : name 部分的名称为空,则可以跳过。

如果指定了命名空间,则可以显示标识符中的消歧符。在其他情况下,通常不需要显示消歧符。如果显示,建议将其放在括号中,例如 [284a76a8b41a7fd3]。如果不存在消歧符,则其值为 0,并且始终可以从显示中省略。

示例

fn main() {
    let x = || {};
    let y = || {};
    x();
    y();
}

crate mycrate 中闭包 x 的符号是

_RNCNvCsgStHSCytQ6I_7mycrate4main0B3_
  ││└─────────────┬─────────────┘│
  ││              │              │
  ││              │              └── identifier with length 0
  ││              └───────────────── path to "mycrate::main"
  │└──────────────────────────────── closure namespace
  └───────────────────────────────── nested-path

闭包 y 的符号类似,带有一个消歧符

_RNCNvCsgStHSCytQ6I_7mycrate4mains_0B3_
                                 ││
                                 │└── base-62-number 0
                                 └─── disambiguator 1 (base-62-number+1)

推荐的反修饰

  • x: mycrate::main::{closure#0}
  • y: mycrate::main::{closure#1}

路径:泛型参数

generic-args → I 路径 {泛型参数} E

generic-arg →
      lifetime
   | 类型
   | K 常量

一个 generic-args 是表示泛型参数列表的路径。它由字符 I 开头,后跟定义实体的路径,然后是零个或多个 泛型参数,以字符 E 结尾。

每个 泛型参数 可以是一个 生命周期 (以字符 L 开头),一个类型,或者是字符 K 后跟一个表示常量参数的 常量

推荐的反修饰

一个 generic-args 可以打印为:路径 ::opt < 逗号分隔的参数列表 >。对于类型路径,可以省略 :: 分隔符(类似于 Rust 的规则)。

示例

fn main() {
    example([123]);
}

fn example<T, const N: usize>(x: [T; N]) {}

函数 example 的符号是

_RINvCsgStHSCytQ6I_7mycrate7examplelKj1_EB2_
  │└──────────────┬───────────────┘││││││
  │               │                │││││└── end of generic-args
  │               │                ││││└─── end of const-data
  │               │                │││└──── const value `1`
  │               │                ││└───── const type `usize`
  │               │                │└────── const generic
  │               │                └─────── generic type i32
  │               └──────────────────────── path to "mycrate::example"
  └──────────────────────────────────────── generic-args

建议的反向解析:mycrate::example::<i32, 1>

命名空间

namespace → 小写 | 大写

命名空间用于将名称分隔到单独的逻辑组中,从而允许相同的名称避免冲突。它由一个大写或小写 ASCII 字母组成。小写字母保留用于实现内部的消歧类别(反向解析器不应显示它们)。大写字母用于特殊命名空间,反向解析器可以特殊方式显示它们。

大写命名空间是

  • C — 一个闭包。
  • S — 一个 shim。在某些需要中间体的场景中,编译器会添加 shim。例如,具有 #[track_caller] 属性的函数的 fn() 指针需要一个 shim 来处理隐式的调用者位置。

推荐的反修饰

有关建议的反向解析,请参见嵌套路径

标识符

identifier → 消歧符opt 未消歧的标识符

undisambiguated-identifier → uopt 十进制数 _opt 字节

bytes → {UTF-8 字节}

标识符路径 中用于引用实体的命名标签。它由一个可选的消歧符和一个未消歧的标识符组成。

消歧符用于消除不应被视为相同的相同标识符的歧义。例如,闭包没有名称,因此消歧符是同一父路径中两个不同闭包之间唯一的区分元素。

未消歧的标识符以可选的 u 字符开头,表示该标识符使用 Punycode 编码。下一部分是 十进制数,表示字节的长度。

在标识符大小之后是一个可选的 _ 字符,用于将长度值与标识符本身分开。如果字节以十进制数字或 _ 开头,则 _ 是必需的,以保持 十进制数 结束和 字节 开始的明确性。

字节是标识符本身,使用 UTF-8 编码。

推荐的反修饰

标识符的显示取决于其上下文。如果它是 Punycode 编码的,则可能在显示之前先进行解码。

消歧符可能会显示,也可能不会显示;请参阅使用标识符的规则的建议。

Punycode 标识符

由于某些环境仅限于 ASCII 字母数字和 _,Rust 的 Unicode 标识符 可以使用修改版本的 Punycode 进行编码。

例如,函数

mod gödel {
  mod escher {
    fn bach() {}
  }
}

将被 mangled 为

_RNvNtNtCsgOH4LzxkuMq_7mycrateu8gdel_5qa6escher4bach
                              ││└───┬──┘
                              ││    │
                              ││    └── gdel_5qa translates to gödel
                              │└─────── 8 is the length
                              └──────── `u` indicates it is a Unicode identifier

标准 Punycode 生成 ([[:ascii:]]+-)?[[:alnum:]]+ 形式的字符串。这是有问题的,因为 - 字符(用于将 ASCII 部分与 base-36 编码分开)不在符号的受支持字符集中。因此,Punycode 编码中的 - 字符将替换为 _

以下是一些示例

原始PunycodePunycode + 编码
føøf-5gaaf_5gaa
α_ω_-ylb7e__ylb7e
铁锈n84amfn84amf
🤦fq9hfq9h
ρυστ2xaedc2xaedc

注意:是否使用 Punycode 编码标识符取决于编译器。某些平台可能原生支持 UTF-8 符号,编译器可能会决定直接使用 UTF-8 编码。反向解析器应准备好支持这两种形式。

消歧符

disambiguator → s base-62 数

消歧符用于符号 路径 的各个部分,以唯一标识路径元素,这些元素本来是相同的,但不应被视为相同。它以字符 s 开头,后跟一个 base-62 数

如果未指定消歧符,则可以假定其值为零。否则,在反向解析时,应将值 1 添加到 base-62 数(因此,编码为 _ 的 0 的 base-62 数的值为 1)。这允许顺序编码的消歧符使用最少的字节。

推荐的反修饰

消歧符可能会显示,也可能不会显示;请参阅使用消歧符的规则的建议。通常,建议永远不要显示零消歧符,除非它们附带的标识符为空(例如闭包等未命名项)。呈现消歧符时,可以将其缩短到适合上下文的长度,类似于 git 提交哈希很少完整显示的方式。

生命周期

lifetime → L base-62 数

生命周期用于编码匿名(编号)生命周期,可以是擦除的或 高阶 的。它以字符 L 开头,后跟一个 base-62 数。索引 0 始终被擦除。从 1 开始的索引(作为 De Bruijn 索引)指向由封闭的 绑定符 绑定的高阶生命周期。

推荐的反修饰

生命周期可以像 Rust 生命周期一样使用单引号显示。

索引 0 应显示为 '_。对于 引用类型可变引用类型动态 trait 类型 中的生命周期,不应显示索引 0。

可以通过将 De Bruijn 索引转换为 De Bruijn 级别(级别 = 绑定生命周期的数量 - 索引)并为每个级别选择一个唯一名称来显示生命周期。例如,从单个小写字母开始,例如级别 0 的 'a。级别超过 25 时,可以考虑将数字生命周期打印为 '_123。有关生命周期索引和排序的更多信息,请参见 绑定符

示例

fn main() {
    example::<fn(&u8, &u16)>();
}

pub fn example<T>() {}

函数 example 的符号是

_RINvCs7qp2U7fqm6G_7mycrate7exampleFG0_RL1_hRL0_tEuEB2_
                                   │└┬┘│└┬┘││└┬┘││
                                   │ │ │ │ ││ │ │└── end of input types
                                   │ │ │ │ ││ │ └─── type u16
                                   │ │ │ │ ││ └───── lifetime #1 'b
                                   │ │ │ │ │└─────── reference type
                                   │ │ │ │ └──────── type u8
                                   │ │ │ └────────── lifetime #2 'a
                                   │ │ └──────────── reference type
                                   │ └────────────── binder with 2 lifetimes
                                   └──────────────── function type

建议的反向解析:mycrate::example::<for<'a, 'b> fn(&'a u8, &'b u16)>

常量

const →
      类型 常量数据
   | p
   | 反向引用

const-data → nopt {十六进制数字} _

十六进制数字数字 | a | b | c | d | e | f

常量用于编码泛型和类型中使用的常量值。它具有以下形式

  • 常量值编码为表示常量类型的类型 和表示常量值的 常量数据,后跟 _ 以终止常量
  • 字符 p 表示 占位符
  • 到先前编码的相同值的常量反向引用

常量数据的编码取决于类型

  • bool — 值 false 编码为 0_,值 true 编码为 1_
  • char — 字符的 Unicode 标量值以十六进制编码。
  • 无符号整数 — 该值以十六进制编码。
  • 有符号整数 — 字符 n 是一个前缀,表示它是负数,后跟以十六进制编码的绝对值。

推荐的反修饰

常量可以通过常量值根据类型显示。

p 占位符应显示为 _ 字符。

对于特定类型

  • b (bool) — 显示为 truefalse
  • c (char) — 以 Rust 字符形式显示字符(例如 'A''\n')。
  • 整数 — 显示整数(以十进制或十六进制显示)。

示例

fn main() {
    example::<0x12345678>();
}

pub fn example<const N: u64>() {}

函数 example 的符号是

_RINvCs7qp2U7fqm6G_7mycrate7exampleKy12345678_EB2_
                                   ││└───┬───┘
                                   ││    │
                                   ││    └── const-data 0x12345678
                                   │└─────── const type u64
                                   └──────── const generic arg

建议的反向解析:mycrate::example::<305419896>

占位符

在类型或常量值不相关的情况下,可能会出现占位符

示例

pub struct Example<T, const N: usize>([T; N]);

impl<T, const N: usize> Example<T, N> {
    pub fn foo() -> &'static () {
        static EXAMPLE_STATIC: () = ();
        &EXAMPLE_STATIC
    }
}

在此示例中,静态变量 EXAMPLE_STATIC 不会通过类型或常量参数 TN 进行单态化。它们将对这些泛型参数使用占位符。它的符号是

_RNvNvMCsd9PVOYlP1UU_7mycrateINtB4_7ExamplepKpE3foo14EXAMPLE_STATIC
                             │             │││
                             │             ││└── const placeholder
                             │             │└─── const generic argument
                             │             └──── type placeholder
                             └────────────────── generic-args

建议的反向解析:<mycrate::Example<_, _>>::foo::EXAMPLE_STATIC

类型

type →
      basic-type
   | 数组类型
   | 切片类型
   | 元组类型
   | 引用类型
   | 可变引用类型
   | 常量指针类型
   | 可变指针类型
   | 函数类型
   | 动态 trait 类型
   | 路径
   | 反向引用

类型表示 Rust 类型。初始字符可用于区分编码的类型。基于初始标签字符的类型编码是

  • 基本类型 编码为单个字符
    • ai8
    • bbool
    • cchar
    • df64
    • estr
    • ff32
    • hu8
    • iisize
    • jusize
    • li32
    • mu32
    • ni128
    • ou128
    • si16
    • tu16
    • u — unit ()
    • v — variadic ...
    • xi64
    • yu64
    • z!
    • p占位符 _

其余基本类型编码为 crate 产生式,例如 C4f128

  • A — 一个数组 [T; N]

    数组类型A 类型 常量

    标签 A 后面跟着数组的 类型,然后是数组大小的 常量

  • S — 一个切片 [T]

    切片类型S 类型

    标签 S 后面跟着切片的 类型

  • T — 一个元组 (T1, T2, T3, ...)

    元组类型T {类型} E

    标签 T 后面跟着一个或多个 类型,表示每个字段的类型,最后以终止符 E 结尾。

    注意,零长度元组(单元)使用 u 基本类型 进行编码。

  • R — 一个引用 &T

    引用类型R 生命周期可选 类型

    标签 R 后面跟着一个可选的 生命周期,然后是引用的 类型。如果生命周期已被擦除,则不包含生命周期。

  • Q — 一个可变引用 &mut T

    可变引用类型Q 生命周期可选 类型

    标签 Q 后面跟着一个可选的 生命周期,然后是可变引用的 类型。如果生命周期已被擦除,则不包含生命周期。

  • P — 一个常量原始指针 *const T

    标签 P 后面跟着指针的 类型

    常量指针类型P 类型

  • O — 一个可变原始指针 *mut T

    可变指针类型O 类型

    标签 O 后面跟着指针的 类型

  • F — 一个函数指针 fn(…) -> …

    函数类型F 函数签名

    函数签名绑定器可选 U可选 (K ABI)可选 {类型} E 类型

    ABI
          C
       | 未歧义标识符

    标签 F 后面跟着函数签名的 函数签名函数签名是函数指针的签名。

    它以一个可选的 绑定器 开始,该绑定器表示高阶特征绑定 (for<…>)。

    之后是一个可选的 U 字符,它表示 unsafe 函数。

    之后是一个可选的 K 字符,它表示指定了 ABI。如果未指定 ABI,则假定为 "Rust" ABI。

    ABI 可以是字母 C,表示它是 "C" ABI。否则,它是 ABI 字符串的 未歧义标识符,其中破折号转换为下划线。

    之后是零个或多个 类型,表示函数的输入参数。

    之后是字符 E,然后是返回值的 类型

  • 一个指向具名类型的 路径

  • 一个用于引用先前编码的类型的 反向引用

推荐的反修饰

一个 类型 可以使用典型的 Rust 语法显示为它表示的类型。

示例

fn main() {
    example::<[u16; 8]>();
}

pub fn example<T>() {}

函数 example 的符号是

_RINvCs7qp2U7fqm6G_7mycrate7exampleAtj8_EB2_
                                   │││├┘│
                                   ││││ └─── end of generic args
                                   │││└───── const data 8
                                   ││└────── const type usize
                                   │└─────── array element type u16
                                   └──────── array type

推荐的解构:mycrate::example::<[u16; 8]>

绑定器

绑定器 → G base-62 数字

一个 *绑定器* 表示要绑定的高阶特征绑定生命周期的数量。它由字符 G 后跟一个 base-62 数字 组成。解码时应将值 1 添加到 base-62 数字(使得 _base-62 数字 编码被解释为具有 1 个绑定器)。

一个 *生命周期* 规则然后可以引用这些编号的生命周期。最小的索引表示最内部的生命周期。绑定生命周期的数量是 base-62 数字 的值加一。

例如,在 for<'a, 'b> fn(for<'c> fn (...)) 中,... 中的任何 生命周期(但不在更多的绑定器内部)将观察到索引 1、2 和 3 分别引用 'c'b'a

推荐的反修饰

可以使用 for<…> 语法打印 *绑定器*,如 生命周期 中推荐的那样列出生命周期。有关示例,请参见 *生命周期*。

反向引用

反向引用 → B base-62 数字

一个 *反向引用* 用于引用被 mangled 符号的先前部分。这提供了一种简单的压缩形式,以减少被 mangled 符号的长度。这有助于减少编译器、链接器和加载器所需的工作量和资源。

它由字符 B 后跟一个 base-62 数字 组成。该数字表示从符号的 _R 前缀之后开始的基于 0 的字节偏移量。反向引用表示从该位置开始的相应元素。

反向引用始终引用在 反向引用 本身之前的位置。

反向引用 压缩依赖于这样一个事实,即所有可替换的符号元素都具有自终止的 mangled 形式。给定编码节点的起始位置,语法保证节点在哪里结束始终是明确的。这是通过不允许可替换产生式末尾的可选或重复元素来确保的。

推荐的反修饰

应通过呈现它指向的元素来解构 反向引用。处理深度嵌套的反向引用时应考虑避免使用过多的堆栈。

示例

fn main() {
    example::<Example, Example>();
}

struct Example;

pub fn example<T, U>() {}

函数 example 的符号是

_RINvCs7qp2U7fqm6G_7mycrate7exampleNtB2_7ExampleBw_EB2_
                                     │├┘        │├┘ │├┘
                                     ││         ││  ││
                                     ││         ││  │└── backref to offset 3 (crate-root)
                                     ││         ││  └─── backref for instantiating-crate path
                                     ││         │└────── backref to offset 33 (path to Example)
                                     ││         └─────── backref for second generic-arg
                                     │└───────────────── backref to offset 3 (crate-root)
                                     └────────────────── backref for first generic-arg (first segment of Example path)

推荐的解构:mycrate::example::<mycrate::Example, mycrate::Example>

实例化 crate

实例化-crate → 路径

实例化-crate符号名称 的一个可选元素,可用于指示哪个 crate 正在实例化该符号。它由单个 路径 组成。

这有助于区分否则将相同的符号,例如,如果另一个 crate 也使用相同的类型实例化相同的泛型函数,则外部 crate 中函数的单态化可能会导致重复。

在实践中,实例化 crate 通常也是定义符号的 crate,因此它通常被编码为指向符号中其他位置编码的 crate 根目录反向引用

推荐的反修饰

实例化-crate 通常不需要显示。

示例

std::path::Path::new("example");

mycrate crate 实例化的 Path::new::<str> 的符号是

_RINvMsY_NtCseXNvpPnDBDp_3std4pathNtB6_4Path3neweECs7qp2U7fqm6G_7mycrate
                                                                └──┬───┘
                                                                   │
                                                                   └── instantiating crate identifier `mycrate`

推荐的解构:<std::path::Path>::new::<str>

特定于供应商的后缀

特定于供应商的后缀 → (. | $) 后缀

后缀 → {字节}

特定于供应商的后缀符号名称 末尾的可选元素。它由一个 .$ 字符后跟零个或多个字节组成。句点或美元符号后的字符没有限制。

此后缀根据实现需要添加。一个可能发生这种情况的示例是当本地唯一名称需要变为全局唯一名称时。LLVM 可以在 LTO 期间附加一个 .llvm.<numbers> 后缀以确保唯一的名称,并且 $ 可用于 Mach-O 上的线程本地数据。在这些情况下,通常可以忽略后缀;带后缀的名称与原始名称具有相同的语义。

推荐的反修饰

特定于供应商的后缀 通常不需要显示。

示例

use std::cell::RefCell;
thread_local! {
    pub static EXAMPLE: RefCell<u32> = RefCell::new(1);
}

macOS 上 EXAMPLE 的符号可能具有以下线程本地数据

_RNvNvNvCs7qp2U7fqm6G_7mycrate7EXAMPLE7___getit5___KEY$tlv$init
                                                      └───┬───┘
                                                          │
                                                          └── vendor-specific-suffix

推荐的解构:mycrate::EXAMPLE::__getit::__KEY

通用规则

十进制数
      0
   | 非零数字 {数字}

非零数字1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
数字0 | 非零数字

小写字母a |b |c |d |e |f |g |h |i |j |k |l |m |n |o |p |q |r |s |t |u |v |w |x |y |z

大写字母A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

十进制数 被编码为一个或多个 数字,表示十进制的数值。

值零被编码为单个字节 0。请注意,在某些情况下,0 后面可能会跟另一个数字,该数字不应被解码为十进制数字的一部分。例如,一个零长度的标识符在一个嵌套路径内,而该嵌套路径又在另一个嵌套路径内,将导致连续出现两个标识符,其中第一个标识符只有 0 的编码。

数字是一个 ASCII 数字。

小写字母大写字母分别是 ASCII 小写字母和大写字母。

base-62-number

base-62-number → { 数字 | 小写字母 | 大写字母 } _

base-62-number 是一个数值的编码。它使用 ASCII 数字、小写字母和大写字母。该值以 _ 字符结尾。如果该值为 0,则编码是 _ 字符,没有任何数字。否则,从该值中减 1,并使用以下映射进行编码

  • 0-9 映射到 0-9
  • a-z 映射到 10 到 35
  • A-Z 映射到 36 到 61

该数字被反复除以 62(整数除法向零舍入),以选择序列中的下一个字符。每次除法的余数用于映射以选择下一个字符。重复此过程,直到数字为 0。然后反转最终的字符序列。

解码是一个类似的反向过程。

示例

编码
0_
10_
11a_
62Z_
6310_
1000g7_

符号语法总结

以下是符号语法所有产生的总结。

symbol-name_R 十进制数字opt 路径 实例化 crateopt 供应商特定后缀opt

路径
      箱根
   | 固有实现
   | 特征实现
   | 特征定义
   | 嵌套路径
   | 泛型参数
   | 反向引用

crate-rootC 标识符
inherent-implM impl-path 类型
trait-implX impl-path 类型 路径
trait-definitionY 类型 路径
nested-pathN 命名空间 路径 标识符
generic-argsI 路径 {generic-arg} E

标识符消歧符opt 未消歧标识符
未消歧标识符uopt 十进制数字 _opt 字节
字节 → {UTF-8 字节}

消歧符s base-62-number

impl-path消歧符opt 路径

类型
      basic-type
   | 数组类型
   | 切片类型
   | 元组类型
   | 引用类型
   | 可变引用类型
   | 常量指针类型
   | 可变指针类型
   | 函数类型
   | 动态 trait 类型
   | 路径
   | 反向引用

基本类型小写字母
数组类型A 类型 常量
切片类型S 类型
元组类型T {类型} E
引用类型R 生命周期opt 类型
可变引用类型Q 生命周期opt 类型
常量指针类型P 类型
可变指针类型O 类型
函数类型F 函数签名
动态 trait 类型D 动态边界 生命周期

命名空间小写字母 | 大写字母

generic-arg
      lifetime
   | 类型
   | K 常量

生命周期L base-62-number

常量
      类型 常量数据
   | p
   | 反向引用

常量数据nopt {十六进制数字} _

十六进制数字数字 | a | b | c | d | e | f

函数签名绑定器opt Uopt (K ABI)opt {类型} E 类型

ABI
      C
   | 未歧义标识符

动态边界绑定器opt {动态 trait} E
动态 trait路径 {动态 trait 关联绑定}
动态 trait 关联绑定p 未消歧标识符 类型

绑定器G base-62-number

后向引用B base-62-number

实例化 crate路径

供应商特定后缀 → (. | $) 后缀
后缀 → {字节}

十进制数
      0
   | 非零数字 {数字}

base-62-number → { 数字 | 小写字母 | 大写字母 } _

非零数字1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
数字0 | 非零数字
小写字母a |b |c |d |e |f |g |h |i |j |k |l |m |n |o |p |q |r |s |t |u |v |w |x |y |z
大写字母A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

Rust 实体的编码

以下是在符号中如何编码 Rust 实体的指导原则。只要符号是明确的,编译器在如何编码实体方面有一定的自由度。

  • 命名的函数、方法和静态变量应由一个路径产生式表示。

  • 路径应该以可以充当路径根的最内层实体为根。根可以是 crate-id、固有 impl、trait impl 和(对于默认方法中的项)trait 定义。

  • 编译器可以从保留范围中选择消歧索引和命名空间标签,只要它确定标识符的明确性。

  • 等于默认值的泛型参数为了节省空间不应进行编码。