什么是 rustc?

欢迎来到 "The rustc book"! rustc 是Rust程序语言的编译器, 它由项目本身提供。 编译器将获取您的源代码并以库或可执行文件的形式生成二进制代码。

大多数Rust程序员并不会直接使用 rustc 命令, 取而代之的是使用 Cargo 。 不过所有的服务都通过 rustc 来完成!如果你想查看 Cargo 是如何使用 rustc 的, 你可以使用如下命令来查看:

$ cargo build --verbose

它将打印出每个 rustc 的调用. 这本书可以帮忙你来理解这些选项的作用. 另外, 虽然大多数 Rustaceans 使用 Cargo, 但并不是所有的 Rustaceans 都这样做: 有时候他们将 rustc 集成到其它构建系统中。 本书会为你提供执行这些操作的所有选项的指南。

基本用法

假设你在 hello.rs文件中有一个小的 hello world 程序:

fn main() {
    println!("Hello, world!");
}

你可以使用 rustc命令将此源代码转换成可执行的文件:

$ rustc hello.rs
$ ./hello # 在linux上
$ .\hello.exe # 在windows上

请注意,我们只是向 rustc 传递了 crate 根目录, 而不是我们想要去编译第一个文件。例如我们有一个如下所示的 main.rs 文件:

mod foo;

fn main() {
    foo::hello();
}

创建 foo.rs 并添加如下内容:

pub fn hello() {
    println!("Hello, world!");
}

我们使用下面的命令去编译它:

$ rustc main.rs

你不需要告诉 rustc 关于 foo.rs的信息; mod 语句会给出需要关联的一切。这与你使用C编译器有所不同,C编译器中,你可以在每个文件上单独调用编译器,然后将他们都链接起来。换句话说, crate 是一个翻译单元(translation unit),而不是特定的模块。

命令行参数

下面是 rustc 的命令行参数列表与操作。

-h/--help: 获取帮助信息

该标签将会打印 rustc的帮助信息。

--cfg: 配置编译环境

此标签会打开或关闭 #[cfg] 变量中的各种 条件编译设置值.

这个值可以是单标识符,也可以是以 = 分隔的双标识符.

例如, --cfg 'verbose' 或 --cfg 'feature="serde"'。 两者分别对应于 #[cfg(verbose)] 和 #[cfg(feature = "serde")] .

-L: 将目录添加到库搜索路径

-L 标签添加了搜索外部crate和库的路径。

当 KIND 是以下情况之一时,可以使用 -L KIND=PATH 这种形式指定搜索路径的类型:

  • dependency — 仅在该目录中搜索传递依赖项。
  • crate — 仅在该目录中搜索此crate的直接依赖项。
  • native — 仅在该目录中搜索本地库。
  • framework — 仅在该目录中搜索macOS框架。
  • all — 搜索此目录中的所有库类型。如果 KIND 没有指定,这将是默认值.

-l: 将生成的crate链接到本地库

该标签允许您在构建 crate 时指定链接到特定的本地库。

当 KIND 是以下情况之一时,库的种类可以使用 -l KIND=lib 这种形式指定:

  • dylib — 本地动态库。
  • static — 本地静态库 (例如 .a archive文件)。(译者注:linux下的静态链接文件格式)
  • framework — macOS框架。

可以用#[link]属性指定库的种类。 如果未在 link 属性或命令行中指定种类, 它将链接到可用动态库,否则将使用静态库。 如果在命令行中指定了库类型,其将会覆盖 link 属性指定的库类型。

link 属性中使用的名称可以使用形如 -l ATTR_NAME:LINK_NAME 形式覆盖,其中 ATTR_NAME 是 link 属性中的名称,LINK_NAME 是将要链接到的实际库的名称。

--crate-type: 编译器将要构建crate的类型列表

这将指示 rustc 以何种 crate type 去构建。该标签接接收逗号分隔的值列表,也可以多次指定。有效的 crate type 如下:

  • lib — 编译器生成的首选库类型, 目前默认为 rlib。
  • rlib — Rust 静态库。
  • staticlib — 本地静态库。
  • dylib — Rust 动态库。
  • cdylib — 本地动态库。
  • bin — 可执行程序。
  • proc-macro — 生成格式化且编译器可加载的过程宏库。

可以使用 crate_type属性来指定 crate 类型。 --crate-type 命令行的值会覆盖 crate_type 属性的值.

更多细节可以参阅 reference 中的 链接章节

--crate-name: 指定正在构建的 crate 名称

这将告知 rustc 您的 crate 的名称。

--edition: 指定使用的edition 版次

该标签值为 2015 或 2018。 默认为 2015。 更多关于版本的信息可以在 版本指南中找到。

--emit: 指定生成输出文件的类型

该标签控制编译器生成的输出文件的类型。其接收以逗号分隔的值列表,也可以多次指定。有效的生成类型有:

  • asm — 生成在 crate 中的一个汇编代码文件。 默认的输出文件是 CRATE_NAME.s。
  • dep-info — 生成一个包含Makefile语法的文件,指示加载以生成crate的所有源文件。 默认输出文件是 CRATE_NAME.d。
  • link — 生成由 --crate-type 指定的 crates 。 默认输出文件取决于平台和 crate 类型。 如果未指定 --emit 这将是默认值。
  • llvm-bc — 生成一个包含 LLVM bitcode的二进制文件。默认输出文件是 CRATE_NAME.bc。
  • llvm-ir — 生成一个包含 LLVM IR( LLVM 中间语言)的文件。默认的输出文件是 CRATE_NAME.ll。
  • metadata — 生成一个关于该 crate 的元数据的文件。 默认输出文件是 CRATE_NAME.rmeta。
  • mir — 生成一个包含 Rust 中级中间表示(即中级中间语言)的文件. 默认输出文件名是 CRATE_NAME.mir。
  • obj — 生成一个本地对象文件,默认输出文件是 CRATE_NAME.o。

输出文件名可以用 -o flag 进行设置。使用-C extra-filename flag可以添加文件名后缀。文件将被写入当前目录除非使用 --out-dir flag 标签。 每一个生成类型也可以使用 KIND=PATH的形式指定输出文件名,它优先于 -o 标签。

--print: 打印编译器信息

该标签打印有关编译器的各种信息。 该标签可以多次指定,并且信息按标志指定的顺序打印。指定 --print 标签通常会禁用 --emit 步骤且只打印请求的信息。打印的有效值类型为:

  • crate-name — crate的名称。
  • file-names — 文件名由 link 命令执行的种类所决定。
  • sysroot — 系统根目录路径。(译者注:此处指的是所使用rust根目录即.rustup下的toolchains文件夹)
  • target-libdir - 目标 lib 文件夹路径(译者注:同上)。
  • cfg — 条件编译值列表。 了解更多条件编译值信息,请参阅 条件编译。
  • target-list — 已知目标列表。 可以使用 --target 标签选择目标。
  • target-cpus — 当前目标的可用CPU值列表。可以使用 -C target-cpu=val flag标签选择目标。
  • target-features — 当前目标的可用 目标 features 列表。目标 features 可以使用 -C target-feature=val 标签启用。该标签是不安全( unsafe )的。 已知问题详细信息请参阅 known issues。
  • relocation-models — 重定位模型列表。重定位模型可以用 -C relocation-model=val flag 标签选择。
  • code-models — 代码模型列表。代码模型可以用 -C code-model=val flag进行设置。
  • tls-models — 支持的线程本地存储模型列表。 模型可以用 -Z tls-model=val 标签来选择。
  • native-static-libs — 当创建一个 staticlib crate 类型时可以使用此选项。 如果这是唯一的标志,它将执行一个完整的编译,并包含一个指出链接生成静态库时要使用的链接器标签(flags)的诊断说明。该说明以文本 native-static-libs: 开始,以便更容易获取输出信息。

-g: 包含调试信息

-C debuginfo=2 的同义词。

-O: 优化代码

-C opt-level=2 的同义词。

-o: 输出的文件名

该标签控制输出的文件名。

--out-dir: 将输出写入的目录

输出的crate将会被写入此目录。 如果使用 -o 标签将会忽略此标签。

--explain: 提供错误消息的详细说明

rustc 对于每一个(检测到的)错误都会返回一个错误码; 这将打印给定错误的较长说明。

--test: 构建测试工具

当编译此crate,rustc 将会忽略 main 函数并且生成测试工具。

--target: 选择要构建目标的三要素

这将控制将要生成的 target。

-W: 设置 lint 警告等级

该标签将会设置哪些 lint 的警告等级.

注: 这些 lint 级别参数的顺序将被考虑进去,更多信息请参见lint level via compiler flag。

-A: 设置 lint 许可等级

该标签将会设置哪些 lint 应该被设置的 许可等级。

Note: 这些 lint 级别参数的顺序, 更多信息请参见 lint level via compiler flag。

-D: 设置 lint 拒绝等级

该标签将会设置哪些 lint 应该被设置的 拒绝等级.

Note: 这些 lint 级别参数的顺序, 更多信息请参见 lint level via compiler flag。

-F: 设置 lint 禁止等级

该标签将会设置哪些 lint 应该被设置的 forbid level.

Note: 这些 lint 级别参数的顺序, 更多信息请参见 lint level via compiler flag。

-Z: 设置不稳定选项

该标签允许你设置不稳定 rustc 选项。该标签可以被使用多次以设置多个选项。 例如: rustc -Z verbose -Z time。 使用 -Z 指定选项只能在 nightly 版本中可用。浏览所有可用选项可以运行: rustc -Z help。

--cap-lints: 设置最严格的 lint 等级

该标签让你 限制 lints 的等级, 更多请 参见。

-C/--codegen: 代码生成选项

该标签允许你设置 生成选项。

-V/--version: 打印版本

该标签将会打印 rustc 的版本。

-v/--verbose: 详细输出

该标签与其他标签结合使用时,会生成额外的输出信息。

--extern: 指定外部库的位置

该标签允许您传递直接依赖项的外部 crate 的名称和位置。 间接依赖项(依赖项的依赖项) 使用 -L 标签来定位。给定的 crate 名称被添加到 extern prelude中, 类似于在根模块中指定 extern crate 。给定的 crate 名称不需要与库构建时使用的名称匹配。

要指出 --extern 与 extern crate 有一个行为差异: --extern 仅仅将 crate 成为链接的一个候选项;不经常指定是不会将其真正链接的。在少数情况下,你可能希望确保一个 crate 是被链接的,即使你不经常在你的代码中使用它:例如, 如果它改变了全局分配器(allocator),或者它包含' #[no_mangle] '符号以供其他编程语言使用,在这种情况下你需要使用 extern crate。

该标签可以多次指定。该标签接受下列格式之一的参数:

  • CRATENAME=PATH — 指定在给定路径上可找到的 crate 。
  • CRATENAME — 指定在搜索路径上可以被找到的 crate ,例如用 sysroot 或由 -L 标签。

同一个 crate 名称可以被不同 crate types 指定多次。如果同时找到 rlib 和 dylib (同名)文件, 则使用一个内部算法来决定使用哪一个进行链接。 -C prefer-dynamic 标签可以被用来影响使用谁。

如果指定了一个带有路径和一个不带路径的同名 crate,则带路径的那个被使用且不带路径的那个无效。

--sysroot: 覆盖系统根目录

"sysroot" 是 rustc 寻找 Rust 发行 crate 的位置;该标签允许被重写。

--error-format: 控制如何产生错误

该标签允许你控制消息的格式。 消息被打印到 stderr 。有效的选项有:

  • human — 人可读的输出格式,此为默认选项。
  • json — 结构化Json输出。 更多细节请参阅 json 章节。
  • short — 简短,单行信息。

--color: 配置输出的颜色

该标签允许你配置输出的颜色。有效选项包括:

  • auto — 如果颜色输出到终端(tty)使用颜色,这是默认选项。
  • always — 始终使用颜色。
  • never — 始终不对输出进行着色。

--remap-path-prefix: 输出中重映射源名称

在所有输出中重新映射源路径前缀,包括编译器诊断、调试信息、宏扩展等。它以 FROM=TO 形式接收一个值,其中 FROM 的路径前缀被重写为值 TO 。 FROM 本身可能包含 = 符号, 但是 TO 值不可能包含。该标签可以被多次指定。

这对于规范化构建产品是很有用的,例如,通过从发送到对象文件的路径名中删除当前目录。该替换是纯文本的,不考虑当前系统的路径名语法。例如 --remap-path-prefix foo=bar 将会匹配 foo/lib.rs 而不是 ./foo/lib.rs。

--json: 配置编译器打印json的消息

当 --error-format=json 选项 传递到 rustc 时,编译器所有的 诊断输出都将以 JSON blobs 的形式发出。 --json 参数可以与 --error-format=json 参数一起使用以配置 JSON blobs 包含的内容以及发出的内容。

使用 --error-format=json 编译器 会将所有编译器错误以 JSON blob 格式发出,但 --json 标签也可以用以下选项来自定义输出:

  • diagnostic-short - 用于诊断消息的json blobs应该使用“ short ”形式呈现,而不是平时的“human”默认值。这意味着 --error-format=short 的输出将被嵌入到JSON诊断中,而不是默认的 --error-format=human 。

  • diagnostic-rendered-ansi - 默认情况下,JSON blob在其 rendered 字段中将包含诊断的纯文本呈现。相反,该选项指示诊断应该嵌入ANSI颜色代码用于为消息着色,就像rustc通常对终端输出所做的那样。注意通常与像 fwdansi 这类的 crate 结合以在 windows console 命令行转换 ANSI 码;或者如果你想在其后选择性地移除 ansi 颜色可以结合 strip-ansi-escapes。

  • artifacts - 这指示rustc为所发出的每个部件发出一个JSON blob对象。部件对应于来自 --emit CLI 参数的请求,一旦部件在文件系统上可用,就会发出相应通知(译者注:即JSON blob对象)。

请注意,--json 参数与 --color 参数组合是无效的,需要将 --json 与 --error format=json 组合。 更多细节请参阅json 章节。

@path: 从路径加载命令行标签

如果在命令行中指定 @path,则它将打开 path 并读取命令行选项。这些选项每行一个;空行表示一个空选项。文件可以使用Unix或Windows样式的行尾,并且必须编码为UTF-8。

Lints

在软件开发中, "lint" 是一个帮助你改善源代码的工具. Rust 编译器中包含了一些 lints, 并且它在编译你的代码时会运行这些 lints. 这些 lints 可能会产生警告,错误或者什么都没有,这些依赖于你对它的配置.

这里有一个小例子 :

$ cat main.rs
fn main() {
    let x = 5;
}
$ rustc main.rs
warning: unused variable: `x`
 --> main.rs:2:9
  |
2 |     let x = 5;
  |         ^
  |
  = note: `#[warn(unused_variables)]` on by default
  = note: to avoid this warning, consider using `_x` instead

这是 unused_variables lint, 并且它告诉你在代码中引入了你没有使用过的变量. 这不是一种 wrong (错误), 但可能是一个Bug, 因此你得到了一个警告.

Future-incompatible lints

(译者注:即对未来可能不兼容代码的警告) 有时为了修复可能导致现存代码停止编译的问题,需要改进编译器,在这种情况下,为了能顺利向新的改进变迁,会向 Rust 用户( users )发出 Future-incompatible lints 。最初,编译器会继续接受有问题的代码并发出警告,该警告包含问题描述和一个这将在未来成为错误的提示,还有一条跟踪问题的链接,此链接提供了关于该问题的详细信息和反馈问题的机会。这给了用户修复代码以适应修改的时间。一段时间后,该警告可能会变成一个错误。

以下是一个 future-incompatible 的例子:

warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
  --> lint_example.rs:11:13
   |
11 |     let y = &x.data.0;
   |             ^^^^^^^^^
   |
   = note: `#[warn(safe_packed_borrows)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior

有关更多 future-incompatible 流程和策略的变更,请查阅 RFC 1589 。

Lint 级别

在 rustc 里, lints 被分为4个 levels (级别):

  1. allow (允许)
  2. warn(警告)
  3. deny(拒绝)
  4. forbid(禁止)

每一个 lint 都有一个默认级别 (会在本章后面lint列表中解释), 并且编译器有一个默认的警告级别. 首先, 让我们解释一下这些级别的含义, 然后再去讨论关于它们的配置.

allow

这个 lints 存在, 但默认情况下不执行任何操作. 例如下面这个源码:


#![allow(unused)]
fn main() {
pub fn foo() {}
}

编译这个文件不会产生任何警告:

$ rustc lib.rs --crate-type=lib
$

但是此代码违反了 missing_docs lint.

这些 lints 主要是通过配置手动去开启的, 我们将在本章节后面再讨论.

warn

如果你违反了 warn 这种 lint 的级别,将会在编译时产生一些警告. 例如下面的代码与 unused_variables lint 发生冲突:


#![allow(unused)]
fn main() {
pub fn foo() {
    let x = 5;
}
}

这将会产生如下所示的警告:

$ rustc lib.rs --crate-type=lib
warning: unused variable: `x`
 --> lib.rs:2:9
  |
2 |     let x = 5;
  |         ^
  |
  = note: `#[warn(unused_variables)]` on by default
  = note: to avoid this warning, consider using `_x` instead

deny

一个 'deny' lint 将会在你违反其规则时产生一个错误。例如下面的代码与 exceeding_bitshifts lint 相冲突。

fn main() {
    100u8 << 10;
}
$ rustc main.rs
error: bitshift exceeds the type's number of bits
 --> main.rs:2:13
  |
2 |     100u8 << 10;
  |     ^^^^^^^^^^^
  |
  = note: `#[deny(exceeding_bitshifts)]` on by default

一个 lint 发出的错误与一个常规错误两者之间有什么不同呢? Lints 可以通过不同的级别(levels)去配置, 因此与 'allow' lints 类似,默认情况下 ' //: # (Section Separator) deny' 的警告是被允许的。类似的, 你可能希望设置一个默认为 warn 等级的 lint 来发出一个错误,此 lint 级别正可以这样让你设置。

forbid

'forbid' 是一种特殊的 lint 级别,它比 'deny' 等级更高。 它与 'deny' 一样会发出一个错误,但是与 'deny' 级别不同的是, 'forbid' 级别不能被比错误更低的情况覆盖了。然而, lint 仍然被 --cap-lints (参阅下文) 限制, 因此 rustc --cap-lints warn 命令将 'forbid' 级别的lints设置为仅有警告信息。

配置 warning 级别

记得我们上面默认级别为 'allow' 的 lint missing_docs 的例子的吗?

$ cat lib.rs
pub fn foo() {}
$ rustc lib.rs --crate-type=lib
$

这样可以配置此 lint 在更高级别上运行,两者都使用编译器标志以及源代码中的属性。

你还可以 "限制" lints 以便编译器可以选择忽略某些 lint 级别. 我们将在最后讨论(这种情况)。

通过编译器标志

比如 -A, -W, -D, 和 -F 标志可以让你设置一个或多个 lint 为 "allow", "waring", "deny", 或者 "forbid" 级别, 像下面这样:

$ rustc lib.rs --crate-type=lib -W missing-docs
warning: missing documentation for crate
 --> lib.rs:1:1
  |
1 | pub fn foo() {}
  | ^^^^^^^^^^^^
  |
  = note: requested on the command line with `-W missing-docs`

warning: missing documentation for a function
 --> lib.rs:1:1
  |
1 | pub fn foo() {}
  | ^^^^^^^^^^^^
$ rustc lib.rs --crate-type=lib -D missing-docs
error: missing documentation for crate
 --> lib.rs:1:1
  |
1 | pub fn foo() {}
  | ^^^^^^^^^^^^
  |
  = note: requested on the command line with `-D missing-docs`

error: missing documentation for a function
 --> lib.rs:1:1
  |
1 | pub fn foo() {}
  | ^^^^^^^^^^^^

error: aborting due to 2 previous errors

你也可以多次传递每个标签,来修改多个 lints 的级别:

$ rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables

当然, 你也可以将这4种标签混合在一起用:

$ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables

这些命令行参数的顺序也考虑在内了。以下内容允许 unused-variables lint, 是因为它是该 lint 的最后一个参数(译者注: 最后一个参数的设置会覆盖之前的):

$ rustc lib.rs --crate-type=lib -D unused-variables -A unused-variables

您可以通过此举在一组 lints 中覆盖某个特定的 lint 的级别来。以下例子将在 unused 组中所有 lint 设置为 拒绝( denies )级别, 但是将此组中的 unused-variables lint 设置为允许( allows )。 (无论顺序如何,"forbid" 仍然胜过一切):

$ rustc lib.rs --crate-type=lib -D unused -A unused-variables

通过属性

你也可以通过设置一个 crate-wide 属性来修改 lint 的级别:

$ cat lib.rs
#![warn(missing_docs)]

pub fn foo() {}
$ rustc lib.rs --crate-type=lib
warning: missing documentation for crate
 --> lib.rs:1:1
  |
1 | / #![warn(missing_docs)]
2 | |
3 | | pub fn foo() {}
  | |_______________^
  |
note: lint level defined here
 --> lib.rs:1:9
  |
1 | #![warn(missing_docs)]
  |         ^^^^^^^^^^^^

warning: missing documentation for a function
 --> lib.rs:3:1
  |
3 | pub fn foo() {}
  | ^^^^^^^^^^^^

warn, allow, deny, forbid 这四种等级都可以使用这种方式修改。

你还可以为每个属性传递多个 lint :


#![allow(unused)]
#![warn(missing_docs, unused_variables)]

fn main() {
pub fn foo() {}
}

还有一起使用多个属性:


#![allow(unused)]
#![warn(missing_docs)]
#![deny(unused_variables)]

fn main() {
pub fn foo() {}
}

Capping lints

rustc 支持一个标签, --cap-lints LEVEL 用来设置 "lint 级别上限"。即此设置所有的 lint 的最高级别。如下所示, 如果我们采用上面 "deny" lint 级别代码示例:

fn main() {
    100u8 << 10;
}

然后我们编译它, 限制 lints 为 warn 级别:

