宣布 Rust 1.52.1

2021 年 5 月 10 日 · Felix Klock,Mark Rousskov 代表 编译器团队

Rust 团队发布了 1.52.1 版本,修复了 1.52.0 版本中增量编译的错误,该错误在 1.52.0 版本中被视为编译错误。我们建议所有 Rust 用户,包括目前使用 1.52.0 之前稳定版本的用户,升级到 1.52.1 或禁用增量编译。有关如何操作的指南,请参见以下内容。

如果您之前已通过 rustup 安装了 Rust,获取 Rust 1.52.1 非常简单:

$ rustup update stable

如果您还没有,您可以从我们网站上的相应页面 获取 rustup

摘要

此版本修复了 1.52.0 版本中由于新添加的验证导致的构建错误。此验证检测到的错误存在于所有 Rust 版本中1,并且可能会在增量构建中触发错误编译,因此降级到之前的稳定版本不是解决方案。

鼓励用户升级到 1.52.1 或在使用之前版本时禁用本地环境中的增量编译:请参阅 您应该做什么 部分,了解如何操作。

增量编译在发布版本中默认关闭,因此很少有生产构建会受到影响(仅适用于已选择加入的用户)。

增量编译中的错误可能会导致最终工件中生成不正确的代码,本质上会产生格式错误的二进制文件,这意味着理论上任何行为都是可能的。实际上,我们目前只知道一个特定的已知错误编译,但由于增量编译导致的错误通常很难追踪:用户在看到二进制文件出现意外结果时,通常会简单地重新构建,这通常会导致足够的重新编译来修复错误。

这篇文章将

  1. 解释 错误是什么样的
  2. 解释 检查的作用,在较高层次上,
  3. 解释 检查是如何呈现的 在 Rust 1.52.0 版本中,
  4. 告诉您 您应该做什么 如果你在你的项目中看到不稳定的指纹,
  5. 描述我们对 Rust 项目将如何解决 这里讨论的问题的计划。

错误是什么样的?

错误消息看起来像这样,关键部分是“发现不稳定的指纹”文本。

thread 'rustc' panicked at 'assertion failed: `(left == right)`
  left: `Some(Fingerprint(4565771098143344972, 7869445775526300234))`,
  right: `Some(Fingerprint(14934403843752251060, 623484215826468126))`: found unstable fingerprints for <massive text describing rustc internals elided>

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

这是由内部一致性检查引起的错误,正如诊断中所述,它会导致“内部编译器错误”(或 ICE)。换句话说,它代表了 Rust 编译器本身内部的错误。在这种情况下,ICE 揭示了增量编译中的错误,该错误早于 1.52.0 版本,如果未被捕获,可能会导致错误编译。

什么是指纹?为什么我们要检查它们?

Rust 编译器支持“增量编译”,这在 2016 年的博客文章 中有描述。当增量编译打开时,编译器将输入源代码分解成多个部分,并跟踪这些输入部分如何影响最终的构建产品。然后,当输入发生变化时,它会检测到这一点并重用先前构建的工件,努力仅将精力集中在构建需要响应输入源代码更改的部分。

指纹是我们检测输入何时发生变化的架构的一部分。更具体地说,指纹(以及一些其他状态来建立上下文)是一个 128 位的值,旨在唯一标识编译器内部使用的内部值。一些编译器内部结果存储在磁盘上(“缓存”)并在运行之间。指纹用于验证新计算的结果是否与缓存的结果相同。(有关此的更多详细信息,请参阅 rustc 开发指南的相关章节。)

指纹稳定性检查是一种保障措施,用于断言指纹的内部一致性。有时编译器被迫重新运行查询,并期望输出与之前的增量编译会话相同。新启用的验证检查该值是否确实如预期的那样,而不是假设它。在某些情况下,由于编译器实现中的错误,实际上并非如此。

历史

我们 最初添加 这些指纹检查作为 2017 年开发 rustc 本身时使用的工具。它仅通过不稳定的 -Z 标志提供,仅适用于 nightly 和开发构建。

最近,在 3 月份,我们遇到了一个 错误编译,导致我们 默认情况下启用 verify-ich。Rust 编译器团队决定最好捕获指纹问题并中止编译,而不是允许潜在的错误编译(以及随后的错误行为)偷偷进入 Rust 程序员的二进制文件。

当我们第一次默认启用指纹检查时,nightly(和 beta)工具链的用户提交了一系列问题,并且在识别修复方面取得了稳步进展,其中许多修复已经完成。

在过去的一周中,我们已经开始 制定计划 来改善用户体验,以便检查发出的诊断能够更好地告诉程序员在响应时该怎么做。不幸的是,这是在假设新的验证将在 1.53 中发布,而不是 1.52 中发布的情况下完成的。

事实证明,verify-ich 在 1.52.0 版本中被启用,该版本 最近发布

