rustc 错误码(Error Codes)体系解析:从分配新 E 代码到诊断输出与测试验证
rustc 错误码Error Codes体系解析从分配新 E 代码到诊断输出与测试验证【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rustrustc 为每一条编译错误分配形如E0123的唯一错误码并配套长篇 Markdown 解释文档构成了 Rust 引以为傲的诊断体验的基石。本文以 rustc-dev-guide 中 error-codes 章节 为主线结合本仓库中rustc_error_codes、rustc_errors等 crate 的真实源码完整讲解错误码的存储结构、解释文档写作规范以及如何按官方流程分配一个新错误码并让它真正在编译器中生效。读完本文你将能够独立完成写一个带EXXXX编号的 rustc 新诊断的全部工作并通过错误索引生成器验证自己的成果。错误码体系概览唯一编号与全局登记rustc 编译器团队为每一条错误消息分配一个唯一代码形如E0123。这些代码在编译器各 crate 的diagnostics.rs文件中定义本质上是一系列宏。所有错误码都必须在rustc_error_codescrate 中集中登记并配有对应的解释文档——新增错误码必须附带解释文档。从源码结构看错误码体系由两个关键组件支撑compiler/rustc_error_codes/src/lib.rs顶层error_codes!宏以数值升序罗列全部在用错误码是全仓库错误码的唯一事实来源single source of truthcompiler/rustc_error_codes/src/error_codes/存放每个错误码对应解释文档的目录本仓库中共有518 个EXXXX.md文件与lib.rs中的宏条目一一对应。lib.rs头部注释明确说明了该宏的设计约束Donotremove entries from this list. Instead, just add a note to the corresponding markdown file saying that this error is not emitted by the compiler any more (see E0001.md for an example), and remove all code examples that do not build any more by marking them withignore (no longer emitted).即不得删除已登记的错误码。即使某个错误不再由编译器发出如历史遗留错误也必须保留其在宏中的位置改为在对应 Markdown 文件中标注 no longer emitted并将不再能编译的示例代码标记为ignore (no longer emitted)。这正是 E0001.md 开头#### Note: this error code is no longer emitted by the compiler.注释的由来。被合并、删除的历史错误码则统一以注释形式列在宏声明的末尾如// E0410, // merged into 408、// E0702, // replaced with a generic attribute input check保证编号历史可追溯。错误解释Error Explanations写为什么而不是怎么改每个错误码都关联一篇 Markdown 格式的扩展解释全部经由rustc_error_codescrate 统一挂接。写作格式遵循RFC 1567long-error-codes-explanation-normalization的约定截至 2026 年 3 月社区正在推动用一份更灵活的新标准对应 RFC 草案 [new-explanations-rfc]取代这份略显过时的 RFC。在官方标准完成全面修订之前写作细节上仍以评审者意见和 Rust Zulip 上的讨论为准。写作时最核心的原则是解释文档应当围绕错误消息展开重点说明错误发生的原因why。直接贴一段快速修复代码对用户帮助有限解释应当帮助用户理解为什么这段代码不被编译器接受从而举一反三。Rust 以高质量错误消息著称长篇解释同样是诊断体验的一部分不应敷衍了事。以 E0001.md 为例其正文先解释触发条件match中某个分支对表达式所有可能取值都不会命中说明前序模式过于宽泛、该分支过于具体或顺序错误再给出正反示例与修正方向——这正是解释原因而非给出补丁的写作范本。注意并非所有历史遗留的不再被发出的错误码都有解释文档这类历史遗留条目是体系中的例外。分配一个新错误码完整操作流程错误码集中存储在compiler/rustc_error_codes。为一个新错误分配编号并注册需要依次完成以下步骤。第一步寻找下一个可用编号打开 compiler/rustc_error_codes/src/lib.rs向下滚动到error_codes!宏声明的末尾即可看到当前在用的最大错误码。以文档写作时的状态为例假设最高在用编号是E0805那么新错误大概率应取E0806。为了确认运行全文检索rg E0806应看到零引用。若存在任何引用如某处已有此编号则需顺延寻找下一个空缺编号。第二步编写扩展解释文档为新错误编写长篇解释保存到compiler/rustc_error_codes/src/error_codes/E0806.md解释内容遵循上文所述解释原因的写作原则与 RFC 1567 的格式要求并在其中附带可编译/可复现错误的代码示例。第三步在error_codes!宏中登记编辑 compiler/rustc_error_codes/src/lib.rs将新编号按数值顺序插入error_codes!宏macro_rules! error_codes { ... 0806, }登记顺序必须严格数值升序0001、0002、0004……一路递增这与src/tools/tidy的一致性检查相呼应详见下文验证与测试一节。第四步在编译器中发出该错误在产生错误的位置使用struct_span_code_err!宏构造并发射诊断struct_span_code_err!(self.dcx(), // 某个指向 DiagCtxt 的路径 span, // 源码中你想要的任意 span E0806, // 你的新错误码 fluent::example::an_error_message) .emit() // 真正发出这条错误其中self.dcx()提供诊断上下文DiagCtxtspan指明错误在源码中的定位范围第三个参数是错误码第四个参数是消息内容。第五步附加标签与说明可选在调用.emit()之前可以链式追加各种诊断增强方法为错误补充标签、注释等上下文信息struct_span_code_err!(...) .span_label(another_span, fluent::example::example_label) .span_note(another_span, fluent::example::separate_note) .emit()span_label用于在第二个 span 处画下划线标签span_note则在对应位置附加一条 note 级别的说明。完整的可参考实现见历史上首个按此流程添加错误码的 PR对应 rust-lang/rust 的 #76143。源码深挖struct_span_code_err!宏到底做了什么struct_span_code_err!并非魔法它的完整定义位于 compiler/rustc_errors/src/diagnostic.rs#[macro_export] macro_rules! struct_span_code_err { ($dcx:expr, $span:expr, $code:expr, $($message:tt)*) ({ $dcx.struct_span_err($span, format!($($message)*)).with_code($code) }) }其展开逻辑可以拆解为三步$dcx.struct_span_err($span, ...)在DiagCtxt上基于 span 构造一个待发射的结构化诊断struct_span_err返回一个可继续定制的诊断构建器.with_code($code)把E0806这样的ErrCode挂到诊断上使其在输出时带上错误码前缀宏表达式整体返回该构建器因此调用方可以继续链式调用.span_label(...)、.span_note(...)等方法最后以.emit()收尾。值得注意的是rustc_errors中Diag类型实现了 Drop 时的析构炸弹destructor bomb机制见同一文件的impl Drop for Diag任何构造出来却未消费未 emit / cancel / 延迟处理的诊断都会在析构时触发一次bug级别的内部错误并 panic提示error was constructed but not emitted。这保证了编译器内部不会静默吞掉诊断。验证与测试错误索引生成器与 tidy 一致性检查运行错误码 doctestrustc_error_codes/src/error_codes/目录下各 Markdown 文件中的代码示例属于可测试内容。运行错误索引生成器即可执行这些示例测试./x test ./src/tools/error_index_generatorerror_index_generator把宏展开成完整索引src/tools/error_index_generator/main.rs 是错误码体系的展示层。它通过rustc_error_codes::error_codes!(define_error_codes_table)宏展开用include_str!把每个错误码对应的EXXXX.md内容内联进一张DIAGNOSTICS表随后按--format参数渲染成 Markdown 或 HTML 格式的 Rust Compiler Error Index供文档站点使用。这也解释了为什么error_codes!宏的语法不能随意改动——改语法需要同步修改 tidy 与索引生成器。tidy自动校验错误码与文档的一致性src/tools/tidy/src/error_codes.rs 实现了check_error_codes_docs与check_error_codes_tests两套检查其逻辑包括从 compiler/rustc_error_codes/src/lib.rs 提取编译器实际使用的全部错误码检查每个在用错误码都在compiler/rustc_error_codes/src/error_codes/下有对应的长篇解释文档缺失即报错统计并打印错误码总数与最大编号例如Found 518 error codes、Highest error code: EXXXX防止编号分配越界或登记乱序。也就是说第三步在宏中登记与第二步编写解释文档缺一不可——即使你忘了写文档CI 中的 tidy 检查也会拦截该变更。这与lib.rs注释中the contents of this macro is checked by tidy (in check_error_codes_docs)的说明完全一致。常见误区与注意事项编号必须按升序插入error_codes!宏按数值排序插入新码时若打乱顺序会破坏 tidy 检查。禁止删除已登记错误码改用#### Note: this error code is no longer emitted by the compiler.标注并将失效示例标记为ignore (no longer emitted)参考 E0001.md。解释文档必须解释原因直接粘贴 quick fix 不是合格的长篇解释应帮助用户理解为什么编译器拒绝这段代码。宏语法是公共契约error_codes!的语法同时被rustc_errors、error_index_generator与tidy依赖改动前需同步评估这三处影响。每条诊断必须被消费由于Diag的析构炸弹机制构造诊断后务必在合适路径上.emit()或做等价处理否则编译过程会以内部 bug 形式暴露问题。通过以上流程你可以为 rustc 贡献一条带完整编号、解释文档与测试覆盖的新诊断相关代码与文档均可直接在本仓库的 compiler/rustc_error_codes 与 src/doc/rustc-dev-guide/src/diagnostics/error-codes.md 中进一步查阅。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →