查看原文
科技

【独家】Rust 1.70.0:详解新版本的亮点与变化

张汉东 觉学社 2023-06-02
前言
因觉学,求绝学。欢迎关注本合集,带你深入 Rust 语言。

语言更新:

  1. 放宽了 asm! 操作数的排序规则。

在 Rust 1.70.0 的版本更新中,对于 asm! 操作数的排序规则进行了放宽。具体的更改可以在这个 PR链接[1] 中查看。在之前的版本中,asm! 宏的操作数需要按照严格的顺序进行排序,这在某些情况下可能会导致使用上的不便。在新的版本中,这个规则被放宽,提高了 asm! 宏的灵活性和易用性。

  1. 允许宏展开的 format_args 调用使用捕获。

在 Rust 1.70.0 的更新中,允许宏展开的 format_args 调用使用捕获。这个更新主要是关于 Rust 的宏系统。

在 Rust 中,宏(macro)是一种在编译时进行代码扩展的方式。format_args 是一个内建的宏,它可以接受一系列参数,并将它们格式化为一个字符串。

"允许宏展开的 format_args 调用使用捕获" 这个更新的含义是,当 format_args 宏在其宏体中使用变量时,这些变量现在可以是外部作用域中的变量,这就是所谓的 "捕获"。这意味着 format_args 宏现在可以访问并使用其外部环境中的变量,这在以前可能是不允许的。

这个更新可能会使得使用 format_args 宏更加灵活和强大,因为它可以更好地与其周围的代码环境交互。

  1. 对有歧义的全局重新导出进行了 lint 检查。

这是关于 Rust 的一个 Pull Request,标题为 "Lint ambiguous glob re-exports",由 jieyouxu 提出,目标是解决问题 #107563。

这个 Pull Request 试图解决的问题是,当两个名称被特定地重新导出时,即不是来自全局导出,我们目前已经发出错误信息。这个 PR 试图对涉及全局导出的模糊重新导出发出默认拒绝的警告。

在讨论过程中,petrochenkov 建议将此诊断从硬错误更改为默认拒绝的警告,以便我们可以通过 crater 运行它并查看结果。jieyouxu 对此进行了修改,并将其变成了默认拒绝的警告。

最终,这个 Pull Request 被合并到了 Rust 的主分支中。

  1. 对 let _ = expr 位置的表达式进行了 const 和 unsafe 检查。

在 Rust 中,"let _ = expr" 是一种忽略表达式的结果的常见方式。这种形式的声明通常用于你不关心表达式的结果,但仍希望表达式被执行的情况,例如,当表达式有副作用(如打印输出或修改全局状态)时。

"const" 和 "unsafe" 是 Rust 的两个关键字。"const" 用于定义常量或常量函数,而 "unsafe" 用于标记不受 Rust 常规安全检查约束的代码块。

这个 PR #102256[2] 主要解决了在 let _ = expr 位置的表达式进行 constunsafe 检查的问题。

在 Rust 中,let _ = expr 是一种常见的用法,用于忽略表达式的结果。然而,这种用法在某些情况下可能会导致问题。例如,如果 expr 是一个 constunsafe 表达式,那么在 let _ = expr 的位置,这个表达式可能会被忽略,导致 constunsafe 的检查被跳过。

为了解决这个问题,这个 PR 引入了一个新的 PlaceMention 语句,专门用于处理那些既不引入绑定也不指定类型的匹配。这样,即使在 let _ = expr 的位置,exprconstunsafe 检查也能被正确地执行。

这个改动对于 Rust 的安全性检查有重要的意义,因为它确保了 constunsafe 的检查不会因为 let _ = expr 的用法而被忽略。

在 Rust 中,PlaceMention 是一个内部的编译器概念,用于表示一个位置(Place)在代码中的使用方式。这个位置可以是一个变量、一个字段、一个数组元素等等。

在 Rust 中,`PlaceMention`[3] 是编译器内部 StatementKind 枚举的一种变体。StatementKind 枚举表示 MIR(中间表示)中可以出现的各种语句。PlaceMention 用于保留与通配符绑定匹配的 scrutinee 的痕迹。这对于 let _ = PLACE; 这样的绑定特别有用,这些绑定解构为单个 PlaceMention(PLACE)

在运行时,PlaceMention 计算给定的位置,但然后丢弃它而不进行加载。如果位置不指向活动内存,那么这是未定义行为。

这里 "Scrutinee" 是一个术语,通常用于描述在模式匹配中被检查的表达式(即,待匹配对象)。例如,在 match 语句中,我们会说 "match 表达式是 scrutinee"。在这种情况下,"scrutinee 的痕迹" 可能是指在模式匹配过程中保留 scrutinee 的某种信息或状态。

let _ = PLACE; 这样的语句中,PLACE 就是 scrutinee,PlaceMention 用于保留 scrutinee 的痕迹,即使它被通配符 _ 绑定并且其值被丢弃。这可能对于某些类型的分析或优化是有用的,例如,确定 scrutinee 是否被使用,或者在哪里被使用。

编译器更新:

  1. 扩展了 -Cdebuginfo 的新选项和命名别名,为只需要行号信息的情况提供了更小的 debuginfo(-Cdebuginfo=line-tables-only),这可能最终成为 -Cdebuginfo=1 的默认级别。

