本月测试基础设施更新:2025 年 3 月刊

2025 年 4 月 13 日 · Jieyou Xu 代表 Bootstrap Team

本月测试基础设施更新:2025 年 3 月刊

这是对 2025-03-112025-04-13 期间 rust-lang/rust 仓库1 测试基础设施变化的快速总结。

在此期间,compiletestbootstrap 有一些重要变化,贡献者应予以了解。

和往常一样,如果您在使用我们的测试基础设施时遇到 bug 或用户体验问题,请提交 issue。如果我们不知道 bug 和小问题,就无法修复它们!

感谢所有为我们的测试基础设施做出贡献的人!

要点

compiletest 现在支持匹配下方行的诊断信息

以前,UI 错误注解可以匹配针对上方行 (//~^) 或同一行 (//~) 发出的诊断信息,但无法表达匹配针对下方行发出的诊断信息。根据 #139100,测试编写者现在可以使用 //~v 来匹配针对下方行发出的诊断信息。这对于例如解析器测试特别有用,在这些测试中,测试文件可能会触发词法分析器/解析器诊断信息,并且测试文件本身在语法上是无效的(因此不能在之后使用注释来匹配之前的行)。

示例

// tests/ui/parser/issues/issue-103451.rs

struct R { }
//~vv ERROR this file contains an unclosed delimiter
struct S {
    x: [u8; R

compiletest 现在支持对与主测试文件无关行信息的诊断信息进行精确和穷尽匹配

以前,测试编写者必须借助于 //@ error-pattern 来匹配与主测试文件没有关联行信息的诊断信息。现在,测试编写者可以使用 //~? DIAGNOSTIC_KIND diagnostic_message 来匹配诊断类别为 DIAGNOSTIC_KIND(例如 ERRORHELP)且消息为 diagnostic_message 的诊断信息。参见 compiletest: Support matching on diagnostics without a span #138865//~? 可以出现在测试文件的任意行,但通常习惯性地放在末尾。

示例

// tests/ui/invalid-module-declaration/invalid-module-declaration.rs

mod auxiliary {
    mod foo;
}

fn main() {}

//~? ERROR file not found for module `baz`

//@ error-pattern 相比,//~? 错误注解是精确的穷尽的

  • 精确的//~? 注解不会匹配那些带有行信息的诊断信息。
  • 穷尽的:如果主测试文件中存在多个缺乏行信息的诊断信息,那么所有这些诊断信息都需要使用 //~? 进行注解。

总的来说,//~? 有助于防止意外地忽略主测试文件中没有关联行信息的诊断信息。

//@ error-pattern 对于例如没有特定 span 的运行时错误消息,或由于多行平台特定诊断信息而需要不精确匹配的编译时消息仍然有用。在合适的地方,应优先使用 //~?

值得关注的变化

本节旨在作为“兼容性说明”,但面向人工测试编写者。

为准备 stage 0 std 重大调整,现在可以为 compiletest 使用 stage 0 的 libtest

根据 stage 0 std 重大调整,构建库树将需要 stage 1 编译器。compiletest 有些奇怪,因为它目前依赖于树内的 libtest——这意味着随着 stage 0 std 的重大调整,对编译器树的更改将需要重建 compiletest,从而给编译器开发周期带来更多麻烦。为了缓解这个问题,bootstrap 现在支持一个新的配置选项,可以将 compiletest 切换为依赖 stage 0 libtest 而不是树内的 libtest,这样对 compiler/ 树的更改就不会导致 compiletest 重建。

[build]
compiletest-use-stage0-libtest = true

请注意,作为权衡,我们在 PR CI 中会检查这个 force-stage0-libtest 配置。这意味着在升级 stage 0 编译器之前,libtest 可能存在修改的时间窗口,这可能需要修改 libtest 的 PR 作者根据情况在依赖 libtest 编程 API 的 compiletest 部分添加 cfg(bootstrap)/cfg(not(bootstrap))。这是基于 libtest 编程 API 更改相对不频繁的假设进行的。如果事实证明这是一个重大负担,bootstrap 团队愿意重新考虑此方案。

请注意,从长远来看,我们希望摆脱对树内 libtest 的依赖(既是为了使这种变通方法不再必要,也是为了更好地控制测试执行)。

bootstrap 的 config.toml 已重命名为 bootstrap.toml

以前,bootstrap 在 checkout 根目录下使用 config.toml 作为配置文件。这可能令人困惑,因为 Cargo 也使用 config.toml 作为其配置文件名。现在,bootstrap 改为使用 bootstrap.toml 作为配置文件名。示例配置文件 config.example.toml 也已重命名为 bootstrap.example.toml

config.toml 作为备用配置文件被临时接受,以缓解不同 checkout 之间的迁移麻烦,但将来会被淘汰。

compiletest 现在强制对诊断类别进行更严格的解析

以前,compiletest 对诊断类别(即错误注解中的 ERROR/HELP 部分)的大小写要求非常宽松。这意味着诸如以下形式的注解也曾被接受:

//~ Error xxx
//~ Error: xxx

它们也被接受了,与更常见的 //~ ERROR//~ error 形式相比。

与更常见的 //~ ERROR//~ error 形式相比,以前也接受了。最终,我们希望将错误注解规范化为一种形式。为了使这一转变不那么突然,作为中间步骤,compiletest 现在将

  • 强制要求错误注解诊断类别必须全大写(例如 ERROR)或全小写(例如 error)。像 //~ Error 这样的混合大小写现在将被拒绝。
  • 空诊断(例如空的 //~ NOTE)将不再被静默忽略。这些表示 rustc 发出了应该修复的愚蠢的空诊断说明。

compiletest 现在强制要求即使使用了 //@ error-pattern 指令,也必须提供错误注解

与之前 //~? 的改进相关,compiletest 现在也会在使用 //@ error-pattern 的测试中检查是否存在错误注解(//~),以最大限度地降低意外忽略诊断信息的风险,包括那些与主测试文件没有关联行信息的诊断信息。

特殊情况下,测试编写者可以通过 //@ compile-flags: --error-format=human 选择不进行错误注解检查。

compiletest 现在允许通过新的指令 //@ dont-require-annotations: DIAGNOSTIC_KIND 选择性地允许对特定诊断类别进行非穷尽匹配

compiletest 现在有一个新指令 //@ dont-require-annotations: DIAGNOSTIC_KIND(其中 DIAGNOSTIC_KIND 例如可以是 ERROR/HELP/SUGGESTION),允许选择性地对指定的 DIAGNOSTIC_KIND 进行非穷尽匹配。这包括 ERROR 诊断类别,以前无法选择退出穷尽匹配。

应谨慎并少量使用此指令。

compiletest 不再接受 {true, false} 作为修订名称

在支持修订的测试套件中,以前接受 //@ revisions: true//@ revisions: false 作为修订名称。然而,这令人困惑,因为它们会自动注册为 --cfg={true,false} 传递给 rustc,但测试编写者必须在测试中使用 cfg(r#true)cfg(r#false)。因此,compiletest 不再允许使用 {true,false} 作为修订名称

compiletest 现在支持 //@ needs-crate-type 指令

测试编写者现在可以使用 //@ needs-crate-type 指令,根据目标平台是否支持所有必需的 crate 类型来限制测试执行。

该指令接受一个逗号分隔的有效 crate 类型列表,这些类型是 rustc --crate-type 标志接受的。例如://@ needs-crate-type: dylib, proc-macro

示例

// This test would be ignored on targets e.g. `wasm32-unknown-unknown` that
// do not (currently) support `dylib` crate type.

//@ needs-crate-type: dylib
//@ compile-flags: --crate-type=dylib

fn foo() {}

compiletest 现在会修剪传递给 //@ {unset,}-{exec,rustc}-env 指令的环境变量名中的空白字符

compiletest 有一个由来已久的怪癖,即

//@ rustc-env: RUSTC_BOOTSTRAP=1

与以下形式不同

//@ rustc-env:RUSTC_BOOTSTRAP=1

其中前者被视为 ⌴RUSTC_BOOTSTRAP//@ exec-env//@ unset-{exec,rustc}-env 指令也存在同样的问题。

现在这个问题已经修复了。compiletest 现在会修剪环境变量名中的空白字符,因此前面提到的形式现在是等效的

//@ rustc-env: RUSTC_BOOTSTRAP=1
//@ rustc-env:RUSTC_BOOTSTRAP=1

都对应于环境变量名 RUSTC_BOOTSTRAP

compiletest 现在强制要求必须使用 //@ edition 指令而不是 //@ compile-flags: --edition=xxx

compiletest 有一个 --edition 标志,允许更改运行测试时使用的默认版次 (edition)。然而,目前没有测试套件在使用非 2015 版次时能够通过,但将来我们希望能够跨所有版次运行测试套件,以确保对所有版次都有良好的测试覆盖(受进一步设计考虑的影响)。

为了使这成为可能,我们首先需要确保 compiletest--edition 覆盖标志能够正常工作。这意味着现在,compiletest 将拒绝通过 //@ compile-flags 传递的 rustc --edition 标志,转而支持 //@ edition 指令,以确保 compiletest 可以覆盖测试的版次。

如果测试作者需要测试 rustc --edition 标志本身的行为,应使用 run-make 测试。

即将到来的变化

以下更改尚未合并,但将在不久的将来合并,或者我们正在积极推进这些工作。

compiletest 即将也将把 SUGGESTION 错误注解视为病毒式传播(viral)

以前,如果测试编写者指定 //~ HELP//~ NOTE,那么 compiletest 会将它们视为病毒式传播(viral)——如果指定了其中一个,则所有同类别的 HELP/NOTE 诊断信息都必须穷尽式地指定。为了保持一致性并更严格地检查编译器发出的诊断信息,我们计划也将 //~ SUGGESTION 注解视为病毒式传播(viral)

这种病毒式穷尽匹配行为可以通过新引入的 //@ dont-require-annotations: SUGGESTION 选择退出(有关此新指令的说明,请参阅值得关注的变化部分)。

run-make 测试(以及 run-make-support 库)很快将默认进行交叉编译以针对目标平台

我们正在努力修复 run-make 测试套件和 run-make-support 库,使其默认能正确测试交叉编译目标平台。如果测试只能在主机上运行,测试作者仍然可以使用 //@ ignore-cross-compile

参见 https://github.com/rust-lang/rust/pull/138066 以及相关的进行中的工作。

PR 列表

改进

修复

清理

文档更新

请注意,由于 rustc-dev-guide 成为了 rust-lang/rust 中的一个 josh 子树,一些文档更新是伴随 rust-lang/rust PR 本身进行的(此处不再重复列出)。