$ rustc lib.rs --cap-lints warn
warning: bitshift exceeds the type's number of bits
 --> lib.rs:2:5
  |
2 |     100u8 << 10;
  |     ^^^^^^^^^^^
  |
  = note: `#[warn(exceeding_bitshifts)]` on by default

warning: this expression will panic at run-time
 --> lib.rs:2:5
  |
2 |     100u8 << 10;
  |     ^^^^^^^^^^^ attempt to shift left with overflow

现在仅仅只是出现了警告,而不是错误。允许所有的 lint 的话我可以走的更远(译者注:意思是我们可以通过编译继续下去)。

$ rustc lib.rs --cap-lints allow
$

在Cargo中这个特性被使用的很多; 它会在我们编译依赖时设置 --cap-lints allow 命令, 以便在有任何警告信息的时候, 不会影响到我们的构建输出。

Lint Groups

rustc 有个叫做 "lint 组" (Lint Groups) 的概念, 你可以通过一个名称来切换其余几个 lint。

例如, nonstandard-style lint 一次便可设置 non-camel-case-types, non-snake-case, 和 non-upper-case-globals。所以以下两条命令是等价的:

$ rustc -D nonstandard-style
$ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals

这儿有一个包含每个 lint 组,和组成它们的 lint 的列表:

组描述包含的lint
warning所有设置为发出问题警告的 lint请查看本章 warn-by-default
future-incompatible用来检测代码未来兼容性问题的 lintabsolute-paths-not-starting-with-crate, ambiguous-associated-items, anonymous-parameters, array-into-iter, cenum-impl-drop-cast, coherence-leak-check, conflicting-repr-hints, const-evaluatable-unchecked, ill-formed-attribute-input, illegal-floating-point-literal-pattern, indirect-structural-match, invalid-type-param-default, keyword-idents, late-bound-lifetime-arguments, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, mutable-borrow-reservation-conflict, nontrivial-structural-match, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, private-in-public, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, safe-packed-borrows, soft-unstable, tyvar-behind-raw-pointer, uninhabited-static, unstable-name-collisions, where-clauses-object-safety
nonstandard-style违反标准命令约定non-camel-case-types, non-snake-case, non-upper-case-globals
rust-2018-compatibility用来将代码从 Rust 2015向 Rust 2018转移的lintabsolute-paths-not-starting-with-crate, anonymous-parameters, keyword-idents, tyvar-behind-raw-pointer
rust-2018-idioms用来推动你适应Rust 2018惯用features的 lintbare-trait-objects, elided-lifetimes-in-paths, ellipsis-inclusive-range-patterns, explicit-outlives-requirements, unused-extern-crates
rustdocRustdoc 特有的 lintbroken-intra-doc-links, invalid-codeblock-attributes, invalid-html-tags, missing-doc-code-examples, non-autolinks, private-doc-tests, private-intra-doc-links
unused用来检测声明但未使用,或是语法冗余的 lintdead-code, overlapping-patterns, path-statements, redundant-semicolons, unreachable-code, unreachable-patterns, unused-allocation, unused-assignments, unused-attributes, unused-braces, unused-doc-comments, unused-extern-crates, unused-features, unused-imports, unused-labels, unused-macros, unused-must-use, unused-mut, unused-parens, unused-unsafe, unused-variables

另外, bad-style lint 组是 nonstandard-style 组已弃用的别名。

最后,你可以通过调用 rustc -W help 来查看上表,其将为你提供已安装编译器版本对应的 lint组 的确切值。

Lint 清单

本章节列出了所有的 lint,以它们的默认 lint 等级分类。

你也可以通过运行 rustc -W help 查看此清单。

默认等级为允许的 lints

默认情况下,这些 lint 都设置为'allow'级别。因此,除非您使用标志或属性将它们设置为更高的 lint 级别,否则它们将不会显示。

absolute_paths_not_starting_with_crate

absolute_paths_not_starting_with_crate lint 检测完全合乎“路径以模块名称开头”的这个要求,即以 crate , self ,或是以一个 extern crate 名称作为开头。

样例

#![deny(absolute_paths_not_starting_with_crate)]

mod foo {
    pub fn bar() {}
}

fn main() {
    ::foo::bar();
}

显示如下结果:

error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
 --> lint_example.rs:8:5
  |
8 |     ::foo::bar();
  |     ^^^^^^^^^^ help: use `crate`: `crate::foo::bar`
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(absolute_paths_not_starting_with_crate)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
  = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130><br>

解释

Rust 语义版本允许语言向前发展而不破坏其向后兼容性(译者注:向后兼容指的是新版本可以运行旧代码)。此 lint 捕获使用 2015语义版本路径样式的代码。在2015语义版本中,绝对路径(以 :: 开头)指的是(本 crate 的) crate 根 或者是外部 crate 。应该使用 crate::路径前缀指向来自 crate 根的项。

如果在不更新代码的情况下将编译器从2015版切换到2018版,那么如果使用旧样式路径,编译器将无法编译。您可以手动更改路径使用crate:: 前缀过渡到2018版。

该 lint 将自动解决此问题。其等级默认为 “allow” 因为此代码在 2015语义版本中是完全有效的。 cargo fix工具带有的 --edition 标签会将此 lint 的等级切换为 “warn” 并且自动应用编译器的修改建议。这提供了一种将旧代码完全自动升级到 2018语义版本的方法。

anonymous-parameters

此 lint 检测匿名参数。一些触发此 lint 的示例代码:

样例

#![deny(anonymous_parameters)]
// edition 2015
pub trait Foo {
    fn foo(usize);
}
fn main() {}

显示如下结果:

error: anonymous parameters are deprecated and will be removed in the next edition.
 --> lint_example.rs:4:12
  |
4 |     fn foo(usize);
  |            ^^^^^ help: try naming the parameter or explicitly ignoring it: `_: usize`
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(anonymous_parameters)]
  |         ^^^^^^^^^^^^^^^^^^^^
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
  = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>

**解释**

这种语法大多是历史意外,可以通过添加 _ 模式(译者注:通配符)或描述性标识符很轻松地解决:


#![allow(unused)]
fn main() {
trait Foo {
    fn foo(_: usize);
}
}

这个语法现在在2018语义版本中仍是个固有错误(hard error)。在2015语义版本中,因为旧代码依然有效所以这个 lint 默认级别是 “allow” ,并且对所有旧代码应用 warning 可能会带来干扰( noisy )。此 lint 可以通过 cargo fix 工具自带的 --edition 标签自动地将旧代码从 2015 版本转换到 2018版本。该工具将会切换此 lint 的等级为 “warn” 并且自动应用编译器的修改建议(会为每个匿名变量添加 _ )。这提供了一种将旧代码完全自动升级到新语义版本的方法。更多细节请参考 issue #41686。

box-pointers

box_pointers lint 用于 Box 类型。

样例

#![allow(unused)]
#![deny(box_pointers)]
fn main() {
struct Foo {
    x: Box<isize>,
}
}

显示如下结果:

error: type uses owned (Box type) pointers: Box<isize>
 --> lint_example.rs:4:5
  |
4 |     x: Box<isize>,
  |     ^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(box_pointers)]
  |         ^^^^^^^^^^^^

解释

这种 lint 主要是历史性的,并不是特别有用。以前 Box<T>是用于构建语言,以及进行堆分配的唯一方法。今天的 Rust 可以调用其他堆分配器等。

elided-lifetimes-in-paths

elided_lifetimes_in_paths lint 用于检测隐藏生命周期参数。

样例

#![allow(unused)]
#![deny(elided_lifetimes_in_paths)]
fn main() {
struct Foo<'a> {
    x: &'a u32
}

fn foo(x: &Foo) {
}
}

显示如下结果:

error: hidden lifetime parameters in types are deprecated
 --> lint_example.rs:7:12
  |
7 | fn foo(x: &Foo) {
  |            ^^^- help: indicate the anonymous lifetime: `<'_>`
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(elided_lifetimes_in_paths)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^

解释

省略的生命周期参数可能使您一眼就看不到发生了借用。该 lint 确保生命周期参数总是被显式指出,即便是_ 占位符的生命周期。

该 lint 默认情况下是 “allow” 级别,因为其有一些已知的问题,并且可能需要对旧代码进行重大的转换。

explicit-outlives-requirements

explicit_outlives_requirements lint 检测指出不必要的生命周期约束(bounds)。

样例


#![allow(unused)]
fn main() {
#![allow(unused)]
#![deny(explicit_outlives_requirements)]

struct SharedRef<'a, T>
where
    T: 'a,
{
    data: &'a T,
}
}

显示如下结果:

error: outlives requirements can be inferred
 --> lint_example.rs:5:24
  |
5 |   struct SharedRef<'a, T>
  |  ________________________^
6 | | where
7 | |     T: 'a,
  | |__________^ help: remove this bound
  |
note: the lint level is defined here
 --> lint_example.rs:2:9
  |
2 | #![deny(explicit_outlives_requirements)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

解释

如果结构体包含引用,例如 &'a T,编译器要求 T 的生命周期长度比 'a 更久。以往要求写上明确的生命周期约束( bound )来此满足此条件。然而,这可能过于明显,且会导致混乱和不必要的复杂性。语言已经改进为如果没有指定则会自动推断约束。具体举例来说,如果结构体包含引用,直接或间接地包含 T 和生命周期 'x ,则它会自动推断要求(requirement) T: 'x。

默认情况下该 lint 级别为 “allow”,因为可能会对现有的已经具有这些要求的代码产生干扰。这是一种风格选择,因为明确的约束声明依然是有效的。它依然具有一些可能会引起混乱的误报。

invalid-html-tags

invalid_html_tags lint 检测无效的 HTML 标签。这是一个仅用于 rustdoc 的 lint ,请参阅 rustdoc book中的文档。

keyword-idents

keyword-idents lint 检测被用作标识符的版本关键字。

样例

#![allow(unused)]
#![deny(keyword_idents)]
fn main() {
// edition 2015
fn dyn() {}
}

显示如下结果:

error: `dyn` is a keyword in the 2018 edition
 --> lint_example.rs:4:4
  |
4 | fn dyn() {}
  |    ^^^ help: you can use a raw identifier to stay compatible: `r#dyn`
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(keyword_idents)]
  |         ^^^^^^^^^^^^^^
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
  = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

解释

Rust 语义版本允许语言向前发展而不破坏其向后兼容性。此 lint 捕获代码中的被用作标识符(例如变量名、函数名等等)的新增关键。如果你没有更新代码就切换编译器到一个新语义版本,就会在你将新关键字作为标识符的情况下编译失败。

可以手动将标识符改为非关键字,或者使用原始标识符,例如r#dyn,来过渡到新版本。

该 lint 可自动解决该问题,其默认为 “allow”等级,因为该代码在旧版本中完全有效。cargo fix工具自带的--edition标签会将此 lint 的等级切换为 “warn” ,并自动应用编译器建议的修复(即使用原始标识符)。这提供了一种完全自动化的方法来将旧代码更新到新版本。

macro-use-extern-crate

macro-use-extern-crate lint 用于检测 macro_use属性的使用

样例

#![deny(macro_use_extern_crate)]

#[macro_use]
extern crate serde_json;

fn main() {
    let _ = json!{{}};
}

显示如下:

error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
 --> src/main.rs:3:1
  |
3 | #[macro_use]
  | ^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> src/main.rs:1:9
  |
1 | #![deny(macro_use_extern_crate)]
  |         ^^^^^^^^^^^^^^^^^^^^^^

解释

macro_use属性放在 extern crate 项上使其宏可被使用,而这个外部 crate 可能会被放进该 crate 的路径前缀,导致导入宏在作用域内无处不在。在 2018 版本中致力于简化依赖项的处理,extern crate 的使用已经淘汰了。要将宏从外部 crate 导入作用域,建议使用 use 导入。

meta_variable_misuse

meta_variable_misuse lint 检测宏定义中可能存在的元变量滥用。

样例

#![deny(meta_variable_misuse)]

macro_rules! foo {
    () => {};
    ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
}

fn main() {
    foo!();
}

显示如下:

error: unknown macro variable `k`
 --> lint_example.rs:5:55
  |
5 |     ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
  |                                                       ^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(meta_variable_misuse)]
  |         ^^^^^^^^^^^^^^^^^^^^

解释

macro_rules宏有许多不恰当的定义方式,这些错误以前只有在宏被展开或根本不( not at all )展开时才能才能检测得到。该 lint 尝试在当定义了宏的时候捕获一些问题。 该 lint 默认等级是 “allow”的,因为其有误报或其他问题。更多细节请参阅 issue #61053。

missing_copy_implementations

missing_copy_implementations lint 检测潜在的忘记实现 Copy trait。

样例

#![deny(missing_copy_implementations)]
pub struct Foo {
    pub field: i32
}
fn main() {}

显示如下:

error: type could implement `Copy`; consider adding `impl Copy`
 --> lint_example.rs:2:1
  |
2 | / pub struct Foo {
3 | |     pub field: i32
4 | | }
  | |_^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(missing_copy_implementations)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

解释

1.0版本以前,类型会被尽可能自动标记为 Copy。后面对此进行了更改,并要求实现 Cpoy trait 来明确选择添加此 trait。此更改的一部分内容是,如果未为一个可复制类型标记 Copy,一个 lint 会发出警告。

该 lint 默认等级是 “allow” 因为其代码并不算糟糕;为了使一个 Cpoy 类型不再 Cpoy(译者注:即不触发该类型实现的Copy trait那部分代码)而创建新类型(newtypes)是相当常见的,Cpoy类型可能会导致意外地复制大量影响性能的数据。

missing_crate_level_docs

missing_crate_level_docs lint 检测 crate 根是否缺失其文档。这是一个仅用于 rustdoc 的 lint,请参阅 rustdoc book中的文档。

missing_debug_implementations

missing_debug_implementations lint 检测 fmt::Debug 的缺失。

样例

#![deny(missing_debug_implementations)]
pub struct Foo;
fn main() {}

显示如下:

error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation
 --> lint_example.rs:2:1
  |
2 | pub struct Foo;
  | ^^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(missing_debug_implementations)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

解释

在类型上实现 Debug 有助于调试。因为它提供了个格式化和显示值的便捷方法。 使用 #[derive(Debug)] 属性会自动生成一个典型实现,或者手动实现该 Debug trait 添加自定义实现。

该 lint 默认等级为 “allow” ,因为添加 Debug 到所有类型可能会对编译时长和代码体积产生负面作用。它还要求对每种类型都添加样板,这有时会是种(编码上的)阻碍。

missing_doc_code_examples

missing_doc_code_examples lint 检测文档中缺失代码样例的公开导出项。这是一个仅用于 rustdoc 的 lint,请参阅 rustdoc book 中的文档。

missing_docs

missing_docs lint 检测缺失文档的公有项目。(译者注:missing_docs 与 missing_doc_code_examples ,一个检测有没有,一个检测文档有没有代码样例)

样例

#![allow(unused)]
#![deny(missing_docs)]
fn main() {
pub fn foo() {}
}

显示如下:

error: missing documentation for the crate
 --> lint_example.rs:1:1
  |
1 | / #![deny(missing_docs)]
2 | | fn main() {
3 | | pub fn foo() {}
4 | | }
  | |_^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(missing_docs)]
  |         ^^^^^^^^^^^^

解释

该 lint 旨在确保一个库有良好的文档记录。没有文档的项目对于用户来说很难理解如何正确使用。 该lint 默认等级是 “allow”是因为其可能会造成干扰,并且不是所有项目都需要强制将一切用文档记录。

non_ascii_idents

non_ascii_idents lint 检测非 ascii 标识符。

样例

#![allow(unused)]
#![feature(non_ascii_idents)]
#![deny(non_ascii_idents)]
fn main() {
    let föö = 1;
}

显示如下:

error: identifier contains non-ASCII characters
 --> lint_example.rs:5:9
  |
5 |     let föö = 1;
  |         ^^^
  |
note: the lint level is defined here
 --> lint_example.rs:3:9
  |
3 | #![deny(non_ascii_idents)]
  |         ^^^^^^^^^^^^^^^^

解释

在稳定版的 Rust 上,标识符必须包含 ASCII 字符。 non_ascii_idents 只在 nightly feature 允许标识符包含非 ASCII 字符。该 lint 允许项目希望切换该 lint 等级为 “forbid” 以保持只使用 ASCII 字符的限制(例如,简化协作或是为了安全)。更多细节请参阅 RFC 2457。

pointer_structural_match

pointer_structural_match lint 检测那些在不同编译器版本和优化级别依赖上不能用于模式中的指针。

样例

#![deny(pointer_structural_match)]
fn foo(a: usize, b: usize) -> usize { a + b }
const FOO: fn(usize, usize) -> usize = foo;
fn main() {
    match FOO {
        FOO => {},
        _ => {},
    }
}

显示如下:

error: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
 --> lint_example.rs:6:9
  |
6 |         FOO => {},
  |         ^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(pointer_structural_match)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>

解释

早期 Rust 版本允许在模式中使用函数指针和泛(wide)原始指针。尽管许多情况下可以按用户期望的方式运行,但由于编译器进行优化,在运行时,指针可能已经 “不等于自身” 或者是指向不同函数的函数指针相等。这是因为如果函数体相等, LLVM 会优化掉重复函数(译者注:即保留一个),因此也会使得这些指向他们的函数指针指向同一位置。另外,如果重复的函数在不同 crate 中,且又没有通过 LTO 进行优化(删除相同代码数据),那么就会造成重复。

private_doc_tests

private_doc_tests lint 检测私有项中的文档测试。这是个只用在 rustdoc 中的 lint,请参阅 rustdoc book 中的文档。

single_use_lifetimes

single_use_lifetimes lint 检测只使用一次的生命期。 样例

#![allow(unused)]
#![deny(single_use_lifetimes)]

fn main() {
fn foo<'a>(x: &'a u32) {}
}

显示如下:

error: lifetime parameter `'a` only used once
 --> lint_example.rs:4:8
  |
4 | fn foo<'a>(x: &'a u32) {}
  |        ^^      -- ...is used only here
  |        |
  |        this lifetime...
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(single_use_lifetimes)]
  |         ^^^^^^^^^^^^^^^^^^^^
help: elide the single-use lifetime
  |
4 | fn foo(x: &u32) {}
  |      --   --

解释

显式指定一个生命周期,例如在函数或 impl 中的 'a应该用来链接这两者。否则,应该使用 '_ 表明生命周期并未链接到两者,或者如果有可能的话干脆直接省略生命周期。

该 lint 默认等级为 “allow” ,因为它是在 '_ 和省略生命周期第一次被引入的时候引入的,而且这个 lint 可能会有很多干扰( too noisy )。此外,它还会产生一些已知的误报,了解历史内容请参阅 RFC 2115,更多细节请参阅 issue #44752

trivial_casts

trivial_casts lint 检测可以被强制类型转换替代的平凡类型转换,这可能需要类型归因(type ascription)或临时变量。

样例


#![allow(unused)]
#![deny(trivial_casts)]
fn main() {
let x: &u32 = &42;
let y = x as *const u32;
}

显示如下:

error: trivial cast: `&u32` as `*const u32`
 --> lint_example.rs:4:9
  |
4 | let y = x as *const u32;
  |         ^^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(trivial_casts)]
  |         ^^^^^^^^^^^^^
  = help: cast can be replaced by coercion; this might require a temporary variable

解释

平凡类型转换是一种 e 含有 U 类型,而且 U 是 T 的一个子类型的 e as T 转换。这种类型转换通常是不必要的,其通常可以被推断出来。

该 lint 默认等级为 “allow” ,因为在某些情况下,例如 FFI 接口或者是 复杂类型别名,可能会被不正确地触发,或者是在一些难以表达清楚意图的情况下。在未来它可能会成为一个 警告(warning),可能会因为类型归因提供了一种解决当前问题的方法。历史内容请参阅 RFC 401

trivial_numeric_casts

trivial_numeric_casts lint 检测可能已经被移除的平凡数值类型转换。

样例

#![allow(unused)]
#![deny(trivial_numeric_casts)]
fn main() {
let x = 42_i32 as i32;
}

显示如下:

error: trivial numeric cast: `i32` as `i32`
 --> lint_example.rs:3:9
  |
3 | let x = 42_i32 as i32;
  |         ^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(trivial_numeric_casts)]
  |         ^^^^^^^^^^^^^^^^^^^^^
  = help: cast can be replaced by coercion; this might require a temporary variable

解释

平凡数值类型转换指的是将数值类型转换为相同数值类型的转换。这种转换通常是不必要的。

该 lint 默认等级为 “allow” ,因为在某些情况下,例如 FFI 接口或者是 复杂类型别名,可能会被不正确地触发,或者是在一些难以表达清楚意图的情况下。在未来它可能会成为一个 警告(warning),可能会因为类型归因提供了一种解决当前问题的方法。历史内容请参阅 RFC 401

unaligned_references

unaligned_references lint 检测对包装结构体字段的未对齐引用。

样例

#![deny(unaligned_references)]

#[repr(packed)]
pub struct Foo {
    field1: u64,
    field2: u8,
}

fn main() {
    unsafe {
        let foo = Foo { field1: 0, field2: 0 };
        let _ = &foo.field1;
    }
}

显示如下:

error: reference to packed field is unaligned
  --> lint_example.rs:12:17
   |
12 |         let _ = &foo.field1;
   |                 ^^^^^^^^^^^
   |
note: the lint level is defined here
  --> lint_example.rs:1:9
   |
1  | #![deny(unaligned_references)]
   |         ^^^^^^^^^^^^^^^^^^^^
   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)

解释

创建对未充分对其的包装字段的引用是一种未定义的行为并且应该被禁止。 默认情况下,此 lint 等级为 “allow” ,因为没有稳定的替代方法,并且尚不确定现有代码将如何触发此 lint 。有关更多讨论请参阅 issue #27060 。

unreachable_pub

unreachable_pub lint 被无法从 crate 根到达的 pub 项所触发。

样例