这个 PR[4] 扩展了 -Cdebuginfo 的新选项和命名别名。原来的 -Cdebuginfo=1 选项并不仅仅是行表,由于向后兼容性问题,无法改变这一点。这个 PR 对此进行了澄清,并添加了一个只发出行表的选项。此外,还添加了一个只发出行信息指令的选项,这对于一些目标(如 nvptx)是必需的。现在的 debuginfo 选项应该与 clang 的 debuginfo 选项行为类似。

新的选项和别名包括:

  • 0none: 没有任何调试信息(默认)。
  • line-directives-only: 仅有行信息指令。对于 nvptx* 目标,这将启用性能分析[5]。对于其他用例,line-tables-only 是更好、更兼容的选择。
  • line-tables-only: 仅有行表。生成最小量的调试信息,用于带有文件名/行号信息的回溯,但不包括其他任何信息,即没有变量或函数参数信息。
  • 1limited: 没有类型或变量级别信息的调试信息。
  • 2full: 完整的调试信息。

这些选项和别名提供了更多的灵活性,以便开发者可以根据他们的需求选择适当的调试信息级别。 这些改变已经通过了 FCP,并且帮助解决了 #109311 和 #104968 的问题

  1. 对 Box::new 进行了 unused_allocation lint 。

这个 PR #104363[6]Box::new 进行了 unused_allocation lint。在此之前,这个 lint 只针对 box 语法,这种语法可能永远不会稳定,所以这个 lint 的用处非常有限。现在,这个 lint 对 Box::new 也有效,这意味着像下面这样的代码将会触发 lint:

Box::new([123]).len();
f(&Box::new(1)); // where f : &i32 -> ()

而首先将 box 存储在变量中的代码则不会触发 lint:

let boxed = Box::new([123]); // no lint
boxed.len();

这个改变可能会影响到大量的用户,因为它扩大了 lint 的范围。但是,这个 PR 已经被合并,所以这个改变已经在 Rust 1.70.0 中生效。

  1. 在 const eval 中提前检测到了无法实例化的类型。

在这个 PR[7] 中,Rust 1.70.0 版本在 const eval(常量求值)中提前检测到了无法实例化的类型。这是一个破坏性的改变,因为一些在 const eval 期间的未定义行为(UB)现在被检测到,而不是被默默地忽略。用户可以通过 -Zextra-const-ub-checks 标志或者在他们的代码上运行 miri(默认设置该标志)来看到这个和可能导致未来破坏的其他 UB。

具体来说,现在我们在 const eval 期间拒绝以下代码:

#[derive(Copy, Clone)]
pub struct ChildStdin {
 inner: AnonPipe,
}
#[derive(Copy, Clone)]
enum AnonPipe {}
const FOO: () = {
 union Foo {
  a: ChildStdin,
  b: (),
 }
 // rust_errors error[E0080]: evaluation of constant value failed
  let x = unsafe { Foo { b: () }.a };
};

在以前,这段代码会被接受,现在则报错。

  1. 将 LLD 作为 {arm,thumb}v4t-none-eabi 的默认链接器。

这个更新是关于 Rust 1.70.0 版本中的一项改动。在这个改动中,LLD 链接器被设定为 {arm,thumb}v4t-none-eabi 目标的默认链接器。LLD 是 LLVM 项目的一部分,是一个高性能的通用链接器。

在 LLVM 16 的更新中,LLD 获得了对 ARMv4t 的支持。因此,Rust 项目决定将其设为 {arm,thumb}v4t-none-eabi 目标的默认链接器,这样用户就不需要安装外部链接器了。这个改动已经被合并到 Rust 语言的主分支中。

这个改动的目的是为了提高 Rust 在 {arm,thumb}v4t-none-eabi 目标上的构建效率和便利性。在这之前,用户可能需要手动安装并配置外部链接器来构建这个目标。现在,由于 LLD 已经成为默认链接器,用户可以更方便地进行构建。

  1. 添加了 loongarch64-unknown-linux-gnu 的第三方目标。 关于loongarch64-unknown-linux-gnu的添加,这是一个针对龙芯架构的Linux GNU系统的Rust编译器和标准库的支持。这意味着Rust现在可以在这种特定的硬件和操作系统配置上运行和编译代码。这个改动包括了对Rust编译器的修改,以及对标准库的一些调整,以确保它们可以在这种系统上正确工作。这是Rust对更多硬件和操作系统的支持的一部分。

  2. 添加了 i586-pc-nto-qnx700(QNX Neutrino RTOS,版本 7.0)的第三方目标。

注意:QNX Neutrino RTOS 是黑莓 QNX 系统,据悉,哪吒汽车与黑莓公司建立合作关系 哪吒S将搭黑莓QNX系统。这意味着 QNX 平台正在准备构建 Rust 工具链支持。 关于i586-pc-nto-qnx700的添加,这是针对QNX Neutrino RTOS版本7.0的x86 32位目标的Rust编译器和标准库的支持。这意味着Rust现在可以在这种特定的硬件和操作系统配置上运行和编译代码。这个改动包括了对Rust编译器的修改,以及对标准库的一些调整,以确保它们可以在这种系统上正确工作。这是Rust对更多硬件和操作系统的支持的一部分。

  1. 插入了对指针解引用的对齐检查作为调试断言,这可以在运行时捕获未定义的行为,并可能导致现有代码失败。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存