今天的 1.52.1 新版本通过暂时更改 Rust 编译器中的默认值来解决新添加的验证导致的故障,除非用户明知故犯,否则将禁用增量编译。

它是如何出现的

本质上,对于某些板条箱,某些编辑-编译循环序列会导致 rustc 遇到“不稳定的指纹”ICE。我在这篇博文开头展示了一个例子。

另一个最近的例子看起来 像这样

thread 'rustc' panicked at 'found unstable fingerprints for predicates_of(<massive text describing rustc internals elided>)', /rustc/.../compiler/rustc_query_system/src/query/plumbing.rs:593:5

它们都源于在将存储在磁盘上的增量编译缓存与当前 rustc 调用期间计算的值进行比较时出现的不一致,这意味着它们都源于使用增量编译。

有几种方法可以打开增量编译

  1. 您可能正在使用 devtest 配置文件,它们默认情况下启用增量编译。
  2. 您可能已设置 环境变量 CARGO_INCREMENTAL=1
  3. 您可能已在 Cargo 配置中启用 build.incremental 设置
  4. 您可能已在 Cargo.toml 中为给定配置文件启用 incremental 设置

如果您的项目没有调整默认值,那么在运行 cargo build --release 或在 release 配置文件中运行时,增量编译在所有 Rust 版本中1 都被禁用,这些问题不应影响您的发布构建。

Rust 程序员应该如何应对

内部编译器错误要求您报告错误,如果您能做到,我们仍然希望获得这些信息。我们希望了解失败的情况。

但是,无论您是否提交错误,都可以通过以下两种方法解决问题:

  1. 升级到 1.52.1,如果您还没有这样做(这将为您禁用增量编译),或者
  2. 删除您的增量编译缓存(例如,通过运行 cargo clean),或者
  3. 强制禁用增量编译,方法是在环境中设置 CARGO_INCREMENTAL=0 或在 config.toml 中将 build.incremental 设置为 false

我们建议 1.52.0 的用户升级到 1.52.1,这将禁用增量编译。

我们建议 1.52.0 的用户为了解决这个问题而降级到更早版本的 Rust。如上所述,至少有一个增量编译导致的静默 错误编译 实例,直到我们添加指纹检查才被发现。

如果用户愿意处理增量验证 ICE,并希望选择回到 1.52.0 的行为,他们可以在环境中将 RUSTC_FORCE_INCREMENTAL 设置为 1。然后,Rust 编译器将尊重 Cargo 传递的 -Cincremental 选项,并且一切将按以前的方式工作,尽管增加了验证。请注意,如果增量编译尚未单独启用(无论是通过 Cargo 还是其他方式),此标志都不会启用增量编译。

如果您目前正在使用 1.52.0 之前的工具链,并且希望继续使用,我们建议您禁用增量编译,以避免遇到静默错误编译。

自增量编译功能加入以来,在所有 Rust 版本中,它都极大地改善了许多用户的编译时间,并且随着时间的推移不断改进。我们承认这里提出的解决方法和建议很痛苦,并将努力确保这种情况尽可能地短暂。

Rust 项目将如何解决这个问题

短期计划

我们今天发布了 1.52.1 版本,它

  • 在 Rust 编译器中禁用了增量编译(除非通过新的环境变量 RUSTC_FORCE_INCREMENTAL=1 请求)。
  • 如果启用了增量编译,则改进了新验证的诊断输出,指示如何通过清除增量状态或禁用增量来解决这些错误。

这旨在成为一种缓解措施,帮助大多数 Rust 用户拥有升级到安全 Rust 编译器的路径,该编译器没有错误编译其代码的风险,但也为愿意处理错误的用户提供选择。

我们预计将继续积极投资于修复这些错误,并且根据我们对修复的信心,可能会发布一个 1.52.2 版本,将这些修复移植到稳定通道。希望帮助我们测试的用户可以使用 nightly 通道,并将遇到的任何 ICE 报告给 rust-lang/rust。

我们目前也不打算在 beta 通道上禁用增量编译,但尚未对此做出坚定承诺。今天 1.53 beta 中提供了一些修复,因此希望继续使用增量的用户可能希望切换到该版本。当然,nightly 将始终拥有最新的修复。

长期计划

长期计划是修复这些错误!增量编译是 Rust 编译器能够为所有程序员提供快速编辑-编译-运行循环的唯一现实方法,因此我们需要解决 所有已识别的问题 通过 verify-ich。 (截至撰写本文时,共有 32 个此类问题,但许多是重复的。)

我们正在积极投资于此,并且已经识别并修复了许多错误。根据修复的状态,未来的稳定版本(1.53 及更高版本)可能会重新启用增量编译。

Rust 团队还将制定计划,确保我们将来拥有更好的错误跟踪系统,既可以防止类似情况再次发生,还可以通过更准确地跟踪错误在通道之间传播来进一步提高我们发布版本的稳定性。

  1. 自增量编译首次启用以来,即在 Rust 1.24 中。 2