#![allow(unused)]
#![deny(unreachable_pub)]
fn main() {
mod foo {
    pub mod bar {

    }
}
}

显示如下:

error: unreachable `pub` item
 --> lint_example.rs:4:5
  |
4 |     pub mod bar {
  |     ---^^^^^^^^
  |     |
  |     help: consider restricting its visibility: `pub(crate)`
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(unreachable_pub)]
  |         ^^^^^^^^^^^^^^^
  = help: or consider exporting it for use by other crates

解释

一个裸( bare ) pub 项的可见性可能会因为该项无法从 crate 导出而被误导。该 pub(crate) 可见性建议用可见性仅在其自身 crate 这种清晰的表达来替代。

默认情况下,此 lint 等级为 “allow” ,因为它会被大量现有的 Rust 代码触发,并且会有一些误报。最终我们希望它成为一个默认警告。

unsafe_code

unsafe_code lint 捕捉 unsafe 代码的使用。

样例

#![deny(unsafe_code)]
fn main() {
    unsafe {

    }
}

显示如下:

error: usage of an `unsafe` block
 --> lint_example.rs:3:5
  |
3 | /     unsafe {
4 | |
5 | |     }
  | |_____^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(unsafe_code)]
  |         ^^^^^^^^^^^

解释

该 lint 意在限制 unsafe 的使用,这很难被正确使用。(译者注:此处的“很难被正确使用”,一者指的是 unsafe 代码的不安全操作,一者指的是对 unsafe 代码的严格限制 lint 很难说是正确的)。

unsafe_op_in_unsafe_fn

unsafe_op_in_unsafe_fn lint 检测非 unsafe 块中 unsafe 函数中的 unsafe 操作。该 lint 仅在 nightly 通道( nightly channel )中使用#![feature(unsafe_block_in_unsafe_fn)]时有效。

样例

#![feature(unsafe_block_in_unsafe_fn)]
#![deny(unsafe_op_in_unsafe_fn)]

unsafe fn foo() {}

unsafe fn bar() {
    foo();
}

fn main() {}

显示如下:

error: call to unsafe function is unsafe and requires unsafe block (error E0133)
 --> lint_example.rs:7:5
  |
7 |     foo();
  |     ^^^^^ call to unsafe function
  |
note: the lint level is defined here
 --> lint_example.rs:2:9
  |
2 | #![deny(unsafe_op_in_unsafe_fn)]
  |         ^^^^^^^^^^^^^^^^^^^^^^
  = note: consult the function's documentation for information on how to avoid undefined behavior

解释

当前,unsafe 函数允许在其中进行任何的 unsafe 操作。然而,这可能会因为需要对代码行为进行适当仔细的检查而增加代码体积。 unsafe 块 提供了一种简便的,可以清楚说明代码的哪部分正在进行 unsafe 操作。在未来,我们希望修改它以便不能在一个非 unsafe 块的 unsafe 函数中执行 unsafe 操作。

解决此问题的方法是将将此 unsafe 代码包装进 unsafe 块中。

该 lint 默认等级为 “allow” ,因为其尚未稳定,也尚未完成。更多细节请参阅 RFC #2585 和 issue #71668。

unstable_features

unstable_features lint 已被废弃,不应再使用。

unused_crate_dependencies

unused_crate_dependencies lint 检测未被使用的 crate 依赖。

样例

#![deny(unused_crate_dependencies)]

显示如下:

error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;`
  |
note: the lint level is defined here
 --> src/lib.rs:1:9
  |
1 | #![deny(unused_crate_dependencies)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^

解释

将使用了依赖项的代码移除之后,通常需要从构建配置中删除依赖。然而,有时可能会忘记这一步,导致浪费时间来构建不再使用的依赖项。该 lint 可以被用来检测从未使用的依赖项(更具体地说,那些从未被 use , extern crate ,或者任何路径指向的,通过 --extern命令行标签指定的依赖)

该 lint 默认等级为 “allow” ,因为根据构建系统的配置不同可能会产生误报。例如,当使用 Cargo 时,一个 “包”(“package”)包含了多个 crate (例如一个库 crate 和一个二进制 crate ),但是这个包的依赖是为整体而定义的,如果有一个依赖仅在二进制 crate 中使用,在库 crate 中未使用,那么该 lint 将会在库(译者注:在库 crate 运行的时候)错误地被发出。

unused_extern_crates

unused_extern_crates lint 防止从未被使用的 extern crate 项。

样例

#![allow(unused)]
#![deny(unused_extern_crates)]
fn main() {
extern crate proc_macro;
}

显示如下:

error: unused extern crate
 --> lint_example.rs:3:1
  |
3 | extern crate proc_macro;
  | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(unused_extern_crates)]
  |         ^^^^^^^^^^^^^^^^^^^^

解释

未使用的 extern crate 项是无效的应该被删除。请注意,在某些情况下,需要指定 extern crate 以确保他们被 crate 所链接,即使没有直接引用它。可以通过为 crate 取一个下划线别名来消除检测,例如 extern crate foo as _。还要注意的是 extern crate 在 2018 语义版本中已经不常用,因为现在外部 crate(译者注:被指定的)会被自动添加到域中。

该 lint 默认等级为 “allow” ,因为其可能会造成干扰和误报。如果要从项目中移除依赖,推荐在构建配置中将其删除(例如 Cargo.toml)确保编译时不会留下陈旧的构建条目。

unused_import_braces

unused_import_braces lint 捕捉导入项中不必要的大括号。

样例

#![deny(unused_import_braces)]
use test::{A};

pub mod test {
    pub struct A;
}
fn main() {}

显示如下:

error: braces around A is unnecessary
 --> lint_example.rs:2:1
  |
2 | use test::{A};
  | ^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(unused_import_braces)]
  |         ^^^^^^^^^^^^^^^^^^^^

解释

如果仅有单个项,应该移除大括号(例如 use test::A;)。

该 lint 默认等级为 “allow” ,因为其只是强制执行样式选择。

unused_lifetimes

unused_lifetimes lint 检测未使用的生命周期参数。

样例

#![allow(unused)]
fn main() {
#[deny(unused_lifetimes)]

pub fn foo<'a>() {}
}

显示如下:

error: lifetime parameter `'a` never used
 --> lint_example.rs:4:12
  |
4 | pub fn foo<'a>() {}
  |           -^^- help: elide the unused lifetime
  |
note: the lint level is defined here
 --> lint_example.rs:2:8
  |
2 | #[deny(unused_lifetimes)]
  |        ^^^^^^^^^^^^^^^^

解释

未使用的生命周期参数可能是个错误或是代码未完成。(译者注:如果是错误)应该考虑删除该参数

unused_qualifications

unused_qualifications lint 检测不必要的限定名。

样例

#![deny(unused_qualifications)]
mod foo {
    pub fn bar() {}
}

fn main() {
    use foo::bar;
    foo::bar();
}

显示如下:

error: unnecessary qualification
 --> lint_example.rs:8:5
  |
8 |     foo::bar();
  |     ^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(unused_qualifications)]
  |         ^^^^^^^^^^^^^^^^^^^^^

解释

如果来自另一个模块的项已经被导入了这个域,在这种情况下无需为该项加限定名,你可以不加 foo:: 直接调用 bar()。

该 lint 默认等级为 “allow” ,因为这有些花哨( pedantic ),并不表示实际问题,而且是一种风格选择,并且当重构或移动代码的时候可能会带来干扰。

unused_results

unused_results lint 检查语句中表达式未使用的 result 。

样例

#![deny(unused_results)]
fn foo<T>() -> T { panic!() }

fn main() {
    foo::<usize>();
}

显示如下:

error: unused result
 --> lint_example.rs:5:5
  |
5 |     foo::<usize>();
  |     ^^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(unused_results)]
  |         ^^^^^^^^^^^^^^

解释

忽略的函数返回值可能会指出一个错误。在可以确定使用 result 的情况下推荐使用 must_use属性来注解函数。如果不使用此类返回值将会触发默认为警告级别的 unused_must_use lint。unused_results lint 本质上是一样的,但是其被所有的返回值触发。

该 lint 默认等级为 “allow” ,因为其可能会带来干扰,且可能并不是一个真正的问题。例如,调用 Vec 或 HashMap 的 remove 方法会返回先前的值(译者注:也就是已经被 remove 的那个值),你可能并不关心这个值,使用这个 lint 将会要求显式地忽略或丢弃这些值。

variant_size_differences

variant_size_differences lint 检测具有不同变量大小的枚举。

样例

#![allow(unused)]
#![deny(variant_size_differences)]
fn main() {
enum En {
    V0(u8),
    VBig([u8; 1024]),
}
}

显示如下:

error: enum variant is more than three times larger (1024 bytes) than the next largest
 --> lint_example.rs:5:5
  |
5 |     VBig([u8; 1024]),
  |     ^^^^^^^^^^^^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(variant_size_differences)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^

解释

向枚举中添加一个比其他变量大得多的变量可能是个错误,这会增加所有变量所需空间的总大小。这可能会影响性能和内存使用。如果第一大的变量比第二大的变量所需空间大三倍以上,就会触发这个 lint。

可以考虑将较大变量的内容放在堆上(例如通过 Box ),以保持枚举体自身大小处于较小量值 。

该 lint 默认等级为 “allow” ,因为其可能会造成干扰,且可能并不是一个真正的问题。应通过基准测试和分析指导来考虑这个问题。

Warn-by-default lints

这些 lint 的默认等级被设置为 “警告”。

array_into_iter

`` lint 检测数组中调用 into_iter。

样例

#![allow(unused)]
fn main() {
#![allow(unused)]
[1, 2, 3].into_iter().for_each(|n| { *n; });
}

显示如下:

warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
 --> lint_example.rs:3:11
  |
3 | [1, 2, 3].into_iter().for_each(|n| { *n; });
  |           ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
  |
  = note: `#[warn(array_into_iter)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>

解释
在将来计划为数组添加一个 IntoIter 实现,这样的话它将遍历的是数组的值而不是引用。由于方法解析的工作方式,这将改变在数组上使用 into_iter 的那部分现有代码。避免此警告的办法是使用 iter() 而不是 into_iter()。

这是个将来不兼容 的 lint ,将来会转化为固有错误(hard error)。更多细节和更全面的 关于此 int 的描述请参阅 issue #66145。

asm_sub_register

asm_sub_register lint 检测仅使用寄存器子集进行内联汇编输入。

样例

#![feature(asm)]

fn main() {
    #[cfg(target_arch="x86_64")]
    unsafe {
        asm!("mov {0}, {0}", in(reg) 0i16);
    }
}

显示如下:

warning: formatting may not be suitable for sub-register argument
 --> src/main.rs:6:19
  |
6 |         asm!("mov {0}, {0}", in(reg) 0i16);
  |                   ^^^  ^^^           ---- for this argument
  |
  = note: `#[warn(asm_sub_register)]` on by default
  = help: use the `x` modifier to have the register formatted as `ax`
  = help: or use the `r` modifier to keep the default formatting of `rax`

解释

一些体系结构上的寄存器可以使用不同的名称来引用寄存器的一个子集。默认情况下,编译器会使用该名称来表示整个寄存器大小。想要显式使用寄存器子集,可以通过模板字符串操作数上使用修饰符来指定何时使用子寄存器来覆盖默认值。如果传入的数据类型小于默认寄存器大小的值,就出触发此 lint,以警告你可能使用了错误的(位)宽度。要想修复此问题,向模板添加建议的修饰符,或者或者将值转为正确的大小。

更多细节请参阅寄存器模板修饰符。

bare_trait_objects

bare_trait_objects lint 暗示为 trait 对象使用 dyn Trait 。

样例

#![allow(unused)]
fn main() {
trait Trait { }

fn takes_trait_object(_: Box<Trait>) {
}
}

显示如下:

warning: trait objects without an explicit `dyn` are deprecated
 --> lint_example.rs:4:30
  |
4 | fn takes_trait_object(_: Box<Trait>) {
  |                              ^^^^^ help: use `dyn`: `dyn Trait`
  |
  = note: `#[warn(bare_trait_objects)]` on by default

解释

没有 dyn 关键字,当阅读代码时你是否是在查看 trait 对象这可能会造成模棱两可或困惑。dyn 关键字将其明确,并且添加了对称性来与 impl Trait对比。

bindings_with_variant_name

bindings_with_variant_name lint 检测与匹配变量之一同名的模式绑定。

样例

#![allow(unused)]
fn main() {
pub enum Enum {
    Foo,
    Bar,
}

pub fn foo(x: Enum) {
    match x {
        Foo => {}
        Bar => {}
    }
}
}

显示如下:

warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Enum`
 --> lint_example.rs:9:9
  |
9 |         Foo => {}
  |         ^^^ help: to match on the variant, qualify the path: `Enum::Foo`
  |
  = note: `#[warn(bindings_with_variant_name)]` on by default

解释

将枚举变量名称指定为标识符模式通常是个错误。在上例中,match 分支指定了变量名来绑定 x 。 第二个分支被忽略,因为第一个分支匹配到了所有的值。可能的意图是第一个分支意在匹配枚举变量。

两个可能的解决办法是: + 使用[路径模式][path-pattern]指定枚举变量,例如 Enum::Foo。 + 将枚举变量引入本地作用域,例如上例在 foo 函数的开头添加 use Enum::*; 。 [path-pattern]:https://doc.rust-lang.org/reference/patterns.html#path-patterns

broken_intra_doc_links lint 检测解析内部文档链接目标失败。这是一个仅用于 rustdoc 的lint,请查看 rustdoc book中的文档。

cenum_impl_drop_cast

cenum_impl_drop_cast lint 检测实现了 Drop trait 的无字段(field-less)枚举体 的 as 强制转换。

样例

#![allow(unused)]
enum E {
    A,
}

impl Drop for E {
    fn drop(&mut self) {
        println!("Drop");
    }
}

fn main() {
    let e = E::A;
    let i = e as u32;
}

显示如下:

warning: cannot cast enum `E` into integer `u32` because it implements `Drop`
  --> lint_example.rs:14:13
   |
14 |     let i = e as u32;
   |             ^^^^^^^^
   |
   = note: `#[warn(cenum_impl_drop_cast)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #73333 <https://github.com/rust-lang/rust/issues/73333>

解释

将未实现整数的 Copy 的无字段枚举体将移动值而不调用 drop 。如果期望是调用 drop,这可能会导致令人惊讶的行为。自动调用 drop 将与其他操作不同。由于两种行为都不是清晰或一致,因此决定不允许这种性质的转换。

这是个将来不兼容 的 lint ,将来会转化为固有错误(hard error)。更多细节请参阅 issue #73333。

clashing_extern_declarations

clashing_extern_declarations lint 检测当同名 extern fn 被声明但是不同类型的情况。

样例

#![allow(unused)]
fn main() {
mod m {
    extern "C" {
        fn foo();
    }
}

extern "C" {
    fn foo(_: u32);
}
}

显示如下:

warning: `foo` redeclared with a different signature
 --> lint_example.rs:9:5
  |
4 |         fn foo();
  |         --------- `foo` previously declared here
...
9 |     fn foo(_: u32);
  |     ^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
  |
  = note: `#[warn(clashing_extern_declarations)]` on by default
  = note: expected `unsafe extern "C" fn()`
             found `unsafe extern "C" fn(u32)`

解释

因为在链接中不能将同名符号(symbols)解析为两个不同的函数,且一个函数不能有两个类型,一个相冲突的外部声明可以肯定是个错误。检查以确保 extern 定义正确且有效,且考虑将它们统一在一个位置。

该 lint 不能跨 crate 运行因为一个项目可能有依赖于相同外部函数的依赖项,但是外部函数以不同(但有效)的方式声明。例如,它们可能都为一个或多个参数声明一个不透明类型(opaque type) (最终会得到不同的类型),或者使用 extern fn 定义的语言中有效的转换类型,在这些情况下,编译器不能说冲突声明(clashing declaration)不正确。

coherence_leak_check

coherence_leak_check lint 检测仅能由旧版泄露检查代码(the old leak-check code)区分的 trait 的冲突实现。

样例

#![allow(unused)]
fn main() {
trait SomeTrait { }
impl SomeTrait for for<'a> fn(&'a u8) { }
impl<'a> SomeTrait for fn(&'a u8) { }
}

显示如下:

warning: conflicting implementations of trait `main::SomeTrait` for type `for<'a> fn(&'a u8)`:
 --> lint_example.rs:4:1
  |
3 | impl SomeTrait for for<'a> fn(&'a u8) { }
  | ------------------------------------- first implementation here
4 | impl<'a> SomeTrait for fn(&'a u8) { }
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a u8)`
  |
  = note: `#[warn(coherence_leak_check)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #56105 <https://github.com/rust-lang/rust/issues/56105>
  = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details

解释

过去编译器接受相同功能但唯一不同是生命周期绑定器(lifetime binder)出现的位置的 trait 实现。由于借用检查器的更改实现了多个 bug 的修复,因此不再允许该行为。然而,因为这会影响现有代码,所以这是个将来不兼容 的 lint ,将来会转化为固有错误(hard error)。 依赖此模式的代码应引入 "newtypes",例如 struct Foo(for<'a> fn(&'a u8)) 。

更多细节请参阅 issue #56105。

confusable_idents

confusable_idents lint 检测容易混淆的标识符对。

样例

#![allow(unused)]
#![feature(non_ascii_idents)]

fn main() {
// Latin Capital Letter E With Caron
pub const Ě: i32 = 1;
// Latin Capital Letter E With Breve
pub const Ĕ: i32 = 2;
}

显示如下:

warning: identifier pair considered confusable between `Ě` and `Ĕ`
 --> lint_example.rs:7:11
  |
5 | pub const Ě: i32 = 1;
  |           - this is where the previous identifier occurred
6 | // Latin Capital Letter E With Breve
7 | pub const Ĕ: i32 = 2;
  |           ^
  |
  = note: `#[warn(confusable_idents)]` on by default
  

解释

上面的 non_ascii_idents 是只能用于 nightly的,其允许使用非 ASCII 字符作为标识符。该 lint 当不同标识符看起来很像的时候发出警告,因为(长得像)这可能会令人困惑。

混淆检测的算法是基于 Unicode® Technical Standard #39 Unicode Security Mechanisms Section 4 Confusable Detection 。对每个不同的标识符 X 执行 skelenton(X) 函数。如果在一个 crate 中存在两个不同的标识符 X 和 Y 但是却得到 skeleton(X) = skeleton(Y) (就会触发警告)。编译器用与此相同的机制来检查标识符与关键字相似。

请注意,易混淆字符集可能会随时间而变化。注意,如果你将该 lint 等级调整为 “禁止”,则现有代码可能在将来会(编译)失败。

const_evaluatable_unchecked

const_evaluatable_unchecked lint 检测类型中使用的泛型常量。

样例

#![allow(unused)]
fn main() {
const fn foo<T>() -> usize {
    if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T
        4
    } else {
        8
    }
}

fn test<T>() {
    let _ = [0; foo::<T>()];
}
}

显示如下:

warning: cannot use constants which depend on generic parameters in types
  --> lint_example.rs:11:17
   |
11 |     let _ = [0; foo::<T>()];
   |                 ^^^^^^^^^^
   |
   = note: `#[warn(const_evaluatable_unchecked)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>

解释

在 1.43 发行版本,会意外地允许在数组重复表达式中使用泛型参数。这是个将来不兼容 的 lint ,将来会转化为固有错误(hard error)。更多细节描述和可能的修复请参阅 issue #76200 。

const_item_mutation

const_item_mutation lint 检测试图更改 const 项。

样例

const FOO: [i32; 1] = [0];

fn main() {
    FOO[0] = 1;
    // This will print "[0]".
    println!("{:?}", FOO);
}

显示如下:

warning: attempting to modify a `const` item
 --> lint_example.rs:4:5
  |
4 |     FOO[0] = 1;
  |     ^^^^^^^^^^
  |
  = note: `#[warn(const_item_mutation)]` on by default
  = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified
note: `const` item defined here
 --> lint_example.rs:1:1
  |
1 | const FOO: [i32; 1] = [0];
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^

解释

试图直接更改 const 项几乎总是个错误。上例中发生的是临时的 const 副本被改变,但是原本的 const 并没有改变。每次通过名称来引用 const(例如上例中的 FOO)时,该值的一个单独副本都会内联到该位置。 该 lint 检查直接写入字段(FOO.field = some_value) 或数组输入(FOO[0] = val),或对 const 进行可变引用(&mut FOO),包括通过自动解引用(FOO.some_mut_self_method())。

以下有多种选择取决于你想要完成的方式: + 首先,总是重新考虑是否使用可变全局变量,因为它们可能很难正确使用,而且会使得代码更难以使用或理解。 + 如果你试图对一个全局变量进行一次性初始化:

  • 如果想要该值可以在编译器计算,请考虑使用常量兼容(const-compatible)的值(请参阅常量值计算 )。
  • 对于更复杂的单次初始化(single-intialization),可以考虑使用第三方 crate ,例如 lazy_static或 once_cell 。
  • 如果你在使用 nightly channel,考虑使用标准库中的新 lazy 模块。
  • 如果确实需要可变的全局变量,请考虑使用具有多种选择的 static 。
    • 可以直接定义简单数据类型并可用 原子类型进行转变。
    • 更复杂的类型可以放在如 mutex 之类的同步原语中,可以使用上面列出的选项之一对其进行初始化。
    • 可变静态变量 是低级原语,要求使用 unsafe。通常情况下应该避免该情况,使用上述之一。

dead_code

dead_code lint 检测未使用,未导出的代码。

样例

#![allow(unused)]
fn main() {
fn foo() {}
}

显示如下:

warning: function is never used: `foo`
 --> lint_example.rs:2:4
  |
2 | fn foo() {}
  |    ^^^
  |
  = note: `#[warn(dead_code)]` on by default

解释

Dead code 表示错误或未完成的代码。要使单个项的警告静默,在名称前加上下划线例如 _foo。如果打算将项导出 crate 之外,考虑添加可见修饰符如 pub 。否则请考虑移除未使用的代码。

deprecated

deprecated lint 检测不推荐使用的项。

样例

#![allow(unused)]
fn main() {
#[deprecated]
fn foo() {}

fn bar() {
    foo();
}
}

显示如下:

warning: use of deprecated function `main::foo`
 --> lint_example.rs:6:5
  |
6 |     foo();
  |     ^^^
  |
  = note: `#[warn(deprecated)]` on by default

解释

项可以被标记为 “被遗弃的”,通过 deprecated 属性指明不该再使用。通常该属性应包含如何使用替换的提示或者检查文档。

drop_bounds

drop_bounds lint 检查使用 std::ops::Drop 作为约束的泛型。

样例

#![allow(unused)]
fn main() {
fn foo<T: Drop>() {}
}

显示如下:

warning: bounds on `T: Drop` are useless, consider instead using `std::mem::needs_drop` to detect if a type has a destructor
 --> lint_example.rs:2:11
  |
2 | fn foo<T: Drop>() {}
  |           ^^^^
  |
  = note: `#[warn(drop_bounds)]` on by default

解释

Drop 约束并没有真正完成(accomplish)任何事。一个类型可能由编译器生成 drop 而没有实现 Drop trait 本身。Drop trait 也只有一个方法 Drop::drop ,而且该函数在用户代码中不可调用。所以实际上没有实际使用 Drop trait 的用例。

drop trait 最有可能的用例是区分有析构函数和没有析构函数的类型。结合泛型特化,初级程序员会编写一个实现并认为类型会被简单 drop,然后为 T:Drop 写了泛型特化 实际上调用了析构函数。实际上这是不正确的,例如,String 实际上并没有实现 Drop,但因为 String 包含 Vec,假设其可以被简单丢弃将会造成内存泄漏。

ellipsis_inclusive_range_patterns

ellipsis_inclusive_range_patterns lint 检测 ... 这种已经被遗弃的范围模式。

样例

#![allow(unused)]
fn main() {
let x = 123;
match x {
    0...100 => {}
    _ => {}
}
}

显示如下:

warning: `...` range patterns are deprecated
 --> lint_example.rs:4:6
  |
4 |     0...100 => {}
  |      ^^^ help: use `..=` for an inclusive range
  |
  = note: `#[warn(ellipsis_inclusive_range_patterns)]` on by default

解释

... 范围模式语法已经被改为 ..=,以避免和 .. 范围表达式的潜在混乱。请使用新形式。

exported_private_dependencies

exported_private_dependencies lint 检测在公共接口公开的私有依赖。

样例

pub fn foo() -> Option<some_private_dependency::Thing> {
    None
}

显示如下:

warning: type `bar::Thing` from private dependency 'bar' in public interface
 --> src/lib.rs:3:1
  |
3 | pub fn foo() -> Option<bar::Thing> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(exported_private_dependencies)]` on by default

解释

依赖可以被标记为 “私有” 以指明其不能在 crate 中的公共接口公开。可以被 Cargo 独立地解析这些依赖项,因为可以假定它不需要使用相同的依赖将它们与其他包统一。该 lint 指明违反了该规则。 要修复此问题,应避免在公共接口中公开此依赖,或将此依赖切换为公有依赖。 注意仅在 nightly channel 中支持此 lint 。更多细节请参阅 RFC 1977,以及 Cargo 文档。

function_item_references

function_item_references lint 检测使用 fmt::Pointer格式化或转换的函数引用。

样例

fn foo() { }

fn main() {
    println!("{:p}", &foo);
}

显示如下:

warning: taking a reference to a function item does not give a function pointer
 --> lint_example.rs:4:22
  |
4 |     println!("{:p}", &foo);
  |                      ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn()`
  |
  = note: `#[warn(function_item_references)]` on by default

解释

引用一个函数可能被误认为是获取函数指针的一种方式。将引用格式化为指针或对其进行转换的时候可能会产生意外的结果。当函数引用被格式化为指针,作为 fmt::Pointer 约束的参数传递或转换时,就会触发该 lint。

illegal_floating_point_literal_pattern

illegal_floating_point_literal_pattern lint 检测用于模式中的浮点数字面量。

样例

#![allow(unused)]
fn main() {
let x = 42.0;

match x {
    5.0 => {}
    _ => {}
}
}

显示如下:

warning: floating-point types cannot be used in patterns
 --> lint_example.rs:5:5
  |
5 |     5.0 => {}
  |     ^^^
  |
  = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>

解释

早期版本的编译器接受用于模式中的浮点数字面量,但是后来确定了是个错误。当与”结构相等“进行对比时,比较浮点数值的语义可能不会再模式中明确。通常你可以通过使用 match 守卫(match guard) 来解决此问题,例如:

#![allow(unused)]
fn main() {
let x = 42.0;

match x {
    y if y == 5.0 => {}
    _ => {}
}
}

这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #41620。

improper_ctypes

improper_ctypes lint 检测在外部模块中错误使用的类型。

样例

#![allow(unused)]
fn main() {
extern "C" {
    static STATIC: String;
}
}

显示如下:

warning: `extern` block uses type `String`, which is not FFI-safe
 --> lint_example.rs:3:20
  |
3 |     static STATIC: String;
  |                    ^^^^^^ not FFI-safe
  |
  = note: `#[warn(improper_ctypes)]` on by default
  = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
  = note: this struct has unspecified layout

解释

编译器做了几项检查以验证外部块中使用的类型是安全的,并遵循某些规则以确保与外部接口的适当兼容性。当其在定义中检测到可能的错误时,将触发此 lint。该 lint 通常应该提供问题描述,并尽可能提示如何解决。

improper_ctypes_definitions

improper_ctypes_definitions lint 检测对 extern 函数 定义的错误使用。

样例

#![allow(unused)]
fn main() {
#![allow(unused)]
pub extern "C" fn str_type(p: &str) { }
}

显示如下:

warning: `extern` fn uses type `str`, which is not FFI-safe
 --> lint_example.rs:3:31
  |
3 | pub extern "C" fn str_type(p: &str) { }
  |                               ^^^^ not FFI-safe
  |
  = note: `#[warn(improper_ctypes_definitions)]` on by default
  = help: consider using `*const u8` and a length instead
  = note: string slices have no C equivalent

解释

在 extern 函数中可能指定了许多与给定的 ABI 不兼容的参数和返回类型。该 lint 是一个关于这些类型都不应该使用的警告。该 lint 应该提供问题的描述,并尽可能提示如何解决问题。

incomplete_features

incomplete_features lint 检测使用 feature 属性启用的不稳定 feature,这可能在一些或全部情况下不能正常工作。

样例

#![allow(unused)]
#![feature(generic_associated_types)]
fn main() {
}

显示如下:

warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
 --> lint_example.rs:1:12
  |
1 | #![feature(generic_associated_types)]
  |            ^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(incomplete_features)]` on by default
  = note: see issue #44265 <https://github.com/rust-lang/rust/issues/44265> for more information

解释

尽管鼓励人们尝试不稳定的性能,其中的一些已知不完整或有缺陷。该 lint 是一个关于 feature 尚未完成的信号,并且你可能会遇到一些问题。

indirect_structural_match

indirect_structural_match lint 检测手动实现的 PartialEq 和 Eq 的模式中的 const。

样例

#![deny(indirect_structural_match)]

struct NoDerive(i32);
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
impl Eq for NoDerive { }
#[derive(PartialEq, Eq)]
struct WrapParam<T>(T);
const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(NoDerive(0));
fn main() {
    match WRAP_INDIRECT_PARAM {
        WRAP_INDIRECT_PARAM => { }
        _ => { }
    }
}

显示如下:

error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
  --> lint_example.rs:11:9
   |
11 |         WRAP_INDIRECT_PARAM => { }
   |         ^^^^^^^^^^^^^^^^^^^
   |
note: the lint level is defined here
  --> lint_example.rs:1:9
   |
1  | #![deny(indirect_structural_match)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>

解释

编译器过去无意间接受了此种形式。这是个将来不兼容 的 lint ,将来会转化为固有错误。完整的问题描述和一些可能的解决办法请参阅 issue #62411。

inline_no_sanitize

inline_no_sanitize lint 检测 #[inline(always)]和#[no_sanitize(...)] 之间的不兼容性。

样例

#![feature(no_sanitize)]

#[inline(always)]
#[no_sanitize(address)]
fn x() {}

fn main() {
    x()
}

显示如下:

warning: `no_sanitize` will have no effect after inlining
 --> lint_example.rs:4:1
  |
4 | #[no_sanitize(address)]
  | ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(inline_no_sanitize)]` on by default
note: inlining requested here
 --> lint_example.rs:3:1
  |
3 | #[inline(always)]
  | ^^^^^^^^^^^^^^^^^

解释

#[inline(always)] 属性的使用会阻止 #[no_sanitize(...)] 属性正常工作。考虑暂时移除 inline 属性。

invalid_codeblock_attributes

invalid_codeblock_attributes lint 检测文档示例中那些可能有类型错误的代码块。这是个仅用于 rustdoc 的 lint ,请参阅 rustdoc book 中的文档。

invalid_value

invalid_value lint 检测创建的无效值,例如 NULL 引用。

样例

#![allow(unused)]
fn main() {
#![allow(unused)]
unsafe {
    let x: &'static i32 = std::mem::zeroed();
}
}

显示如下:

warning: the type `&i32` does not permit zero-initialization
 --> lint_example.rs:4:27
  |
4 |     let x: &'static i32 = std::mem::zeroed();
  |                           ^^^^^^^^^^^^^^^^^^
  |                           |
  |                           this code causes undefined behavior when executed
  |                           help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: `#[warn(invalid_value)]` on by default
  = note: references must be non-null

解释

一些情况下,编译器可以检测到代码创建了无效的值,这应该是避免的。 特别地,该 lint 会检测是否有不恰当的使用 mem::zeroed,mem::uninitialized,mem::transmute和MaybeUninit::assume_init 可能造成未定义行为。

irrefutable_let_patterns

irrefutable_let_patterns lint 检测 在 [if-let][https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions] 和 [while-let][https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops] 语句中的[不可辩驳模式][https://doc.rust-lang.org/reference/patterns.html#refutability] 。

样例

#![allow(unused)]
fn main() {
if let _ = 123 {
    println!("always runs!");
}
}

显示如下:

warning: irrefutable if-let pattern
 --> lint_example.rs:2:1
  |
2 | / if let _ = 123 {
3 | |     println!("always runs!");
4 | | }
  | |_^
  |
  = note: `#[warn(irrefutable_let_patterns)]` on by default

解释

通常没理由在 if-let 或 while-let 语句中使用不可辩驳模式,因为这样的话模式总是会匹配成功,要是这样的话 let 或 loop 语句就够了。然而,当用宏生成代码时,在宏不知道模式是否是可辨驳的情况下,禁止不可辩驳模式是一种笨拙的解决办法。该 lint 允许宏接受此形式,并警告普通代码这可能是不正确的使用。 更多细节请参阅 RFC 2086。

late_bound_lifetime_arguments

late_bound_lifetime_arguments lint 检测后绑定生命周期参数路径段中的泛型生命周期参数。

样例

struct S;

impl S {
    fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
}

fn main() {
    S.late::<'static>(&0, &0);
}

显示如下:

warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
 --> lint_example.rs:8:14
  |
4 |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
  |             -- the late bound lifetime parameter is introduced here
...
8 |     S.late::<'static>(&0, &0);
  |              ^^^^^^^
  |
  = note: `#[warn(late_bound_lifetime_arguments)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>

解释

如果将先绑定生命周期参数与同一参数列表中的后绑定生命周期参数混合在一起,则不清楚如何为其提供参数。目前,如果存在后绑定参数,提供显式参数将触发此 lint。因此将来解决方案可以被采用而不会遇到向后兼容性问题。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节以及先绑定和后绑定之间差异的描述请参阅 issue #42868。

mixed_script_confusables

mixed_script_confusables lint 检测在不同脚本标识符(identifiers between different scripts)间的可视性易混淆的字符。

样例

#![allow(unused)]
#![feature(non_ascii_idents)]

fn main() {
// The Japanese katakana character エ can be confused with the Han character 工.
const エ: &'static str = "アイウ";
}

显示如下:

warning: The usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables
 --> lint_example.rs:5:7
  |
5 | const エ: &'static str = "アイウ";
  |       ^^
  |
  = note: `#[warn(mixed_script_confusables)]` on by default
  = note: The usage includes 'エ' (U+30A8).
  = note: Please recheck to make sure their usages are indeed what you want.

解释

上面的 non_ascii_idents 是只能用于 nightly的,其允许使用非 ASCII 字符作为标识符。该 lint 当不同脚本字符在视觉上看起来很像的时候发出警告,因为(长得像)这可能会造成混乱。 如果 crate包含在相同的脚本中不会引起混淆的字符,那么此 lint 将不会被触发。例如,如果上例还有另一个带有片假名字符的标识符(例如 let カタカナ = 123;),然后就会表明你在有意使用片假名,并且不会对此发出警告。 请注意,易混淆字符集可能会随时间而变化。注意,如果你将该 lint 等级调整为 “禁止”,则现有代码可能在将来会(编译)失败。

mutable_borrow_reservation_conflict

mutable_borrow_reservation_conflict lint 检测与其他共享借用相冲突的第二阶段借用这种保留。

样例

#![allow(unused)]
fn main() {
let mut v = vec![0, 1, 2];
let shared = &v;
v.push(shared.len());
}

显示如下:

warning: cannot borrow `v` as mutable because it is also borrowed as immutable
 --> lint_example.rs:4:1
  |
3 | let shared = &v;
  |              -- immutable borrow occurs here
4 | v.push(shared.len());
  | ^      ------ immutable borrow later used here
  | |
  | mutable borrow occurs here
  |
  = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
  = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
  = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>

解释

这是个将来不兼容 的 lint ,将来会转化为固有错误。完整问题描述和一些可能的解决办法请参阅 issue #59159。

no_mangle_generic_items

no_mangle_generic_items lint 检测必须使用 改发(mangle)的泛型项。

样例

#![allow(unused)]
fn main() {
#[no_mangle]
fn foo<T>(t: T) {

}
}

显示如下:

warning: functions generic over types or consts must be mangled
 --> lint_example.rs:3:1
  |
2 |   #[no_mangle]
  |   ------------ help: remove this attribute
3 | / fn foo<T>(t: T) {
4 | |
5 | | }
  | |_^
  |
  = note: `#[warn(no_mangle_generic_items)]` on by default

解释

泛型函数必须改发其符号以适应泛型参数。no_mangle 属性对此无效,应该被移除。

non_autolinks lint 检测何时仅能用尖括号写入 URL 。这是一个仅用于 rustdoc 的lint,请查看 rustdoc book中的文档。

non_camel_case_types

non_camel_case_types lint 检测没有使用驼峰命名的类型、变量、trait 和类型参数。

样例

#![allow(unused)]
fn main() {
struct my_struct;
}

显示如下:

warning: type `my_struct` should have an upper camel case name
 --> lint_example.rs:2:8
  |
2 | struct my_struct;
  |        ^^^^^^^^^ help: convert the identifier to upper camel case: `MyStruct`
  |
  = note: `#[warn(non_camel_case_types)]` on by default

解释

标识符的首选样式是使用 ”驼峰大小写“,例如 MyStruct,其中首字母不应小写,且字母之间不应使用下划线。在标识符的开头和结尾以及非字母之间(例如 X86_64),都可以使用下划线。

non_shorthand_field_patterns

non_shorthand_field_patterns lint 检测在模式中使用 Struct { x: x } 而非 Struct { x }。

样例

struct Point {
    x: i32,
    y: i32,
}


fn main() {
    let p = Point {
        x: 5,
        y: 5,
    };

    match p {
        Point { x: x, y: y } => (),
    }
}

显示如下:

warning: the `x:` in this pattern is redundant
  --> lint_example.rs:14:17
   |
14 |         Point { x: x, y: y } => (),
   |                 ^^^^ help: use shorthand field pattern: `x`
   |
   = note: `#[warn(non_shorthand_field_patterns)]` on by default

解释

首选的样式是避免在两个标识符相同的情况下重复指定字段名和绑定名。

non_snake_case

non_snake_case lint 检测没有使用蛇形命名的变量、方法、函数、生命周期参数和模块。

样例

#![allow(unused)]
fn main() {
let MY_VALUE = 5;
}

显示如下:

warning: variable `MY_VALUE` should have a snake case name
 --> lint_example.rs:2:5
  |
2 | let MY_VALUE = 5;
  |     ^^^^^^^^ help: convert the identifier to snake case: `my_value`
  |
  = note: `#[warn(non_snake_case)]` on by default

解释
标识符首选样式是使用蛇形命名,即所有字符均为小写,单词之间用单个下划线分隔,例如 my_value。

non_upper_case_globals

non_upper_case_globals lint 检测没有使用大写标识符的 static 项。

样例

#![allow(unused)]
fn main() {
static max_points: i32 = 5;
}

显示如下:

warning: static variable `max_points` should have an upper case name
 --> lint_example.rs:2:8
  |
2 | static max_points: i32 = 5;
  |        ^^^^^^^^^^ help: convert the identifier to upper case: `MAX_POINTS`
  |
  = note: `#[warn(non_upper_case_globals)]` on by default

解释

静态项命名的首选样式是都使用大写,例如 MAX_POINTS。

nontrivial_structural_match

nontrivial_structural_match lint 检测用于模式中的常量,该常量类型是非结构化匹配(not structural match)的且初始化体实际上所使用的值是非结构化匹配的。所以如果常数仅是 None,Option<NotStruturalMatch> 是对的。

样例

#![deny(nontrivial_structural_match)]

#[derive(Copy, Clone, Debug)]
struct NoDerive(u32);
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
impl Eq for NoDerive { }
fn main() {
    const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
    match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
}

显示如下:

error: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
 --> lint_example.rs:9:47
  |
9 |     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
  |                                               ^^^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(nontrivial_structural_match)]
  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>

解释

早期的 Rust 接受在模式中使用常量,甚至就算常量类型没有派生 PartialEq 。因此编译器会回退到 PartialEq 执行的运行时,即使两个常量位等效该运行时也报告为不等。

overlapping_patterns

overlapping_patterns lint 检测具有重叠的范围模式的 match 分支。

样例

#![allow(unused)]
fn main() {
let x = 123u8;
match x {
    0..=100 => { println!("small"); }
    100..=255 => { println!("large"); }
}
}

显示如下:

warning: multiple patterns covering the same range
 --> lint_example.rs:5:5
  |
4 |     0..=100 => { println!("small"); }
  |     ------- this range overlaps on `100_u8`
5 |     100..=255 => { println!("large"); }
  |     ^^^^^^^^^ overlapping patterns
  |
  = note: `#[warn(overlapping_patterns)]` on by default

解释

在 match 表达式中重叠的范围模式可能是错误的。检查开始和结束值是否符合你的期望,并记住,使用 ..= 时,左边界和右边界是包括在内的。

path_statements

path_statements lint 检测无效的路径语句(path statements)。

样例

#![allow(unused)]
fn main() {
let x = 42;

x;
}

显示如下:

warning: path statement with no effect
 --> lint_example.rs:4:1
  |
4 | x;
  | ^^
  |
  = note: `#[warn(path_statements)]` on by default

解释

无效的语句通常是个错误。

private_in_public

private_in_public lint 检测以前的实现没有捕获的公有接口中的私有项。

样例

#![allow(unused)]
struct SemiPriv;

mod m1 {
    struct Priv;
    impl super::SemiPriv {
        pub fn f(_: Priv) {}
    }
}
fn main() {}

显示如下:

warning: private type `Priv` in public interface (error E0446)
 --> lint_example.rs:7:9
  |
7 |         pub fn f(_: Priv) {}
  |         ^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(private_in_public)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>

解释

可见性规则旨在防止公共接口公开私有项。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #34537。

该 lint 是当从公有项链接到私有项时会发出警告的 broken_intra_doc_links 的子集。这是一个仅用于 rustdoc 的lint,请查看 rustdoc book中的文档。

proc_macro_derive_resolution_fallback

proc_macro_derive_resolution_fallback lint 检测使用父模块中无法访问的名称的 proc 宏派生。

样例

// foo.rs
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::*;

#[proc_macro_derive(Foo)]
pub fn foo1(a: TokenStream) -> TokenStream {
    drop(a);
    "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
}
// bar.rs
#[macro_use]
extern crate foo;

struct Something;

#[derive(Foo)]
struct Another;

fn main() {}

显示如下:

warning: cannot find type `Something` in this scope
 --> src/main.rs:8:10
  |
8 | #[derive(Foo)]
  |          ^^^ names from parent modules are not accessible without an explicit import
  |
  = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>

解释

如果 proc-macro 生成了一个模块,则编译器会无意地允许该模块中的项引用 crate 根中的项而不用导入。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #50504。

redundant_semicolons

redundant_semicolons lint 检测不必要的尾部分号。

样例

#![allow(unused)]
fn main() {
let _ = 123;;
}

显示如下:

warning: unnecessary trailing semicolon
 --> lint_example.rs:2:13
  |
2 | let _ = 123;;
  |             ^ help: remove this semicolon
  |
  = note: `#[warn(redundant_semicolons)]` on by default

解释

多余的分号是不需要的,可以将其删除以避免混淆和视觉混乱。

renamed_and_removed_lints

renamed_and_removed_lints lint 检测已经呗重命名或移除的 lint 。

样例

#![allow(unused)]
#![deny(raw_pointer_derive)]
fn main() {
}

显示如下:

warning: lint `raw_pointer_derive` has been removed: `using derive with raw pointers is ok`
 --> lint_example.rs:1:9
  |
1 | #![deny(raw_pointer_derive)]
  |         ^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(renamed_and_removed_lints)]` on by default

解释

要修复此问题,要么移除此 lint,要么使用推荐的新名字。这可以帮助避免与不再有效的 lint 的混淆,并且保持重命名后的 lint 的一致性。

safe_packed_borrows

safe_packed_borrows lint 检测借用包装结构体对齐方式不是1 的字段。

样例

#[repr(packed)]
pub struct Unaligned<T>(pub T);

pub struct Foo {
    start: u8,
    data: Unaligned<u32>,
}

fn main() {
    let x = Foo { start: 0, data: Unaligned(1) };
    let y = &x.data.0;
}

显示如下:

warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
  --> lint_example.rs:11:13
   |
11 |     let y = &x.data.0;
   |             ^^^^^^^^^
   |
   = note: `#[warn(safe_packed_borrows)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior

解释

这种借用方式是不安全的,且可能再某些平台上导致错误和违反编译器所做的某些假设,以前无意中会允许这样做。这是个将来不兼容 的 lint ,将来会转化为固有错误。有关如何解决该问题的引导和更多细节请参阅 issue #46043。

stable_features

stable_features lint 检测已经变为 stable 的 feature 属性。

样例

#![feature(test_accepted_feature)]
fn main() {}

显示如下:

warning: the feature `test_accepted_feature` has been stable since 1.0.0 and no longer requires an attribute to enable
 --> lint_example.rs:1:12
  |
1 | #![feature(test_accepted_feature)]
  |            ^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(stable_features)]` on by default

解释

当一个 feature 稳定后,就不再需要包含 #![feature] 属性了。要修复此问题,只需简单地移除 #![feature] 属性就行。

temporary_cstring_as_ptr

temporary_cstring_as_ptr lint 检测临时获取 CString 的内部指针。

样例

#![allow(unused)]
fn main() {
#![allow(unused)]
use std::ffi::CString;
let c_str = CString::new("foo").unwrap().as_ptr();
}

显示如下:

warning: getting the inner pointer of a temporary `CString`
 --> lint_example.rs:4:42
  |
4 | let c_str = CString::new("foo").unwrap().as_ptr();
  |             ---------------------------- ^^^^^^ this pointer will be invalid
  |             |
  |             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
  |
  = note: `#[warn(temporary_cstring_as_ptr)]` on by default
  = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
  = help: for more information, see https://doc.rust-lang.org/reference/destructors.html

解释

CString 的内部指针 存活时间和其指向的 CString 一样长。获取临时的 CString 的内部指针允许在语句结尾释放 CString ,因为就类型系统而言,其并未被引用。这意味着在语句之外,该指针将会指向已释放的内存,如果之后解引用指针会导致未定义的行为。

trivial_bounds

trivial_bounds lint 检测没有依赖任何参数的 triat 约束。

样例

#![allow(unused)]
#![feature(trivial_bounds)]
fn main() {
pub struct A where i32: Copy;
}

显示如下:

warning: Trait bound i32: Copy does not depend on any type or lifetime parameters
 --> lint_example.rs:3:25
  |
3 | pub struct A where i32: Copy;
  |                         ^^^^
  |
  = note: `#[warn(trivial_bounds)]` on by default

解释

通常,你不会写出一个你知道它永远是对的,或者永远不对的 trait 约束。然而,使用宏时,宏可能不知道在生成代码时约束是否成立。当前,如果约束始终正确,编译器不会警告你;如果约束不对,编译器会生成错误。在这两种情况下, trivial_bounds feature 都将其更改为警告,从而使得宏有更大的自由度和灵活性来生成代码,同时在产生存在问题的非宏代码时会发出相应信号表明存在问题。 更多细节请参阅 RFC 2056。该 feature 目前仅在 nightly channel 有效,跟踪问题请参阅 issue #48214。

type_alias_bounds

type_alias_bounds lint 检测类型别名中的约束。

样例

#![allow(unused)]
fn main() {
type SendVec<T: Send> = Vec<T>;
}

显示如下:

warning: bounds on generic parameters are not enforced in type aliases
 --> lint_example.rs:2:17
  |
2 | type SendVec<T: Send> = Vec<T>;
  |                 ^^^^
  |
  = note: `#[warn(type_alias_bounds)]` on by default
help: the bound will not be checked when the type alias is used, and should be removed
  |
2 | type SendVec<T> = Vec<T>;
  |              --

解释

类型别名中的 trait 约束 当前是被忽略的,并且不应该包含在内以免造成混淆。以前会无意中允许这样做,这在将来可能会转换为固有错误。

tyvar_behind_raw_pointer

tyvar_behind_raw_pointer lint 检测指向推断变量(inference variable)的原生指针(raw pointer)。

样例

#![allow(unused)]
fn main() {
// edition 2015
let data = std::ptr::null();
let _ = &data as *const *const ();

if data.is_null() {}
}

显示如下:

warning: type annotations needed
 --> lint_example.rs:6:9
  |
6 | if data.is_null() {}
  |         ^^^^^^^
  |
  = note: `#[warn(tyvar_behind_raw_pointer)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
  = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>

解释

这种推断以前是允许的,但是随着将来 arbitrary self type的引入,这可能会引起歧义。要解决此问题,请使用显式类型而非依赖类型推导。 这是个将来不兼容 的 lint ,在 2018 版本中会转化为固有错误。更多细节请参阅 issue #46906 。目前在 2018 版本中是个固有错误,在2018版本中默认等级是警告。

uncommon_codepoints

uncommon_codepoints lint 检测在标识符中不常见的 Unicode 字符码(codepoint)。

样例

#![allow(unused)]
fn main() {
#![allow(unused)]
#![feature(non_ascii_idents)]
const µ: f64 = 0.000001;
}

显示如下:

warning: identifier contains uncommon Unicode codepoints
 --> lint_example.rs:4:7
  |
4 | const µ: f64 = 0.000001;
  |       ^
  |
  = note: `#[warn(uncommon_codepoints)]` on by default

解释

上面的 non_ascii_idents 是只能用于 nightly的,其允许使用非 ASCII 字符作为标识符。该 lint发出警告不要使用不常用字符,并且可能会引起视觉混乱。 该 lint 由包含不属于 “Allowed” 字符码集的字符码的标识符所触发,该 “Allowed” 字符码集被描述为 Unicode® Technical Standard #39 Unicode Security Mechanisms Section 3.1 General Security Profile for Identifiers。

unconditional_recursion

unconditional_recursion lint 检测不调用自身无法返回的函数。

样例

#![allow(unused)]
fn main() {
fn foo() {
    foo();
}
}

显示如下:

warning: function cannot return without recursing
 --> lint_example.rs:2:1
  |
2 | fn foo() {
  | ^^^^^^^^ cannot return without recursing
3 |     foo();
  |     ----- recursive call site
  |
  = note: `#[warn(unconditional_recursion)]` on by default
  = help: a `loop` may express intention better if this is on purpose

解释

进行没有一定条件终止的递归调用通常是个错误。如果确实想要进行无限循环,推荐使用 loop 表达式。

uninhabited_static

uninhabited_static lint 检测 uninhabited 静态项。(译者想把 uninhabited 翻译为空巢,但是想想还是算了,太花哨了)

样例

#![allow(unused)]
fn main() {
enum Void {}
extern {
    static EXTERN: Void;
}
}

显示如下:

warning: static of uninhabited type
 --> lint_example.rs:4:5
  |
4 |     static EXTERN: Void;
  |     ^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(uninhabited_static)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
  = note: uninhabited statics cannot be initialized, and any access would be an immediate error

解释

一个 uninhabited 的 static 类型永远不会被初始化,因此无法定义。然而,该问题可以使用 extern static 来避开。(uninhabited static)假定其没有初始化的 uninhabited 的地方(例如本地或静态变量)。(uninhabited static)确实被允许这么做,但是其正在被淘汰。

unknown_lints

unknown_lints lint 无法识别的 lint 属性。

样例

#![allow(unused)]
#![allow(not_a_real_lint)]
fn main() {
}

显示如下:

warning: unknown lint: `not_a_real_lint`
 --> lint_example.rs:1:10
  |
1 | #![allow(not_a_real_lint)]
  |          ^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unknown_lints)]` on by default

解释

指定一个不存在的 lint 通常是个错误。检查拼写和 lint 列表中的正确名称是否相同。同时考虑是否是在使用旧版本的编译器,而此 lint 仅在新版本中可用。

unnameable_test_items

unnameable_test_items lint 检测不能由测试工具运行的 #[test] 函数,因为它们处于不可命名的地方。

样例

fn main() {
    #[test]
    fn foo() {
        // This test will not fail because it does not run.
        assert_eq!(1, 2);
    }
}

显示如下:

warning: cannot test inner items
 --> lint_example.rs:2:5
  |
2 |     #[test]
  |     ^^^^^^^
  |
  = note: `#[warn(unnameable_test_items)]` on by default
  = note: this warning originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

解释

为了让测试工具能够进行测试,测试函数必须位于可以从 crate 根访问的位置。通常来说,这意味着必须在模块中定义它,而不是在其他地方,例如在另一个函数中定义。编译器以前允许这样做而没有发出错误消息,因此添加了一个 lint 发出未使用测试的警告。如今尚未确定是否应该允许这么做,请参阅 RFC 2471 和 issue #36629 。

unreachable_code

unreachable_code lint 检测无法到达的代码路径。

样例

#![allow(unused)]
fn main() {
panic!("we never go past here!");

let x = 5;
}

显示如下:

warning: unreachable statement
 --> lint_example.rs:4:1
  |
2 | panic!("we never go past here!");
  | --------------------------------- any code following this expression is unreachable
3 | 
4 | let x = 5;
  | ^^^^^^^^^^ unreachable statement
  |
  = note: `#[warn(unreachable_code)]` on by default

解释

无法到达的代码可能意味着是个错误或代码未完成。如果代码不再使用,请考虑移除它。

unreachable_patterns

unreachable_patterns lint 检测无法到达的模式。

样例

#![allow(unused)]
fn main() {
let x = 5;
match x {
    y => (),
    5 => (),
}
}

显示如下:

warning: unreachable pattern
 --> lint_example.rs:5:5
  |
4 |     y => (),
  |     - matches any value
5 |     5 => (),
  |     ^ unreachable pattern
  |
  = note: `#[warn(unreachable_patterns)]` on by default

解释

这通常意味着模式的指定或顺序有误。在上例中,y 模式总是会匹配,所以 5 是不可能到达的。记住,match 分支是按顺序匹配的,你可以将 5 调整到 y 的上面。

unstable_name_collisions

unstable_name_collisions lint 检测使用了标准库计划在将来添加的名称。

样例

#![allow(unused)]
fn main() {
trait MyIterator : Iterator {
    // is_sorted is an unstable method that already exists on the Iterator trait
    fn is_sorted(self) -> bool where Self: Sized {true}
}

impl<T: ?Sized> MyIterator for T where T: Iterator { }

let x = vec![1,2,3];
let _ = x.iter().is_sorted();
}

显示如下:

warning: a method with this name may be added to the standard library in the future
  --> lint_example.rs:10:18
   |
10 | let _ = x.iter().is_sorted();
   |                  ^^^^^^^^^
   |
   = note: `#[warn(unstable_name_collisions)]` on by default
   = warning: once this method is added to the standard library, the ambiguity may cause an error or change in behavior!
   = note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
   = help: call with fully qualified syntax `MyIterator::is_sorted(...)` to keep using the current method
   = help: add `#![feature(is_sorted)]` to the crate attributes to enable `is_sorted`

解释

当标准库中的 trait 添加了新方法之时,它们通常在具有 feature 属性的 nightly channel 中以 “unstable” 形式添加。如果有任何之前已存在的代码扩展了具有同名方法的 trait,则这些名称将会发生冲突。将来,当方法稳定后,由于歧义将会造成错误。该 lint 是一个让你知道将来可能会发生碰撞的预警。可以通过添加类型注解来消除要调用的 trait 方法的歧义避免此歧义,例如 MyIterator::is_sorted(my_iter) 或重名或删除该方法。

unused_allocation

unused_allocation lint 检测可以被消除的不必要的(内存)分配。

样例

#![feature(box_syntax)]
fn main() {
    let a = (box [1,2,3]).len();
}

显示如下:

warning: unnecessary allocation, use `&` instead
 --> lint_example.rs:3:13
  |
3 |     let a = (box [1,2,3]).len();
  |             ^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_allocation)]` on by default

解释

当一个 box 表达式立即被强转为引用时,说明这个分配时不必要的,且应该使用引用( 使用 & 或 &mut )来避免引用。

unused_assignments

unused_assignments lint 检测从未被读取的赋值。

样例

#![allow(unused)]
fn main() {
let mut x = 5;
x = 6;
}

显示如下:

warning: value assigned to `x` is never read
 --> lint_example.rs:3:1
  |
3 | x = 6;
  | ^
  |
  = note: `#[warn(unused_assignments)]` on by default
  = help: maybe it is overwritten before being read?

解释

未使用的赋值可能意味着是个错误或未完成的代码。如果变量自赋值之后就从未被使用,那么这个赋值也可以被移除。带有下划线前缀的变量例如 _x 将不会触发此 lint 。

unused_attributes

unused_attributes lint 检测编译器未使用的属性。

样例

#![allow(unused)]
#![ignore]
fn main() {
}

显示如下:

warning: unused attribute
 --> lint_example.rs:1:1
  |
1 | #![ignore]
  | ^^^^^^^^^^
  |
  = note: `#[warn(unused_attributes)]` on by default

解释

未使用的属性可能意味着属性放在了错误的位置。考虑移除它,或将其放在正确的地方。还应考虑是否使用属性所在项的内部属性(用 !,例如#![allow(unused)]),或者应用于属性后面项的外部属性(没有 !,例如 [allow(unused)])。

unused_braces

unused_braces lint 检测表达式周边不必要的大括号。

样例

#![allow(unused)]
fn main() {
if { true } {
    // ...
}
}

显示如下:

warning: unnecessary braces around `if` condition
 --> lint_example.rs:2:4
  |
2 | if { true } {
  |    ^^^^^^^^ help: remove these braces
  |
  = note: `#[warn(unused_braces)]` on by default

解释

该大括号是不需要的,应该将其移除。这是编写这些表达式的首选样式。

unused_comparisons

unused_comparisons lint 检测由于所涉及类型的限制而变得无用的比较。

样例

#![allow(unused)]
fn main() {
fn foo(x: u8) {
    x >= 0;
}
}

显示如下:

warning: comparison is useless due to type limits
 --> lint_example.rs:3:5
  |
3 |     x >= 0;
  |     ^^^^^^
  |
  = note: `#[warn(unused_comparisons)]` on by default

解释

一个无用的比较或许表明是一个错误,或者应该被修复或移除。

unused_doc_comments

unused_doc_comments lint 检测并未用于 rustdoc 的文档注释。

样例

#![allow(unused)]
fn main() {
/// docs for x
let x = 12;
}

显示如下:

warning: unused doc comment
 --> lint_example.rs:2:1
  |
2 | /// docs for x
  | ^^^^^^^^^^^^^^
3 | let x = 12;
  | ----------- rustdoc does not generate documentation for statements
  |
  = note: `#[warn(unused_doc_comments)]` on by default

解释

rustdoc 并不会使用所有地方的文档注释,因此某些文档注释将会被忽略。尝试使用 // 将其改为普通注释,以免出现警告。

unused_features

unused_features lint 检测未使用或未知的在 crate-level feature 属性找到的 feature 。

注意:该 lint 目前还无法运作,更多细节请参阅 issue #44232。

unused_imports

unused_imports lint 检测从未被使用的 import 项。

样例

#![allow(unused)]
fn main() {
use std::collections::HashMap;
}

显示如下:

warning: unused import: `std::collections::HashMap`
 --> lint_example.rs:2:5
  |
2 | use std::collections::HashMap;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

解释

未使用的 import 项可能意味着是个错误或未完成的代码,并且会使代码混乱,应该将其移除。如果要重导出项使得在模块外可用,请添加可见修饰符如 pub 。

unused_labels

unused_labels lint 检测未使用的 标记。

样例

#![allow(unused)]
fn main() {
'unused_label: loop {}
}

显示如下:

warning: unused label
 --> lint_example.rs:2:1
  |
2 | 'unused_label: loop {}
  | ^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_labels)]` on by default

解释

未使用的标记可能意味着是个错误或未完成的代码。要使单个标记的该警告沉默,在前面添加下划线,如 '_my_label:。

unused_macros

unused_macros lint 检测从未使用的宏。

样例

macro_rules! unused {
    () => {};
}

fn main() {
}

显示如下:

warning: unused macro definition
 --> lint_example.rs:1:1
  |
1 | / macro_rules! unused {
2 | |     () => {};
3 | | }
  | |_^
  |
  = note: `#[warn(unused_macros)]` on by default

解释

未使用的宏可能意味着是个错误或未完成的代码。使单个宏的该警告沉默,在前面添加下划线,如 '_my_macro。如果想要导出宏以使其在 crate 之外可用,请使用 macro_export 属性。

unused_must_use

unused_must_use lint 检测被标记为 #[must_use] 却没被使用的类型的 result 。

样例

fn returns_result() -> Result<(), ()> {
    Ok(())
}

fn main() {
    returns_result();
}

显示如下:

warning: unused `std::result::Result` that must be used
 --> lint_example.rs:6:5
  |
6 |     returns_result();
  |     ^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_must_use)]` on by default
  = note: this `Result` may be an `Err` variant, which should be handled

解释

#[must_use] 属性表明忽略返回值是个错误。更多细节请参阅 reference。

unused_mut

unused_mut lint 不需要可变的可变变量。

样例

#![allow(unused)]
fn main() {
let mut x = 5;
}

显示如下:

warning: variable does not need to be mutable
 --> lint_example.rs:2:5
  |
2 | let mut x = 5;
  |     ----^
  |     |
  |     help: remove this `mut`
  |
  = note: `#[warn(unused_mut)]` on by default

解释

首选样式是仅在需要时才将变量标记为 mut 。

unused_parens

unused_parens lint 检测 if,match,while和return 带有圆括号,它们不需要圆括号。

样例

#![allow(unused)]
fn main() {
if(true) {}
}

显示如下:

warning: unnecessary parentheses around `if` condition
 --> lint_example.rs:2:3
  |
2 | if(true) {}
  |   ^^^^^^ help: remove these parentheses
  |
  = note: `#[warn(unused_parens)]` on by default

解释

圆括号是不需要的,应该被移除。这是这些表达式的首选样式。

unused_unsafe

unused_unsafe lint 检测不必要的 unsafe 块的使用。

样例

#![allow(unused)]
fn main() {
unsafe {}
}

显示如下:

warning: unnecessary `unsafe` block
 --> lint_example.rs:2:1
  |
2 | unsafe {}
  | ^^^^^^ unnecessary `unsafe` block
  |
  = note: `#[warn(unused_unsafe)]` on by default

解释

如果块中没有内容需要 unsafe,应该移除 unsafe 标记,因为其不是必要并且可能会造成混乱。

unused_variables

unused_variables lint 检测未以任何方式使用的变量。

样例


#![allow(unused)]
fn main() {
let x = 5;
}

显示如下:

warning: unused variable: `x`
 --> lint_example.rs:2:5
  |
2 | let x = 5;
  |     ^ help: if this is intentional, prefix it with an underscore: `_x`
  |
  = note: `#[warn(unused_variables)]` on by default

解释

未使用变量可能意味着是个错误或未完成的代码。要对单个变量使该警告沉默,前缀加上下划线例如 _x 。

warnings

warnings lint 允许你更改那些将会产生警告的 lint 的等级 为其他等级。

样例

#![deny(warnings)]
fn main() {
fn foo() {}
}

显示如下:

error: function is never used: `foo`
 --> lint_example.rs:3:4
  |
3 | fn foo() {}
  |    ^^^
  |
note: the lint level is defined here
 --> lint_example.rs:1:9
  |
1 | #![deny(warnings)]
  |         ^^^^^^^^
  = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]`

解释

warning lint 有点特殊;通过改变其等级,可以改变所有其他会根据你想要的任何值生成警告的警告。这样说来,你永远不会在代码中直接触发此 lint 。

where_clauses_object_safety

where_clauses_object_safety lint 检测 where 子句的 对象安全。

样例

trait Trait {}

trait X { fn foo(&self) where Self: Trait; }

impl X for () { fn foo(&self) {} }

impl Trait for dyn X {}

// Segfault at opt-level 0, SIGILL otherwise.
pub fn main() { <dyn X as X>::foo(&()); }

显示如下:

warning: the trait `X` cannot be made into an object
 --> lint_example.rs:3:14
  |
3 | trait X { fn foo(&self) where Self: Trait; }
  |              ^^^
  |
  = note: `#[warn(where_clauses_object_safety)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
 --> lint_example.rs:3:14
  |
3 | trait X { fn foo(&self) where Self: Trait; }
  |       -      ^^^ ...because method `foo` references the `Self` type in its `where` clause
  |       |
  |       this trait cannot be made into an object...
  = help: consider moving `foo` to another trait

解释

编译器以前会允许这些对象不安全的约束,这是不安全的。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #51443。

while_true

while_true lint 检测 while true { }。

样例


#![allow(unused)]
fn main() {
while true {

}
}

显示如下:

warning: denote infinite loops with `loop { ... }`
 --> lint_example.rs:2:1
  |
2 | while true {
  | ^^^^^^^^^^ help: use `loop`
  |
  = note: `#[warn(while_true)]` on by default

解释
while true 应该被 loop 所代替。loop 表达式是编写无限循环的首选方法因为其直接表达了无限循环的意图。

默认等级为拒绝的 lints

默认情况下,这些 lint 都设置为 'deny' 级别。

ambiguous_associated_items

ambiguous_associated_items lint 检测枚举变量和关联项之间的不确定项。

样例

#![allow(unused)]
fn main() {
enum E {
    V
}

trait Tr {
    type V;
    fn foo() -> Self::V;
}

impl Tr for E {
    type V = u8;
    // `Self::V` is ambiguous because it may refer to the associated type or
    // the enum variant.
    fn foo() -> Self::V { 0 }
}
}

显示如下:

error: ambiguous associated item
  --> lint_example.rs:15:17
   |
15 |     fn foo() -> Self::V { 0 }
   |                 ^^^^^^^ help: use fully-qualified syntax: `<E as Tr>::V`
   |
   = note: `#[deny(ambiguous_associated_items)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #57644 <https://github.com/rust-lang/rust/issues/57644>
note: `V` could refer to the variant defined here
  --> lint_example.rs:3:5
   |
3  |     V
   |     ^
note: `V` could also refer to the associated type defined here
  --> lint_example.rs:7:5
   |
7  |     type V;
   |     ^^^^^^^
   

解释

早期 Rust 版本不允许通过类型别名访问枚举变量,当添加此功能时(请参阅 RFC 2338),这引入了某些情况,即类型所指的可能不明确。

要解决该歧义,应使用路径限定明确声明要使用的类型。例如,以上示例中函数可以被写作fn f() -> <Self as Tr>::V { 0 } 以明确引用关联的类型。

这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #57644

arithmetic_overflow

arithmetic_overflow lint 检测会溢出的算术运算

样例

#![allow(unused)]
fn main() {
1_i32 << 32;
}

显示如下:

error: this arithmetic operation will overflow
 --> lint_example.rs:2:1
  |
2 | 1_i32 << 32;
  | ^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow
  |
  = note: `#[deny(arithmetic_overflow)]` on by default

解释

执行值溢出运算很可能是错误,如果编译器能够在编译时检测到这些溢出,就会触发这个 lint。请考虑调整表达式避免溢出,或者使用不会溢出的数据类型。

conflicting_repr_hints

conflicting_repr_hints lint 检测带有冲突提示的 repr 属性。

样例


#![allow(unused)]
fn main() {
#[repr(u32, u64)]
enum Foo {
    Variant1,
}
}

显示如下:

error[E0566]: conflicting representation hints
 --> lint_example.rs:2:8
  |
2 | #[repr(u32, u64)]
  |        ^^^  ^^^
  |
  = note: `#[deny(conflicting_repr_hints)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>

解释

过去编译器错误的接受了这些冲突的表示形式。这是个将来不兼容 的 lint ,将来会转化为固有错误。了解更多细节请参阅 issue #68585

想要更正该问题,请移除冲突的提示之一。

const_err

const_err lint 检测常量求值时的错误表达式。

样例

#![allow(unused)]
#![allow(unconditional_panic)]
fn main() {
let x: &'static i32 = &(1 / 0);
}

显示如下:

error: reaching this expression at runtime will panic or abort
 --> lint_example.rs:3:24
  |
3 | let x: &'static i32 = &(1 / 0);
  |                       -^^^^^^^
  |                        |
  |                        dividing by zero
  |
  = note: `#[deny(const_err)]` on by default

解释

该 lint 检测很可能错误的代码,如果将该 lint 等级变为允许,那么代码将不会在编译时进行计算,而是继续生成代码,在运行时计算,这可能会在运行时 panic 。 注意,该 lint 可以在 const 上下文内部或外部触发。在 const 上下文外部,编译器有时会在编译时对表达式求值以生成更高效的代码。如果编译器要在这方面做得更好,它需要决定当遇到肯定会panic 或是不正确的代码时应该怎么做。将此设置为固有错误(hard error)将阻止表现出此行为的现有代码编译,破坏向后兼容性。然而,这肯定是不正确的代码,因此这是一个默认等级为拒绝的 lint。更多细节请参阅 RFC 1229 和 issue #28238。 注意还有几个其他更特定的编译时计算相关的 lint,例如:arithmetic_overflow,unconditional_panic 。

ill_formed_attribute_input

ill_formed_attribute_input lint 检测以前被接收并且用于实践中的不良格式的属性输入。

样例

#![allow(unused)]
fn main() {
#[inline = "this is not valid"]
fn foo() {}
}

这会显示:

error: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
 --> lint_example.rs:2:1
  |
2 | #[inline = "this is not valid"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(ill_formed_attribute_input)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>

解释

以前,许多内置属性的输入没有经过验证,无意义的属性输入被接收。在添加了验证之后,明确了一些现有的项目使用了这些无效的格式。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #57571 。 有关有效输入的属性,更多细节请参阅 attribute reference 。

incomplete_include

incomplete_include lint 检测一个文件包含多于一个表达式的 include! 宏。

样例

fn main() {
    include!("foo.txt");
}

当 foo.txt文件包含以下内容:

println!("hi!");

显示如下:

error: include macro expected single expression in source
 --> foo.txt:1:14
  |
1 | println!("1");
  |              ^
  |
  = note: `#[deny(incomplete_include)]` on by default

解释

include! 宏当前仅打算用于单个表达式或多个项。从以前看,它会忽略第一个表达式之后的任何内容,但这可能会令人困惑。在上例中,println! 表达式( println! expression )刚好在分号之前结束,从而使分号成为多余的信息而被忽略,更令人惊讶的是,如果包含的文件有多个打印语句,后续的语句将被忽略! 一个解决办法是将内容放在大括号中创建块表达式。还可以考虑其他办法,例如函数封装表达式或者使用过程宏。 这是个 lint 而不是固有错误是因为现有项目已经发现并报过错。谨慎起见,它现在还是个 lint 。include! 宏的未来语义还不确定,请参阅 issue #35560。

invalid_type_param_default

invalid_type_param_default lint 检测在无效位置中错误地允许 (allowed) 使用类型参数默认值。

样例

#![allow(unused)]
fn main() {
fn foo<T=i32>(t: T) {}
}

显示如下:

error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions.
 --> lint_example.rs:2:8
  |
2 | fn foo<T=i32>(t: T) {}
  |        ^
  |
  = note: `#[deny(invalid_type_param_default)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>

解释

默认类型参数仅在某些情况下才允许使用,但是以前编译器在任何地方都允许使用。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #36887 。

macro_expanded_macro_exports_accessed_by_absolute_paths

macro_expanded_macro_exports_accessed_by_absolute_paths lint 检测当前 crate 中不能被绝对路径引用的 macro_export宏的宏展开。

样例

macro_rules! define_exported {
    () => {
        #[macro_export]
        macro_rules! exported {
            () => {};
        }
    };
}

define_exported!();

fn main() {
    crate::exported!();
}

显示如下:

error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
  --> lint_example.rs:13:5
   |
13 |     crate::exported!();
   |     ^^^^^^^^^^^^^^^
   |
   = note: `#[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
  --> lint_example.rs:4:9
   |
4  | /         macro_rules! exported {
5  | |             () => {};
6  | |         }
   | |_________^
...
10 |   define_exported!();
   |   ------------------- in this macro invocation
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

解释

我们的目的是所有使用 #[macro_export] 属性的宏在 crate 根是可用的。然而,当一个 macro_rules! 定义由另一个宏生成之时,宏展开是无法遵循该规则的。 这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #53495 。

missing_fragment_specifier

missing_fragment_specifier lint 当有一个未使用的模式在未跟有片段说明符 (fragment specifier) (例如::expr)的元变量(例如:$e)的 macro_rules! 宏定义中时被触发。

始终可以通过移除 macro_rules! 宏定义中未使用的模式来解决此警告。

样例

macro_rules! foo {
   () => {};
   ($name) => { };
}

fn main() {
   foo!();
}

显示如下:

error: missing fragment specifier
 --> lint_example.rs:3:5
  |
3 |    ($name) => { };
  |     ^^^^^
  |
  = note: `#[deny(missing_fragment_specifier)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>

解释

要修复此问题,从 macro_rules! 定义中移除此未使用模式:

macro_rules! foo {
    () => {};
}
fn main() {
    foo!();
}

mutable_transmutes

mutable_transmutes lint 捕捉从 &T 到 &mut T 这种未定义行为 的转换。

样例

#![allow(unused)]
fn main() {
unsafe {
    let y = std::mem::transmute::<&i32, &mut i32>(&5);
}
}

显示如下:

error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
 --> lint_example.rs:3:13
  |
3 |     let y = std::mem::transmute::<&i32, &mut i32>(&5);
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(mutable_transmutes)]` on by default

解释

我们对数据别名做出了一些假设,而这种转换是违反这些假设的。考虑使用 UnsafeCell。

no_mangle_const_items

no_mangle_const_items lint 检测 no_mangle属性的所有 const 项。

样例

#![allow(unused)]
fn main() {
#[no_mangle]
const FOO: i32 = 5;
}

显示如下:

error: const items should never be `#[no_mangle]`
 --> lint_example.rs:3:1
  |
3 | const FOO: i32 = 5;
  | -----^^^^^^^^^^^^^^
  | |
  | help: try a static value: `pub static`
  |
  = note: `#[deny(no_mangle_const_items)]` on by default

解释

常量没有其导出符号,因此这可能意味着你得用 static 而不是 const。

order_dependent_trait_objects

order_dependent_trait_objects lint 检测一种 trait 一致性冲突,该冲突即为同一个包含标记 trait (marker traits)的 dynamic trait object 创建两个 trait 实现。

样例

#![allow(unused)]
fn main() {
pub trait Trait {}

impl Trait for dyn Send + Sync { }
impl Trait for dyn Sync + Send { }
}

显示如下:

error: conflicting implementations of trait `main::Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
 --> lint_example.rs:5:1
  |
4 | impl Trait for dyn Send + Sync { }
  | ------------------------------ first implementation here
5 | impl Trait for dyn Sync + Send { }
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
  |
  = note: `#[deny(order_dependent_trait_objects)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>

解释

以前的一个 bug 导致编译器将不同顺序的 trait (例如 Send + Sync 和 Sync + Send)解释为不同的类型,然而它们应该被认为是相同的。这允许代码在出现一致性错误的时候定义单独的 trait 实现。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #56484 。

overflowing_literals

overflowing_literals lint 检测超出其所属类型范围的字面量。

样例

#![allow(unused)]
fn main() {
let x: u8 = 1000;
}

显示如下:

error: literal out of range for `u8`
 --> lint_example.rs:2:13
  |
2 | let x: u8 = 1000;
  |             ^^^^
  |
  = note: `#[deny(overflowing_literals)]` on by default
  = note: the literal `1000` does not fit into the type `u8` whose range is `0..=255`

解释

使用溢出其所用类型的字面量通常是错误。要么就使用在其类型范围内的字面量,要么就更改其类型以能容纳该字面量。

patterns_in_fns_without_body

patterns_in_fns_without_body lint 检测 mut 标识符模式用于没有函数体的函数的参数。

样例

#![allow(unused)]
fn main() {
trait Trait {
    fn foo(mut arg: u8);
}
}

显示如下:

error: patterns aren't allowed in functions without bodies
 --> lint_example.rs:3:12
  |
3 |     fn foo(mut arg: u8);
  |            ^^^^^^^
  |
  = note: `#[deny(patterns_in_fns_without_body)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>

解释

要想修复此问题, trait 定义中从参数移除 mut ;也可以使用默认实现。也就是说,以下两种都行:

#![allow(unused)]
fn main() {
trait Trait {
    fn foo(arg: u8); // Removed `mut` here
}

impl Trait for i32 {
    fn foo(mut arg: u8) { // `mut` here is OK

    }
}
}

trait 定义中可以定义没有函数体的函数以指定实现必须实现的函数体。无函数体的函数形参名仅允许是 _ 或为了文档目的的(仅类型相关)的标识符。以前的编译器版本错误地允许标识符模式使用 mut 关键字,但这是不被允许的。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #35203 。

pub_use_of_private_extern_crate

pub_use_of_private_extern_crate lint 检测私有 extern crate 重导出的具体情况。

样例

#![allow(unused)]
fn main() {
extern crate core;
pub use core as reexported_core;
}

显示如下:

error: extern crate `core` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
 --> lint_example.rs:3:9
  |
3 | pub use core as reexported_core;
  |         ^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(pub_use_of_private_extern_crate)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537>

解释

一个公开的 use 声明不应该用于 公开性地重导出私有 extern crate。应该使用 pub extern crate。 过去是允许该行为的,但是根据可见性规则这是不符合预期的。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #34537 。

soft_unstable

soft_unstable lint 检测 在 stable 上无意间允许(allowed)的 unstable feature。

样例

#![allow(unused)]
fn main() {
#[cfg(test)]
extern crate test;

#[bench]
fn name(b: &mut test::Bencher) {
    b.iter(|| 123)
}
}

显示如下:

error: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable
 --> lint_example.rs:5:3
  |
5 | #[bench]
  |   ^^^^^
  |
  = note: `#[deny(soft_unstable)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266>

解释

bench 属性意外地在 stable release channel 上被指定。将此转化为固有错误会破坏一些(现有)项目。当使用 --cap-lints 时该 lint 允许项目正确地构建,否则会发出一个错误提示。#[bench] 不应该被用在 stable channel。这是个将来不兼容 的 lint ,将来会转化为固有错误。更多细节请参阅 issue #64266 。

unconditional_panic

unconditional_panic lint 检测将在运行时引起 panic 的操作。

样例

#![allow(unused)]
fn main() {
#![allow(unused)]
let x = 1 / 0;
}

显示如下:

error: this operation will panic at runtime
 --> lint_example.rs:3:9
  |
3 | let x = 1 / 0;
  |         ^^^^^ attempt to divide `1_i32` by zero
  |
  = note: `#[deny(unconditional_panic)]` on by default

解释

该 lint 检测很可能不正确的代码。如果可能,编译器将尝试检测代码能够在编译时进行计算的情况,以生成更高效的代码。在计算这类代码时,如果检测到代码会无条件地 panic ,通常表示(要执行的计算)在做一些错误的事情。如果该 lint 等级被改为允许,然后此代码将不会在编译时被计算,而是继续生成代码在运行时计算,这也可能会在运行时 panic。

unknown_crate_types

unknown_crate_types lint 检测在 crate_type属性中找到的未知 crate 类型。

样例

#![crate_type="lol"]
fn main() {}

显示如下:

error: invalid `crate_type` value
 --> lint_example.rs:1:15
  |
1 | #![crate_type="lol"]
  |               ^^^^^
  |
  = note: `#[deny(unknown_crate_types)]` on by default

解释

给 crate_type 属性赋未知值可以肯定说是一个错误。

useless_deprecated

useless_deprecated lint 检测无效且弃用的属性。

样例

#![allow(unused)]
fn main() {
struct X;

#[deprecated = "message"]
impl Default for X {
    fn default() -> Self {
        X
    }
}
}

显示如下:

error: this `#[deprecated]` annotation has no effect
 --> lint_example.rs:4:1
  |
4 | #[deprecated = "message"]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the unnecessary deprecation attribute
  |
  = note: `#[deny(useless_deprecated)]` on by default

解释

弃用属性对 trait 实现是无影响的。

Codegen 选项

(译者注:Codegen,即 Code generation ,代码生成 ,所以本文是在说各种代码生成选项。)

所有的这些选项都通过 -C 标签传递给 rustc ,是 "codegen" 的缩写。通过运行 rustc -C help

ar

这个选项是被废弃的并且没什么用。

code-model

这个选项让你可以选择要使用的代码模型。
代码模型对程序及其符号可能使用的地址范围进行了约束。
有了更小的地址范围,机器指令就可以使用更紧凑的寻址模式。

该具体范围依赖于目标体系结构及其可用的寻址模式。
对于 x86 体系结构,更多细节性的描述可以在 System V 应用程序二进制接口 规范中找到。

该选项支持的值有:

  • tiny - 微代码模型。
  • small - 小代码模型。这是大多数所支持的目标的默认模式。
  • kernel - 内核代码模式。
  • medium - 中型代码模式。
  • large - 大型代码模式。

也可以通过运行 rustc --print code-models 查找受支持的值(也就是平台可用的代码模型)。

codegen-units

该标签控制将 crate 分隔进多少个代码生成单元,这个(代码生成单元数)大于 0 。

当一个 crate 被分割进多个代码生成单元,LLVM 就可以并行处理它们。提高并行性或许会加快编译时间(缩短编译耗时),但是也可能会产生更慢的代码。设置该标签为 1 可能会提升生成代码的性能,但是也可能会编译得更慢。

如果没有指明默认值,对于非增量构建默认值就是 16 。对于增量构建,默认值是 256,可以使缓存更加细粒度。

control-flow-guard

该标签控制 LLVM 是否启用 Windows 的 控制流守卫 平台安全功能。该标签当前会忽略非 Windows 目标(即在非 Windows 平台上不会生效)。它使用下列值中的一个:

  • y, yes, on, checks, 或者没有值: 启用控制流守卫。
  • nochecks: 不进行运行时强制检查的情况下触发控制流守卫元数据(这理应只用于测试目的,因为它不提供安全强制)。
  • n, no, off: 不启用控制流守卫(默认值)。

debug-assertions

该标签让你可以打开或关闭 cfg(debug_assertions) 条件编译。其采用以下值之一:

  • y, yes, on, 或者无值 :开启 debug-assertions。
  • n, no, 或 off : 禁用 debug-assertions。

如果没有指明( debug-assertions ),仅在 opt-level 是 0 的时候开启 debug assertions 。

debuginfo

该标签控制调试信息的生成。其采用以下值之一:

  • 0: 没有任何调试信息 (默认)。
  • 1: 仅在行表中。
  • 2: 完整的调试信息。

注意:-g 标签 是 -C debuginfo=2 的别名。

default-linker-libraries

该标签控制链接器是否包含其默认链接库。其采用以下值之一:

  • y, yes, on, 或者没有值 : 包含默认库(默认值)。
  • n。 no, 或者 off: 除开默认库。

例如,对于 gcc flavor 链接器,这会向链接器传递 -nodefaultlibs 标签。

embed-bitcode

该标签控制编译器是否将 LLVM 位码嵌入目标文件(object files)中。其采用以下值之一:

  • y, yes, on, 或者无值: 将位码放入 rlib (默认值)。
  • n, no, 或 off: 省略 rlib 中的位码。

当 rustc 执行 LTO (link-time optimization ,链接时优化)时需要 LLVM 位码,在像 iOS 这样的目标平台上也需要。被嵌入的位码将会出现在由 rustc 生成的目标文件中,其名称由目标平台定义,大多数时候是 .llvmbc 。

如果你的编译实际上不需要位码(例如,如果你不针对 iOS 进行编译或不执行 LTO ),-C embed-bitcode=no 的使用可以大大缩短编译时间并且减少生成文件的大小.由于这些原因,Cargo 会尽可能使用 -C embed-bitcode=no 。同样,如果你直接用 rustc 进行构建,我们推荐你在不使用 LTO 的时候使用 -C embed-bitcode=no 。

如果结合 -C lto,-C embed-bitcode=no 将会导致 rustc 启动时就中止,因为该(标签)组合是无效的。

注意: 如果你使用 LTO 构建 Rust 代码,你就可能甚至不需要打开 embed-bitcode 选项。你可能会想要使用 -Clinker-plugin-lto 来代替,它会完全跳过生成目标文件,并且用 LLVM 位码来简单替换目标文件。唯一的使用 -Cembed-bitcode 的目的是当你要生成同时使用和不使用 LTO 的 rlib 时,例如 Rust 标准库带有嵌入的位码,因为用户可以使用或不使用 LTO 进行链接。

这也可能会让你想知道为什么该选项的默认值是 yes 。理由是在 1.45 中及更早版本中是这样的。在 1.45 中,将此选项默认值调整为关闭。

extra-filename

该选项允许你将额外的数据放进每个输出文件。它需要一个字符串作为后缀添加到文件名中。更多信息请参阅 --emit 标签 。

force-frame-pointers

该标签可以强制栈帧指针的使用。其采用以下值之一:

  • y, yes, on, 或者无值: 强制启用栈帧指针。
  • n, no, 或 off: 不强制启用栈帧指针,但这并不意味着移除栈帧指针。

如果没有强制启用栈帧指针,则默认行为取决于目标平台。

force-unwind-tables

该标签强制栈回溯表的生成。其采用以下值之一:

  • y, yes, on, 或者无值: 强制生成栈回溯表。
  • n, no, 或 off: 不强制生成栈回溯表。如果目标平台或 -C panic=unwind 需要栈回溯表,就会触发一个错误。

默认值如果没有指明则取决于目标平台。

incremental

该标签允许你启用增量编译,这允许 rustc 在编译完 crate 之后保存信息,以便重新编译 crate 的时候可以重用,缩短重编译的时间。这将采用一个存放增量文件的目录的路径。

inline-threshold

该选项使你可以设置内联函数的默认阈值。其值采用无符号整数。内联基于成本模型( cost model ),较高的阈值将会允许更多的内联。

默认(阈值)取决于 opt-level:

opt-levelThreshold
0N/A, 仅内联强制内联函数( always-inline functions )
1N/A, 仅内联强制内联函数和 LLVM 生命周期内联函数 ( LLVM lifetime intrinsics )
2225
3275
s75
z25

该标签使你可以在链接器调用后附加一个额外的参数。

“附加” 是很重要的;你可以多次传递该标签以添加多个参数。

该标签使你可以在链接器调用后附加多个额外的参数。该选项(后的参数)应该用空格分隔。

该标签控制链接器是否保留无效代码。其采用以下值之一:

  • y, yes, on, 或者无值: 保留无效代码。
  • n, no, 或 off: 移除无效代码(默认值)。

该标签的一个有用的例子是当试图构造代码覆盖率指标的时候(译者注:也就是说试图保留无效代码,咳咳。。)。

在支持该标签的目标平台上,该标签控制链接器使用 Rust 附带的库和对象,还是使用系统中的库和对象。其采用以下值之一:

  • 无值: 如果系统已经有了必要的工具, rustc 将使用启发式禁用 self-contained 模式。
  • y, yes, on: 仅使用 Rust 附带的库/对象。
  • n, no, 或 off: 取决于用户或链接器(是否)提供非 Rust 的 库/对象。

当检测失败或用户想要使用附带的库时,这可以覆盖大多数情况。

linker

该标签控制 rustc 调用哪个链接器来链接代码。它接受链接器可执行文件的路径。如果该标签未指明,使用的链接器就会根据目标来推断。另外,请参阅 linker-flavor 标签 —— 指定链接器的另一种方法。

linker-flavor

该标签控制 rustc 使用的链接器的样式。 如果给编译器附加 -C linker 标签 ,那么链接器样式将从提供的值中推断出来。如果没有给出链接器,则会使用链接器样式来确定要使用的链接器。每个 rustc 目标都默认有一些链接器样式。有效的选项有:

  • em: 使用 Emscripten emcc.
  • gcc: 使用 cc 可执行文件, 在许多系统上通常是 gcc 或 clang 。
  • ld: 使用 ld 可执行文件
  • msvc: 使用 Microsoft Visual Studio MSVC 的 link.exe 可执行文件。
  • ptx-linker: 使用 Nvidia NVPTX GPGPU 所支持的 rust-ptx-linker 。
  • wasm-ld: 使用可执行文件 wasm-ld , 一个用于 WebAssembly 的 LLVM lld 端口。
  • ld64.lld: 对于 apple 的 ld,使用附加 -flavor darwin 标签 的 LLVM lld 可执行文件。
  • ld.lld: 对于 GNU binutil 的 ld,使用附加 -flavor gnu 标签 的 LLVM lld 可执行文件。
  • lld-link: 对于Microsoft 的 link.exe,使用附加 -flavor link 标签 的 LLVM lld 可执行文件。

linker-plugin-lto

该标签将 LTO 优化推迟到 链接器阶段。 更多细节请参阅 linker-plugin-LTO 。 其采用以下值之一:

  • y, yes, on, 或者无值:启用 linker plugin LTO 。
  • n, no, 或 off: 禁用 linker plugin LTO (默认)。
  • 一个链接器插件( linker plugin )的路径。

更具体地说,该标签将使得编译器将其通常的目标文件输出( typical object file output )替换为 LLVM 位码文件。 例如,使用 -Clinker-plugin-lto 生成的 rlib 会仍然有 *.o 文件在其中, 但实际上它们都是 LLVM 位码而非机器码。 预计本平台链接器可以加载这些 LLVM 位码文件并在链接时生成代码(通常在执行优化之后)。

注意, rustc 也可以读取由 -Clinker-plugin-lto 生成的它自己的目标文件。如果 rlib 只会在使用 -Clto 编译时使用,那么可以传递 -Clinker-plugin-lto 标签来加速编译,并避免生成不使用的目标文件。

llvm-args

该标签可以用来将参数列表直接传递给 LLVM 。

该列表必须用空格来分隔。

传递 --help 来查看选项列表。

lto

该标签控制是否 LLVM 用 链接时间优化 来产生更好的优化代码,使用完整的程序分析,以更长的链接时间为代价。其采用以下值之一:

  • y, yes, on, fat, 或无值:执行 "fat" LTO ,即尝试将依赖图中的所有依赖跨 crate 执行优化。
  • n, no, off: 禁用 LTO 。
  • thin: 执行 "thin" LTO 。这类似于 "fat" ,但会花费更少的时间(优化),同时仍然可以得到类似于 "fat" 的性能提升。

如果没有指定 -C lto , 那么编译器就会尝试执行 "thin local LTO" ,即只在本地 crate 上跨其代码生成单元 执行 "thin" LTO (which performs "thin" LTO on the local crate only across its codegen units )。 当未指定 -C lto 时,如果代码生成单元是 1 或优化被禁用(-C opt-level=0),则 LTO 将被禁用。即是:

  • 当 -C lto 未指定:
    • codegen-units=1: 禁用 LTO 。
    • opt-level=0: 禁用 LTO。
  • 当 -C lto=true:
    • lto=true: 16 个代码生成单元, 跨 crate 执行 fat LTO 。
    • codegen-units=1 + lto=true: 1 个代码生成单元, 跨 crate 执行 fat LTO 。

跨语言 LTO 请参阅 linker-plugin-lto。

metadata

该选项使你可以控制用于符号修饰(symbol mangling)。其采用值为以空格分隔的字符串列表。修饰后的符号将会合并元数据的 hash 。例如,这可以在链接时用来区分相同 crate 的两个不同版本之间符号。

no-prepopulate-passes

该标签告诉传递管理器(pass manager)使用一个空的传递列表而非通常的预填充了的传递列表。

no-redzone

该标签允许你禁用 the red zone 。 其采用以下值之一:

  • y, yes, on,或无值: 禁用 the red zone 。
  • n, no, 或 off: 启用 the red zone 。

如果该标签未指定,默认行为取决于目标系统。

no-stack-check

该选项已被弃用,且不执行任何操作。

no-vectorize-loops

该标签禁用 循环矢量化( loop vectorization )。

no-vectorize-slp

该标签禁用矢量化使用 superword-level parallelism 。

opt-level

该标签控制优化级别。

  • 0: 没有优化,同时打开 cfg(debug_assertions)(默认值)。
  • 1:基本的优化(basic optimizations)。
  • 2:一些优化(some optimizations)。
  • 3: 全部优化(all optimizations)。
  • s:优化二进制大小(optimize for binary size)。
  • z:优化二进制大小,同时关闭循环矢量化。

注意: -O 标签 是 -C opt-level=2 的一个别名。

默认值为 0。

overflow-checks

该标签允许你控制 运行时整数溢出的行为。当 overflow-checks 被启用时,溢出时会发出一个 panic 。该标签采用以下值之一:

  • y, yes, on, 或无值:开启 overflow checks 。
  • n, no, or off: 禁用 overflow checks 。

倘若未指定 overflow checks,如果 debug-assertions 是启用的 overflow checks 才会启用,否则是禁用的。

panic

该标签使你在代码 panic 时控制(程序栈)行为情况。

  • abort:在 panic 时终止进程。
  • unwind:在 panic 时对栈进行展开。

如果未指定,默认值取决于目标。

passes

该标签可以用于添加额外的 LLVM passes 到编译中。

列表必须以空格分隔。

另请参阅 no-prepopulate-passes 标签。

prefer-dynamic

默认情况下,rustc 更倾向于静态链接依赖项。该选项表明,如果库的静态和动态版本都是可用的,则应尽可能使用动态链接。有一个内部算法用于确定是否可以静态或动摇地链接依赖项。例如, cdylib crate 类型只能使用静态链接。该标采用以下值之一:

  • y, yes, on, 或无值: 使用动态链接。
  • n, no, 或 off: 使用静态链接(默认值)。

profile-generate

该标签允许创建用于收集分析数据的仪器化二进制文件(instrumented binaries),用于 PGO 。该标签采用一个可选参数,该参数是一个目录的路径,仪器化二进制文件将会把收集到的数据发送到该目录中。更多信息请参阅 PGO 章节。

profile-use

该标签指定用于 PGO 的分析数据文件。该标签采用一个强制参数,它是一个有效的 .profdata 文件的路径。更多信息请参阅 PGO 章节。

relocation-model

该选项控制 地址无关代码 (PIC) 的生成。

该选项支持的值有:

Primary relocation models

  • static - 不可重定位代码,机器指令得使用绝对寻址模式。

  • pic - 完全可重定位独立代码,机器指令需要使用相对寻址模式。
    等效于在其它编译器 “大写” -fPIC 或 -fPIE 选项,取决于产生的 crate 类型。
    这是大多数受支持目标的默认 model。

Special relocation models

  • dynamic-no-pic - 可重定位外部引用,不可重定位代码。
    仅对 Darwin 操作系统有用,并且很少使用
    如果 StackOverflow 告诉你将其作为 PIC 或 PIE 的退出选项, 不要相信它,应该使用 -C relocation-model=static 。
  • ropi, rwpi 和 ropi-rwpi - 可重定位代码和只读数据, 可重定位的读写数据, 以及两者的组合。
    只对特定的 嵌入式 ARM 目标有意义。.
  • default -重定位默认模型到当前目标
    仅有的意义是作为对先前在命令行上设置的其他一些明确指定的重定位模型的替代。

也可以通过运行 rustc --print relocation-models 查找支持的值。

Linking effects

除了代码生成效果之外, relocation-model 在链接期间也有效果。

如果重定位模型是 pic ,并且当前目标支持地址无关可执行文件(PIE),则将指示链接器生成一个(地址无关可执行文件)。
如果目标不支持地址无关且静态链接的可执行文件,那么 -C target-feature=+crt-static 会“超过” -C relocation-model=pic,并指示链接器(-static)生成静态链接但不是地址无关的可执行文件。

remark

该标签允许你打印优化传递命令的备注。

传递命令的列表应该用空格分隔。

(如果是)all 将会对每个传递命令备注。

rpath

该标签控制是否启用 rpath 。其采用以下值之一:

  • y, yes, on, 或者无值: 启用 rpath 。
  • n, no, 或 off: 禁用 rpath (默认值)。

save-temps

该标签控制在编译完成后是否删除编译过程中生成的临时文件。其采用以下值之一:

  • y, yes, on, 或者无值:保存临时文件。
  • n, no, 或 off:删除临时文件(默认值)。

soft-float

该选项控制是否 rustc 生成模拟软件中浮点指令的代码。其采用以下值之一:

  • y, yes, on, 或者无值: 使用软浮点数。
  • n, no, 或 off: 使用硬件浮点数(默认值)。

target-cpu

这会指示 rustc 生成专用于特定处理器的代码。

你可以运行 rustc --print target-cpus 来查看此处有效的传递选项。每个目标都有一个默认的基础 CPU 。 特殊值包括:

  • native 可以传递给使用该主机处理器(同样的机器)。
  • generic 指具有最少的 features 但经过现代调优的一个 LLVM 目标。

target-feature

各个目标会支持不同的 features ; 该标签使你可以控制启用或禁用 feature 。 每个 feature 应该以一个 + 或 - 来做前缀来启用或禁用 feature 。

多个 features 通过 -C target-feature 选项的是可组合的。
多个 features 可以在单个选项中使用逗号分隔符指定—— -C target-feature=+x,-y。
如果某些 feature 同时使用 + 和 - 指定了一次或多次,那么后面传递的值会覆盖前面传递的值。
例如, -C target-feature=+x,-y,+z -Ctarget-feature=-x,+y 等价于 -C target-feature=-x,+y,+z.

要查看有效的选项和使用示例,请运行 rustc --print target-features。

使用该标签是不安全的,可能会导致 未定义的运行时行为.

同样请参阅 target_feature attribute 控制每个函数的 features 。

这也支持 +crt-static 和 -crt-static feature 来控制 静态 C 运行时链接.

每个 target 和 target-cpu 都有一组默认启用的 features 。

tune-cpu

这会指示 rustc 为特定处理器调度代码。这不会影响兼容性(指令集或 ABI),但应该会使得代码在所选定的 CPU 上更有效率。

有效的选项与 target-cpu 的相同。默认值为 None, LLVM 将其转化为 target-cpu 。

这是个不稳定的选项。使用 -Z tune-cpu=machine 来指定值。

由于 LLVM (12.0.0-git9218f92)的限制,此选项当前仅针对 x86 目标有效。

JSON 输出

本章节介绍由 rustc 所发出的 JSON 的结构。可以通过 --error-format=json 标签 启用 JSON。可以使用 --json 标签 指定其他可以更改生成的消息以及消息的格式的选项。

JSON 消息每行都被发送到 stderr 。

如果使用 Rust 解析输出, cargo_metadata crate 提供了解析消息的一些支持。

当解析时,应注意与将来的格式更改保持向前兼容(译者注:向前兼容指的是以前的兼容以后的,而向后兼容就是以后的兼容以前的)。可选值可以为 null 。新的字段可能会添加。枚举字段如 “level” 或 “suggestion_applicability” 可以添加新的值。

诊断 (Diagnostics)

诊断消息会提供错误或在编译中可能产生的问题。 rustc 提供有关诊断来源的详细信息,以及提示和建议。

诊断以 parent/child 关系排列,其中 parent 诊断是诊断的核心,附加的 children 提供了其他的上下文,帮助和信息。

诊断有如下格式:

{
    /* 主消息 */
    "message": "unused variable: `x`",
    /* 诊断码
       一些消息可能将这个值设置为 null 。
    */
    "code": {
        /* 标识了触发哪个诊断的独一的字符串。 */
        "code": "unused_variables",
        /* 可选字符串,解释关于诊断码的更多细节。*/
        "explanation": null
    },
    /* 诊断信息的重要程度。
       值可能是:
       - "error": 无法编译的致命错误。
       - "warning": 可能的错误或预警。
       - "note": 诊断的附加信息或上下文。
       - "help": 解决诊断问题的建议。
       - "failure-note": 为了获取更多信息的附带说明。
       - "error: internal compiler error": 指明编译器内部的错误。
    */
    "level": "warning",
    /* 一个源代码位置数组,指出有关诊断来源的详细信息。这个数组可能是空的,例如,
    对于一些全局消息,或者附加到 parent 的 child 消息,就可能是空的。

       字符偏移量是 Unicode 标量的偏移量。
    */
    "spans": [
        {
            /* span 所在的文件。
               注意,此路径可能不存在。例如,如果路径指向标准库,而
               rust src 在系统根目录中不可用, 那么它可能会指向一个不存在的文件。
               注意,这也可能指向外部 crate 源。
            */
            "file_name": "lib.rs",
            /* span 开始的字节偏移量(基于0且包含0)。 */
            "byte_start": 21,
            /* span 结束的字节偏移量(基于0且不包含0)。 */
            "byte_end": 22,
            /* span 的第一行编号(基于1且包含1)。 */
            "line_start": 2,
            /* span 的最后一行编号(基于1且包含1)。 */
            "line_end": 2,
            /* 行首(line_start)的第一个字符偏移量(基于1且包含1) */
            "column_start": 9,
            /* 行尾(line_end)的最后一个字符偏移量(基于1且不包含1) */
            "column_end": 10,
            /* 不管这是不是 "primary" span。

               这表明这个 span 是该诊断的焦点所在(focal)。

               在少数情况下,多个 span 可能被标记为 primary。 例如 "immutable borrow occurs here" 和
               "mutable borrow ends here" 可以是两个独立的 primary span。

               top (parent) 消息应该有至少一个 rimary span ,除非有 0 个 span 。
               child 消息有 0 个或多个 primary span 。
            */
            "is_primary": true,
            /* 一个对象数组,显示该 span 的原始源代码。这将展示 span 所在的整行文本 。跨多行的 span 对于每行会有一个单独对应的值。
            */
            "text": [
                {
                    /* 完整的原始源代码行。 */
                    "text": "    let x = 123;",
                    /* span 所指行的首字符偏移量(基于1且包含1)。 */
                    "highlight_start": 9,
                    /* span 所指行的最后一个字符偏移量(基于1且不包含1)。 */
                    "highlight_end": 10
                }
            ],
            /* 一个可选消息,用于显示 span 位置。对于主 span ,这通常为 null 。
            */
            "label": null,
            /* 一个可选字符串,对于解决该问题建议的替换。 工具( Tools )可能会尝试用此文本替换该 span 的内容 。
            */
            "suggested_replacement": null,
            /* 一个可选字符串,指出 "suggested_replacement" 的置信度。工具(  Tools )可能会用这个值来决定是否自动应用建议(的替换)。

               可能的值可以是:
               - "MachineApplicable": 该建议无疑是用户的意图。该建议应该自动被应用。
               - "MaybeIncorrect": 该建议可能是用户的意图,但不确定。如果应用了该建议,则应该产生有效的 Rust 代码。
               - "HasPlaceholders": 该建议包含占位符,如
                 `(...)`。 建议不会被自动应用因为它不会产生有效的 Rust 代码。用户需要填充该占位符。
               - "Unspecified": 建议的适用性尚不清楚。
            */
            "suggestion_applicability": null,
            /* 一个可选对象,指出该 span 内的宏展开。

               如果消息发生在宏调用中,该对象将会提供该消息在宏展开所在位置的详细信息。
            */
            "expansion": {
                /* 宏调用的 span 。
                   使用与 "spans" 数组相同的 span 定义。
                */
                "span": {/*...*/}
                /* 宏名称, 例如 "foo!" 或 "#[derive(Eq)]"。 */
                "macro_decl_name": "some_macro!",
                /* 可选的 span ,定义了宏的相关部分 */
                "def_site_span": {/*...*/},
            }
        }
    ],
    /* 附加诊断消息的数组。
       这是一个对象数组,使用与 parent 消息相同的格式。
       children 没有嵌套 ( children 自身不包含 "children" 的定义 )
    */
    "children": [
        {
            "message": "`#[warn(unused_variables)]` on by default",
            "code": null,
            "level": "note",
            "spans": [],
            "children": [],
            "rendered": null
        },
        {
            "message": "if this is intentional, prefix it with an underscore",
            "code": null,
            "level": "help",
            "spans": [
                {
                    "file_name": "lib.rs",
                    "byte_start": 21,
                    "byte_end": 22,
                    "line_start": 2,
                    "line_end": 2,
                    "column_start": 9,
                    "column_end": 10,
                    "is_primary": true,
                    "text": [
                        {
                            "text": "    let x = 123;",
                            "highlight_start": 9,
                            "highlight_end": 10
                        }
                    ],
                    "label": null,
                    "suggested_replacement": "_x",
                    "suggestion_applicability": "MachineApplicable",
                    "expansion": null
                }
            ],
            "children": [],
            "rendered": null
        }
    ],
    /* 可选字符串,由 rustc 显示的诊断的 rendered 版本。注意这可能会受到 `--json` 标签的影响。
    */
    "rendered": "warning: unused variable: `x`\n --> lib.rs:2:9\n  |\n2 |     let x = 123;\n  |         ^ help: if this is intentional, prefix it with an underscore: `_x`\n  |\n  = note: `#[warn(unused_variables)]` on by default\n\n"
}

工件通知

当使用 --json=artifacts 标签 时就会触发工件通知( Artifact notification ,译者注,artifact 真的是一个很难恰到其处翻译的词语,所以这里只能约定俗成地翻译为“工件”) 。 它们指明了文件工件已经被保存到了磁盘中。有关发出(工件)类型的更多信息可以在 --emit 标签 文档中找到。

{
    /* 生成工件的文件名 */
    "artifact": "libfoo.rlib",
    /* 生成的工件的种类,可能的值有:
       - "link": 根据 crate 类型指定生成的 crate 。 
       - "dep-info": 具有依赖信息的 `.d` 文件,所用语法类似于 Makefile 文件的语法。
       - "metadata": 包含有关 crate 元数据的 Rust `.rmeta` 文件。
       - "save-analysis": 由 `-Zsave-analysis` feature 所发出的 JSON 文件 。
    */
    "emit": "link"
}

平台支持

对不同平台的支持被分成三层,每一层都有不同的保证集。

平台由他们的 “目标三元组” ("target triple") 标识,“目标三元组”是一个用来通知编译器应该产生何种输出的字符串。下表中的列具有以下含义:

  • std:
    • ✓ 表明完整的标准库可用。
    • * 表明目标仅支持 no_std 开发。
    • ? 表明标准库支持未知或者支持工作正在开展。
  • host: ✓ 表明 rustc 和 cargo 都能够在主机平台运行。

第一层

第一层平台可以视为 “保证可以工作”。具体说,它们每一种都将满足以下要求:

  • 对该平台提供了官方二进制发行版本。
  • 设置了自动测试以运行该平台的测试。
  • 对 rust-lang/rust 仓库 master 分支的更改取决于测试是否通过。
  • 提供了如何使用和构建此平台(程序)的文档。
targetstdhost备注
aarch64-unknown-linux-gnu✓✓ARM64 Linux (kernel 4.2, glibc 2.17+) 1
i686-pc-windows-gnu✓✓32-bit MinGW (Windows 7+)
i686-pc-windows-msvc✓✓32-bit MSVC (Windows 7+)
i686-unknown-linux-gnu✓✓32-bit Linux (kernel 2.6.32+, glibc 2.11+)
x86_64-apple-darwin✓✓64-bit macOS (10.7+, Lion+)
x86_64-pc-windows-gnu✓✓64-bit MinGW (Windows 7+)
x86_64-pc-windows-msvc✓✓64-bit MSVC (Windows 7+)
x86_64-unknown-linux-gnu✓✓64-bit Linux (kernel 2.6.32+, glibc 2.11+)
1

aarch64-unknown-linux-gnu 缺少对堆栈探针(Stack probes)的支持,计划在不久的将来实现。跟踪实现可以查看 issue #77071.

第二层

第二层平台可以视为 “保证可以构建”。不会运行自动测试,因此不保证生成的构建可工作,但是(如果能工作)平台通常能工作的相当好,补丁也很受欢迎!具体说,它们每一种都将满足以下要求:

  • 对该平台提供了官方二进制发行版本。
  • 设置了自动构建,但可能没有运行测试。
  • 对 rust-lang/rust 仓库 master 分支的更改取决于平台构建。一些平台只编译标准库,但另一些也能编译运行 rustc 和 cargo 。
targetstdhostnotes
aarch64-apple-darwin✓✓ARM64 macOS (11.0+, Big Sur+)
aarch64-apple-ios✓ARM64 iOS
aarch64-fuchsia✓ARM64 Fuchsia
aarch64-linux-android✓ARM64 Android
aarch64-pc-windows-msvc✓✓ARM64 Windows MSVC
aarch64-unknown-linux-musl✓✓ARM64 Linux with MUSL
aarch64-unknown-none*Bare ARM64, hardfloat
aarch64-unknown-none-softfloat*Bare ARM64, softfloat
arm-linux-androideabi✓ARMv7 Android
arm-unknown-linux-gnueabi✓✓ARMv6 Linux (kernel 3.2, glibc 2.17)
arm-unknown-linux-gnueabihf✓✓ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
arm-unknown-linux-musleabi✓ARMv6 Linux with MUSL
arm-unknown-linux-musleabihf✓ARMv6 Linux with MUSL, hardfloat
armebv7r-none-eabi*Bare ARMv7-R, Big Endian
armebv7r-none-eabihf*Bare ARMv7-R, Big Endian, hardfloat
armv5te-unknown-linux-gnueabi✓ARMv5TE Linux (kernel 4.4, glibc 2.23)
armv5te-unknown-linux-musleabi✓ARMv5TE Linux with MUSL
armv7-linux-androideabi✓ARMv7a Android
armv7a-none-eabi*Bare ARMv7-A
armv7r-none-eabi*Bare ARMv7-R
armv7r-none-eabihf*Bare ARMv7-R, hardfloat
armv7-unknown-linux-gnueabi✓ARMv7 Linux (kernel 4.15, glibc 2.27)
armv7-unknown-linux-gnueabihf✓✓ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17)
armv7-unknown-linux-musleabi✓ARMv7 Linux, MUSL
armv7-unknown-linux-musleabihf✓ARMv7 Linux with MUSL
asmjs-unknown-emscripten✓asm.js via Emscripten
i586-pc-windows-msvc✓32-bit Windows w/o SSE
i586-unknown-linux-gnu✓32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
i586-unknown-linux-musl✓32-bit Linux w/o SSE, MUSL
i686-linux-android✓32-bit x86 Android
i686-unknown-freebsd✓32-bit FreeBSD
i686-unknown-linux-musl✓32-bit Linux with MUSL
mips-unknown-linux-gnu✓✓MIPS Linux (kernel 4.4, glibc 2.23)
mips-unknown-linux-musl✓MIPS Linux with MUSL
mips64-unknown-linux-gnuabi64✓✓MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
mips64-unknown-linux-muslabi64✓MIPS64 Linux, n64 ABI, MUSL
mips64el-unknown-linux-gnuabi64✓✓MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
mips64el-unknown-linux-muslabi64✓MIPS64 (LE) Linux, n64 ABI, MUSL
mipsel-unknown-linux-gnu✓✓MIPS (LE) Linux (kernel 4.4, glibc 2.23)
mipsel-unknown-linux-musl✓MIPS (LE) Linux with MUSL
nvptx64-nvidia-cuda✓--emit=asm generates PTX code that runs on NVIDIA GPUs
powerpc-unknown-linux-gnu✓✓PowerPC Linux (kernel 2.6.32, glibc 2.11)
powerpc64-unknown-linux-gnu✓✓PPC64 Linux (kernel 2.6.32, glibc 2.11)
powerpc64le-unknown-linux-gnu✓✓PPC64LE Linux (kernel 3.10, glibc 2.17)
riscv32i-unknown-none-elf*Bare RISC-V (RV32I ISA)
riscv32imac-unknown-none-elf*Bare RISC-V (RV32IMAC ISA)
riscv32imc-unknown-none-elf*Bare RISC-V (RV32IMC ISA)
riscv64gc-unknown-linux-gnu✓✓RISC-V Linux (kernel 4.20, glibc 2.29)
riscv64gc-unknown-none-elf*Bare RISC-V (RV64IMAFDC ISA)
riscv64imac-unknown-none-elf*Bare RISC-V (RV64IMAC ISA)
s390x-unknown-linux-gnu✓✓S390x Linux (kernel 2.6.32, glibc 2.11)
sparc64-unknown-linux-gnu✓SPARC Linux (kernel 4.4, glibc 2.23)
sparcv9-sun-solaris✓SPARC Solaris 10/11, illumos
thumbv6m-none-eabi*Bare Cortex-M0, M0+, M1
thumbv7em-none-eabi*Bare Cortex-M4, M7
thumbv7em-none-eabihf*Bare Cortex-M4F, M7F, FPU, hardfloat
thumbv7m-none-eabi*Bare Cortex-M3
thumbv7neon-linux-androideabi✓Thumb2-mode ARMv7a Android with NEON
thumbv7neon-unknown-linux-gnueabihf✓Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23)
thumbv8m.base-none-eabi*ARMv8-M Baseline
thumbv8m.main-none-eabi*ARMv8-M Mainline
thumbv8m.main-none-eabihf*ARMv8-M Mainline, hardfloat
wasm32-unknown-emscripten✓WebAssembly via Emscripten
wasm32-unknown-unknown✓WebAssembly
wasm32-wasi✓WebAssembly with WASI
x86_64-apple-ios✓64-bit x86 iOS
x86_64-fortanix-unknown-sgx✓Fortanix ABI for 64-bit Intel SGX
x86_64-fuchsia✓64-bit Fuchsia
x86_64-linux-android✓64-bit x86 Android
x86_64-rumprun-netbsd✓64-bit NetBSD Rump Kernel
x86_64-sun-solaris✓64-bit Solaris 10/11, illumos
x86_64-unknown-freebsd✓✓64-bit FreeBSD
x86_64-unknown-illumos✓✓illumos
x86_64-unknown-linux-gnux32✓64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
x86_64-unknown-linux-musl✓✓64-bit Linux with MUSL
x86_64-unknown-netbsd✓✓NetBSD/amd64
x86_64-unknown-redox✓Redox OS

第三层

第三层平台是 Rust 代码库支持的平台,但不会自动构建或测试,并且可能无法工作,官方构建不可用。

targetstdhostnotes
aarch64-apple-ios-macabi?Apple Catalyst on ARM64
aarch64-apple-tvos*ARM64 tvOS
aarch64-unknown-freebsd✓✓ARM64 FreeBSD
aarch64-unknown-hermit?
aarch64-unknown-netbsd✓✓
aarch64-unknown-openbsd✓✓ARM64 OpenBSD
aarch64-unknown-redox?ARM64 Redox OS
aarch64-uwp-windows-msvc?
aarch64-wrs-vxworks?
armv4t-unknown-linux-gnueabi?
armv5te-unknown-linux-uclibceabi?ARMv5TE Linux with uClibc
armv6-unknown-freebsd✓✓ARMv6 FreeBSD
armv6-unknown-netbsd-eabihf?
armv7-apple-ios✓ARMv7 iOS, Cortex-a8
armv7-unknown-freebsd✓✓ARMv7 FreeBSD
armv7-unknown-netbsd-eabihf✓✓
armv7-wrs-vxworks-eabihf?
armv7a-none-eabihf*ARM Cortex-A, hardfloat
armv7s-apple-ios✓
avr-unknown-gnu-atmega328✗AVR. Requires -Z build-std=core
hexagon-unknown-linux-musl?
i386-apple-ios✓32-bit x86 iOS
i686-apple-darwin✓✓32-bit macOS (10.7+, Lion+)
i686-pc-windows-msvc✓32-bit Windows XP support
i686-unknown-uefi?32-bit UEFI
i686-unknown-haiku✓✓32-bit Haiku
i686-unknown-netbsd✓✓NetBSD/i386 with SSE2
i686-unknown-openbsd✓✓32-bit OpenBSD
i686-uwp-windows-gnu?
i686-uwp-windows-msvc?
i686-wrs-vxworks?
mips-unknown-linux-uclibc✓MIPS Linux with uClibc
mipsel-unknown-linux-uclibc✓MIPS (LE) Linux with uClibc
mipsel-unknown-none*Bare MIPS (LE) softfloat
mipsel-sony-psp*MIPS (LE) Sony PlayStation Portable (PSP)
mipsisa32r6-unknown-linux-gnu?
mipsisa32r6el-unknown-linux-gnu?
mipsisa64r6-unknown-linux-gnuabi64?
mipsisa64r6el-unknown-linux-gnuabi64?
msp430-none-elf*16-bit MSP430 microcontrollers
powerpc-unknown-linux-gnuspe✓PowerPC SPE Linux
powerpc-unknown-linux-musl?
powerpc-unknown-netbsd✓✓
powerpc-wrs-vxworks?
powerpc-wrs-vxworks-spe?
powerpc64-unknown-freebsd✓✓PPC64 FreeBSD (ELFv1 and ELFv2)
powerpc64-unknown-linux-musl?
powerpc64-wrs-vxworks?
powerpc64le-unknown-linux-musl?
riscv32gc-unknown-linux-gnuRISC-V Linux (kernel 5.4, glibc 2.33)
sparc-unknown-linux-gnu✓32-bit SPARC Linux
sparc64-unknown-netbsd✓✓NetBSD/sparc64
sparc64-unknown-openbsd?
thumbv7a-pc-windows-msvc?
thumbv7a-uwp-windows-msvc✓
thumbv7neon-unknown-linux-musleabihf?Thumb2-mode ARMv7a Linux with NEON, MUSL
thumbv4t-none-eabi*ARMv4T T32
x86_64-apple-ios-macabi✓Apple Catalyst on x86_64
x86_64-apple-tvos*x86 64-bit tvOS
x86_64-linux-kernel*Linux kernel modules
x86_64-pc-solaris?
x86_64-pc-windows-msvc✓64-bit Windows XP support
x86_64-unknown-dragonfly✓✓64-bit DragonFlyBSD
x86_64-unknown-haiku✓✓64-bit Haiku
x86_64-unknown-hermit?
x86_64-unknown-hermit-kernel?HermitCore kernel
x86_64-unknown-l4re-uclibc?
x86_64-unknown-openbsd✓✓64-bit OpenBSD
x86_64-unknown-uefi?
x86_64-uwp-windows-gnu✓
x86_64-uwp-windows-msvc✓
x86_64-wrs-vxworks?

Targets

rustc 默认情况下是一个交叉编译器。这意味着你可以使用任意平台的编译器构建任意体系架构(的程序)。 targets 清单列出了你可以构建的可能的体系架构目标。

要查看你可以为构建目标设置的所有选项,请查看文档。

使用 --target 标签将代码编译为特定目标:

$ rustc src/main.rs --target=wasm32-unknown-unknown

Target Features

x86 和 ARMv8 是两种流行的 CPU 体系架构。 它们的指令集是大多数 CPU 的通用基准。然而,一些 CPU 在其上扩展了自定义指令集来扩展功能,例如:用于向量( AVX ),位操作( BMI )或是加密( AES )。

知道编译的代码将在哪个 CUP 上运行的开发人员,可以通过运行 -C target-feature=val 标签添加(或删除) CPU 特定指令集。

请注意,该标签通常被认为是不安全的,更多细节可在本章中找到。

内置 Targets

rustc 能够自动编译代码为多个目标,我们称之为“内置” ("built-in") targets,他们通常与团队直接支持的目标相对应。 要查看内置 targets 的清单,可以运行 rustc --print target-list。

通常,目标 需要 Rust 标准库的编译副本才能工作。如果使用 rustup,想要了解如何下载由官方 Rust 发行版 构建的预构建标准库,请参阅关于 交叉编译 的文档。大多数目标需要系统链接器 (system linker),还有可能需要其他的东西。

自定义 Targets

如果你想要构建 rustc 尚不支持的目标, 你可以用 “自定义目标规范” ("custom target specification") 来定义目标。这些目标规范文件是 JSON 格式的。要查看主机目标的 JSON,可以运行:

$ rustc +nightly -Z unstable-options --print target-spec-json

要查看其他目标的 JSON,添加 --target 标签:

$ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json

要使用自定义目标,查看 cargo的 (尚不稳定) build-std feature 。

已知问题

本文将告知你一些已知的“陷阱” 。 请记住,本部分是(并且将始终是)不完整的。如有建议和修正,可以随时为本指南做 贡献 。

Target Features

当将启用了 target-feature 的代码和禁用 target-feature 的代码混合后,大多数 target-feature 出现了问题。如果想要避免未定义的行为,推荐用一组通用的 target-feature 构建所有的代码。

默认情况下,用 -C target-feature 标签编译代码将不会重新编译整个标准库 和/或( and/or ) 导入对应 target features 的 crate。因此, target features 通常被认为是不安全的,在单个函数上使用 #[target_feature] 属性会使得函数不安全。

例如:

Target-Feature问题所在架构描述细节
+soft-float
和
-sse
段错误和 ABI 不匹配x86 和 x86-64x86 和 x86_64 架构将 SSE 寄存器 (又名 xmm)用于浮点运算。使用软件模拟浮点数 ("soft-floats") 会禁用 xmm 寄存器。但 Rust 部分核心库 (例如 std::f32 或 std::f64) 编译时并没有使用 soft-floats 并且期望参数能传递到 xmm 寄存器。 这就导致了 ABI 不匹配。

尝试使用禁用的 SSE 编译也会导致此问题。
#63466

Profile Guided Optimization

rustc 支持使用 profile-guided optimization (PGO)。(译者注:该名词有时被译作配置文件引导优化/剖面引导优化,意思虽有契合但容易误导,此处以不译为好。) 本章描述 PGO 是什么,有什么优点,以及如何使用。

什么是 PGO?

PGO 的基本概念是收集关于一个程序典型的执行数据 (例如,它可能会执行的哪些分支)然后使用该数据来进行如内联,机器码布局,寄存器分配等告知优化。

有多种收集程序执行相关数据的办法。 一种是在分析器中运行程序 (例如 perf) 另一种是创建仪器化(instrumented)二进制文件,即已经内置了数据收集的二进制文件,并运行它。后者通常提供的数据更准确,这也是 rustc 所支持的。

用法

生成 PGO优化程序涉及到以下四个工作流程::

  1. 在开启检测工具的情况下编译程序(例如,rustc -Cprofile-generate=/tmp/pgo-data main.rs)
  2. 运行仪器化程序 (例如 ./main) 生成 default_<id>.profraw 文件。
  3. 使用 LLVM's llvm-profdata 工具转化 .profraw 文件为 .profdata 文件。
  4. 再次编译程序,此次使用分析数据(例如 rustc -Cprofile-use=merged.profdata main.rs)

一个仪器化程序将会创建一个或多个 .profraw 文件,每个 .profraw 文件对应一个仪器化程序 。例如,一个加载了两个仪器化动态库的仪器化可执行文件在运行时会生成三个 .profraw文件。另一方面,多次运行一个仪器化二进制文件,将会重新使用各自的 .profraw 文件,并在适当的地方更新它们。

这些 .profraw 文件必须被后期处理后才能被返回到编译器中,这是由 llvm-profdata 工具来完成的。该工具可以很轻易地通过以下命令安装:

rustup component add llvm-tools-preview

注意,安装 llvm-tools-preview 组件 不会将 llvm-profdata 添加到 PATH 中。而是可以在以下位置找到此工具:

~/.rustup/toolchains/<toolchain>/lib/rustlib/<target-triple>/bin/

或者 llvm-profdata 通常也可以使用最新的 LLVM 或 Clang 版本。

llvm-profdata 工具将多个 .profraw 文件合成单个的 .profdata文件然后就可以通过 -Cprofile-use 将其反馈给编译器:

# STEP 1: 使用工具编译二进制文件。
rustc -Cprofile-generate=/tmp/pgo-data -O ./main.rs

# STEP 2: 运行数次二进制文件,可以使用通用的参数集。
#         每次运行将会创建或更新在 /tmp/pgo-data 下的 `.profraw` 文件
./main mydata1.csv
./main mydata2.csv
./main mydata3.csv

# STEP 3: 合并和处理所有 /tmp/pgo-data 下的 `.profraw` 文件 
llvm-profdata merge -o ./merged.profdata /tmp/pgo-data

# STEP 4: 使用优化过程中合并的 `.profdata` 文件。所有 `rustc`标签
#         必须是相同的
rustc -Cprofile-use=./merged.profdata -O ./main.rs

完整的 Cargo 工作流程

在 Cargo 上使用此功能与直接使用 rustc非常相似。同样我们会生成一个仪表二进制文件 ,运行其以生成数据,合并数据,并将其反馈给编译器。 一些注意事项如下:

  • 我们使用 RUSTFLAGS 环境变量传递 PGO 编译器标签给程序中所有 crate 的编译。

  • 我们通过传递 --target 标签给 Cargo以防止 RUSTFLAGS 环境变量被传递给 Cargo 构建脚本。我们可不希望构建生成一堆 .profraw 文件的脚本。

  • 我们通过传递 --release 给 Cargo 因为这才是 PGO 最有意义的地方(译者注:也就是说PGO优化本应该用在构建发行版本程序)。 理论上, PGO 也可以在调试构建(debug builds)时进行,但没理由这么做。

  • -Cprofile-generate 和变量 -Cprofile-use 推荐使用 绝对路径 。Cargo 可以在不同工作目录调用 rustc , 这意味着 rustc 可能会无法找到提供的 .profdata 文件。如果使用绝对路径这将不是问题。

  • 确保不会遗留之前编译会话中的分析数据是一种较好实践(good practice)。仅删除(分析数据所在)目录是一种简单的办法 (参考下面的 STEP 0 )。

整个工作流程如下:

# STEP 0: 确保没有遗留之前运行产生的分析数据
rm -rf /tmp/pgo-data

# STEP 1: 构建仪器化二进制文件
RUSTFLAGS="-Cprofile-generate=/tmp/pgo-data" \
    cargo build --release --target=x86_64-unknown-linux-gnu

# STEP 2: 可使用一些经典数据
./target/x86_64-unknown-linux-gnu/release/myprogram mydata1.csv
./target/x86_64-unknown-linux-gnu/release/myprogram mydata2.csv
./target/x86_64-unknown-linux-gnu/release/myprogram mydata3.csv

# STEP 3: 合并 `.profraw` 文件进一个 `.profdata` 文件
llvm-profdata merge -o /tmp/pgo-data/merged.profdata /tmp/pgo-data

# STEP 4: 使用 `.profdata` 文件指导优化
RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \
    cargo build --release --target=x86_64-unknown-linux-gnu

故障排除

  • 建议在 -Cprofile-use 阶段传递 -Cllvm-args=-pgo-warn-missing-function。如果找不到给定函数的分析数据,LLVM 默认 不会发出警告。启用此警告将使你更容易发现设置中的错误。

  • 在 1.39版本以前的 Cargo 中有一个已知的问题,会阻止 PGO 的正常工作,当执行 PGO 优化的时候,请确保使用 Cargo 1.39 或更新的版本。

延伸阅读

rustc 的 PGO 支持完全依赖于 LLVM 对该特性的实现,相当于 Clang 通过 -fprofile-generate / -fprofile-use 标签提供的功能。对于任何想要使用 Rust 进行 PGO优化的人来说,Clang 文档的 Profile Guided Optimization 章节会是次悦读。

Linker-plugin-LTO

-C linker-plugin-lto 标签允许将 LTO (译者注:Linking Technology and Order)优化推迟到实际链接步骤中,如果要链接的所有目标文件(object files) 都是基于 LLVM 工具链优化的,则此标签又允许跨编程语言边界执行过程间优化,本文示例主要展示如何将 Rust 代码与使用 Clang 编译的 C/C++ 代码链接在一起。

用法

链接基于LTO的插件有两种主要的情况:

  • 编译 Rust staticlib 用于 C ABI 的依赖项。
  • 在 rustc 调用链接器的地方编译 Rust 二进制文件。

在这两种情况下,Rust代码需要用 -C linker-plugin-lto 编译,并且 c/c++ 代码使用 -flto 或 -flto=thin 以便将目标文件生成 LLVM 位码。

Rust staticlib 作为 C/C++ 程序中的依赖项

在这种情况下,Rust 编译器只需要确保 staticlib 中的目标文件格式正确即可。 要想进行链接,必须使用带有 LLVM 插件的链接器 (例如 LLD)。

直接使用 rustc :

# 编译 Rust staticlib
rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs
# 用 `-flto=thin` 编译 C代码
clang -c -O2 -flto=thin -o main.o ./main.c
# 链接起来,得先确保我们使用的是合适的链接器。
clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o

使用 cargo:

# 编译 Rust staticlib
RUSTFLAGS="-Clinker-plugin-lto" cargo build --release
# 用 `-flto=thin` 编译 C代码
clang -c -O2 -flto=thin -o main.o ./main.c
# 链接起来,得先确保我们使用的是合适的链接器。
clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o

C/C++ 代码作为 Rust 中的依赖项

在这种情况下,将由 rustc 调用链接器。我们再次必须确保使用合适的链接器。

直接使用 rustc :

# 用 `-flto=thin` 编译 C代码
clang ./clib.c -flto=thin -c -o ./clib.o -O2
# 从 C代码中创建静态库
ar crus ./libxyz.a ./clib.o

# 使用其他参数一起调用 `rustc`
rustc -Clinker-plugin-lto -L. -Copt-level=2 -Clinker=clang -Clink-arg=-fuse-ld=lld ./main.rs

直接使用 cargo:

# 用 `-flto` 编译 C代码
clang ./clib.c -flto=thin -c -o ./clib.o -O2
# 从 C代码中创建静态库
ar crus ./libxyz.a ./clib.o

# 通过 RUSTFLAGS 设置链接参数
RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build --release

明确指定 rustc 要使用的链接器插件

如果想要使用 LLD 以外的链接器,需要明确指定使用的 LLVM 链接器插件。否则链接器无法读取目标文件。插件的路径通过作为 -Clinker-plugin-lto 选项的参数传递:

rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs

工具链的兼容性

为了使这种 LTO 生效,LLVM 链接器插件必须能够处理由 rustc 和 clang 产生的 LLVM 位码。

通过使用基于相同版本的 LLVM 的 rustc 和 clang 实现可获得最佳结果。可以使用 rustc -vV 来查看给定 rustc 版本所使用的 LLVM。注意因为Rust有时会使用 LLVM 的不稳定版本,所以此处所给出的版本号只是一个近似值,但是这种近似通常是可靠的。

下表展示了已知工具链的良好组合。

Rust 版本Clang 版本
Rust 1.34Clang 8
Rust 1.35Clang 8
Rust 1.36Clang 8
Rust 1.37Clang 8
Rust 1.38Clang 9
Rust 1.39Clang 9
Rust 1.40Clang 9
Rust 1.41Clang 9
Rust 1.42Clang 9
Rust 1.43Clang 9
Rust 1.44Clang 9
Rust 1.45Clang 10
Rust 1.46Clang 10

注意,此处的兼容性策略将来可能会更改。

Contributing to rustc

我们很乐意如果你能帮助改进 rustc! 为此,我们编写了 一本完整的书 介绍其内部构造,工作原理,以及如何开始工作。想要了解更多信息,你需要查阅它。

如果你想对这本书做贡献, 你可以在 rustc 源代码中的 src/doc/rustc 找到其原文。