拓冰建站拓冰建站
首页 / 资讯中心 / 正文

rustc Lint 级别完全指南:allow、expect、warn、force-warn、deny 与 forbid 的语义、配置方法与优先级

rustc Lint 级别完全指南allow、expect、warn、force-warn、deny 与 forbid 的语义、配置方法与优先级【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust本指南以 Rust 编译器rustc文档 levels.md 为核心系统讲解 rustc 中六种 lint 级别的语义差异、两种配置入口命令行 flag 与源码属性、--cap-lints限制机制以及多来源之间的优先级规则。读完本文你将能精准控制任意 lint 的行为——从默认沉默到不可覆盖的错误并理解其背后的编译器实现原理可直接用于日常开发与 CI 严格化配置。六个 lint 级别总览在rustc中lint 被划分为六个级别levels每个 lint 都有一个默认级别可在 lint 列表 中查阅编译器本身也有一个默认的警告级别。六个级别由低到高依次为级别触发时的行为能否被覆盖allow什么都不做静默放行可expect抑制 lint但若 lint 未触发则报告期望未满足仅通过#[expect]属性设置warn产生警告编译继续可force-warn产生警告且不可被覆盖--cap-lints也无效否deny产生错误lint 检查完成后停止执行可forbid产生错误且不可被降级覆盖--cap-lints仍可封顶否下面逐一详解每个级别的含义然后再讨论配置方式。allow存在的 lint但默认什么都不做处于allow级别的 lint 是真实存在、并且会在编译时被检查的只是默认不产生任何输出。例如下面这段源码pub fn foo() {}编译它不会产生任何警告$ rustc lib.rs --crate-typelib $但这段代码实际上违反了missing_docslint公共 API 缺少文档注释。这类 lint 之所以存在主要是为了让用户通过配置手动打开它们正如本文后面配置警告级别一节所介绍的那样。missing_docs等默认允许的 lint 完整清单见 allowed-by-default 列表。expect抑制 lint但确保它仍然应该被触发有时候我们希望抑制某个 lint但同时又想确认代码中确实存在触发该 lint 的问题——expect级别正是为此设计的。如果被#[expect]的 lint 最终没有触发那么unfulfilled_lint_expectationslint 就会在expect属性上触发提醒你这条期望已经失效了可能是代码被修复也可能是该 lint 不再适用。fn main() { #[expect(unused_variables)] let unused Everyone ignores me; #[expect(unused_variables)] // unused_variables lint is not emitted let used Im useful; // the expectation is therefore unfulfilled println!(The used value is equal to: {:?}, used); }上面这段代码会输出如下警告warning: this lint expectation is unfulfilled -- src/main.rs:7:14 | 7 | #[expect(unused_variables)] | ^^^^^^^^^^^^^^^^ | note: #[warn(unfulfilled_lint_expectations)] on by default关于expect级别有两点需要特别注意它只能通过#[expect]属性定义没有对应的命令行 flag 等价物处于force-warn特殊级别的 lint即使被#[expect]包裹仍然会照常发出警告因为 force-warn 不可覆盖。expect机制的引入源自 RFC 2383编译器内部通过LintExpectationId把一次 lint 发射emission与具体的期望关联起来见 rustc_lint_defs 中的 Level 枚举 的相关注释。warn违反即警告warn级别会在违反 lint 时产生警告但编译流程继续执行。例如下面的代码触发了unused_variableslintpub fn foo() { let x 5; }编译输出$ rustc lib.rs --crate-typelib 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注意输出中的两行note第一行告诉你该 lint 的默认级别是warn第二行给出编译器建议的修复方式把x改成_x。这也是绝大多数 lint 的默认工作方式默认 warn 的 lint 清单见 warn-by-default 列表。force-warn不可覆盖的警告force-warn是一个特殊的 lint 级别。它和warn一样处于该级别的 lint 会产生警告但和warn不同的是它无法被覆盖一旦某个 lint 被设置为force-warn它就保证一定产生警告——不多不少。即使整体 lint 级别通过--cap-lints被封顶force-warn的警告依然会发出。这个级别的典型用途是编译器自身或构建系统强制要求某些信息必须可见不允许用户或下游配置把它静默掉。由于它不可覆盖一旦设置后续针对同一 lint 的任何其他级别设置都不会生效。deny违反即错误deny级别的 lint 在违反时会产生错误。例如下面的代码触发了exceeding_bitshiftslintfn main() { 100u8 10; }$ rustc main.rs error: bitshift exceeds the types number of bits -- main.rs:2:13 | 2 | 100u8 10; | ^^^^^^^^^^^ | note: #[deny(exceeding_bitshifts)] on by default那么lint 产生的错误和普通的编译器错误有什么区别区别在于lint 错误是通过级别机制配置的。和allow级别的 lint 类似默认就是deny的 lint 允许你把它降级为allow同理你也可以把一个默认warn的 lint 提升为错误。deny级别正是提供了这种灵活性。默认 deny 的 lint 清单见 deny-by-default 列表。forbid不可覆盖的错误forbid是deny的特殊版本两者关系正如force-warn之于warn。处于forbid级别的 lint 违反时产生错误但和deny不同它不能被覆盖为任何低于错误error的级别。不过 lint 级别仍然可以被--cap-lints封顶所以rustc --cap-lints warn会让设置为forbid的 lint 退化为仅警告。forbid特别适合用在库或项目的关键公共代码上——例如把unsafe_code设为forbid可以确保整个 crate 无论后续配置如何变化都不会悄悄出现unsafe代码。配置警告级别还记得前面allow级别中的missing_docs例子吗$ cat lib.rs pub fn foo() {} $ rustc lib.rs --crate-typelib $我们可以通过两种方式把这个 lint 配置到更高的级别编译器命令行 flag与源码中的属性attribute。此外还可以封顶caplint 级别让编译器忽略某些级别设置这部分放在最后讲。通过编译器 flag 配置-A、-W、--force-warn、-D、-F五个 flag 分别可以把一个或多个 lint 设置为 allow、warn、force-warn、deny、forbid 级别。例如$ rustc lib.rs --crate-typelib -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-typelib -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注意命令行输出中的requested on the command line with ...一行它表明该级别是通过命令行 flag 设置的。每个 flag 可以多次传参用来同时修改多个 lint$ rustc lib.rs --crate-typelib -D missing-docs -D unused-variables五个 flag 可以混用$ rustc lib.rs --crate-typelib -D missing-docs -A unused-variables命令行参数顺序会被考虑。下面的命令最终会 allowunused-variables因为-A是最后一个针对该 lint 的参数$ rustc lib.rs --crate-typelib -D unused-variables -A unused-variables可以利用这个顺序行为对某个 lint 组中的一个 lint 单独覆盖级别。下面的命令把unused组的所有 lint 设为 deny但显式把组内的unused-variables允许掉注意forbid无论顺序如何都优先$ rustc lib.rs --crate-typelib -D unused -A unused-variables由于force-warn和forbid不可覆盖一旦设置了其中一个后面针对同一 lint 的任何更高级别设置都不会生效。关于 lint 组lint group的完整概念与组成参见 lint groups 文档。也可以在安装了 rustc 的机器上直接运行rustc -W help查看当前编译器支持的所有 lint 组及其包含的具体 lint。通过属性配置除了命令行 flag还可以用crate 级属性修改 lint 级别$ cat lib.rs #![warn(missing_docs)] pub fn foo() {} $ rustc lib.rs --crate-typelib 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() {} | ^^^^^^^^^^^^注意这里输出了note: lint level defined here指向属性定义的位置。warn、allow、deny、forbid四种属性都可以这样使用没有方式用属性把 lint 设为force-warnforce-warn 只能通过命令行设置。每个属性可以传入多个 lint#![warn(missing_docs, unused_variables)] pub fn foo() {}也可以同时使用多个属性#![warn(missing_docs)] #![deny(unused_variables)] pub fn foo() {}所有 lint 属性都支持额外的reason参数用来说明添加该属性的上下文原因。如果 lint 在定义级别被触发这个 reason 会作为 lint 消息的一部分显示出来use std::path::PathBuf; pub fn get_path() - PathBuf { #[allow(unused_mut, reason this is only modified on some platforms)] let mut file_name PathBuf::from(git); #[cfg(target_os windows)] file_name.set_extension(exe); file_name }在上面的例子中unused_mut在非 Windows 平台上是多余的但开发者明确知道这一点因此用带reason的#[allow]既抑制了警告又为后来维护者留下了上下文说明。reason参数对应源码中LintLevelSource::Node的reason: OptionSymbol字段见 rustc_middle/src/lint.rs。封顶 lintCapping lintsrustc支持--cap-lints LEVELflag它设置lint 封顶层级lint cap level即所有 lint 级别的最大值。以前面deny一节的代码为例fn main() { 100u8 10; }编译时把 lint 封顶到 warn$ rustc lib.rs --cap-lints warn warning: bitshift exceeds the types 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现在它只警告而不再报错。还可以进一步把级别封顶为 allow让所有 lint 都沉默$ rustc lib.rs --cap-lints allow $Cargo 重度使用这个特性编译依赖时 Cargo 会传入--cap-lints allow这样依赖自身的警告不会污染你的构建输出。但请注意--cap-lints allow不会覆盖标记为force-warn的 lint——这一点在 rustc_session 的会话初始化逻辑 中也有体现当warnings被 allow 或 lint_cap 为 allow 时can_emit_warnings为 false但 force-warn 的强制发射路径不受此开关约束。lint 级别来源的优先级Rust 允许通过多种来源设置 lint 级别allow、warn、deny、forbid、force-warn属性Attributes#[allow(...)]、#![deny(...)]等命令行选项Command-line options--cap-lints、--force-warn、-A、-W、-D、-F。这些来源的交互规则如下1.--force-warn强制 lint 处于警告级别优先于属性和所有其他 CLI flag。#[forbid(unused_variables)] fn main() { let x 42; }编译命令及其输出$ rustc --force-warn unused_variables lib.rs warning: unused variable: x -- lib.rs:3:9 | 3 | let x 42; | ^ help: if this is intentional, prefix it with an underscore: _x | note: requested on the command line with --force-warn unused-variables warning: 1 warning emitted注意尽管源码里是#[forbid(unused_variables)]--force-warn依然把输出压成了警告。2.--cap-lints设置 lint 的最大级别优先于属性以及-D、-W、-F这些 CLI flag。#[deny(unused_variables)] fn main() { let x 42; }编译命令及其输出$ rustc --cap-lintswarn lib.rs warning: unused variable: x -- test1.rs:3:9 | 3 | let x 42; | ^ help: if this is intentional, prefix it with an underscore: _x | note: the lint level is defined here -- test1.rs:1:8 | 1 | #[deny(unused_variables)] | ^^^^^^^^^^^^^^^^ warning: 1 warning emitted3. CLI 级别 flag 覆盖 lint 的默认级别其行为本质上等同于 crate 级属性。源码中的属性优先于 CLI flag但-F/--forbid除外——它不可被覆盖。flag 的顺序有意义右边的 flag 优先于左边的。fn main() { let x 42; }编译命令及其输出$ rustc -A unused_variables -D unused_variables lib.rs error: unused variable: x -- test1.rs:2:9 | 2 | let x 42; | ^ help: if this is intentional, prefix it with an underscore: _x | note: requested on the command line with -D unused-variables error: aborting due to 1 previous error4. 在源码内部语法树中层级更低的属性作用域更小、更贴近节点的优先于层级更高的属性同一实体上的多个属性按从左到右的源码顺序后出现的优先。#![deny(unused_variables)] #[allow(unused_variables)] fn main() { let x 42; // Allow wins }在上面的代码中crate 级#![deny]被函数级的#[allow]覆盖因此x不会触发错误。唯一的例外是forbid一旦 lint 被设置为forbid再试图改变它的级别就是错误在 forbid 上下文中设置deny是被允许的语法但会被忽略。就优先级而言lint 组lint groups会被当作展开成其包含的所有 lint 的列表来处理唯一的例外是warnings组——它忽略属性与 CLI 的顺序作用于该实体上所有本会警告的 lint。源码视角lint 级别在编译器内部如何落地理解了语义和用法之后不妨看一下 rustc 源码中这些概念是如何建模的这有助于预测各种边界情况的行为。六个级别的枚举定义位于 compiler/rustc_lint_defs/src/lib.rsLevel::Allow、Level::Expect、Level::Warn、Level::ForceWarn、Level::Deny、Level::Forbid与本文介绍的六个级别一一对应。其文档注释还揭示了一些实现细节Expect不是 lint 的初始级别它需要携带一个LintExpectationId用于在 lint 实际发射时把发射与期望链接起来RFC 2383 的落地ForceWarn当前只能通过控制台命令行设置因此是 session 相关的Deny会产生错误并在 lint pass 完成后停止进一步执行。级别来源的建模位于 compiler/rustc_middle/src/lint.rsLintLevelSource枚举区分了三种来源——Defaultrustc 声明的默认级别、Node属性设置携带属性名、span 以及 RFC 2383 的 reason、CommandLine命令行 flag 设置记录 flag 名和指定的级别。每个 lint 的最终状态则由LevelSpec表示一个Level 可选的LintExpectationIdLintLevelSource其构造器会校验level/lint_id的组合合法性比如只有Expect才允许携带 lint_id。层级解析的数据结构位于 compiler/rustc_lint/src/levels.rsLintLevelSets维护一个LintSet的链表IndexVec每个LintSet对应 AST 上一个节点的属性集合parent指针把不同层级的节点串起来链表的起点是COMMAND_LINE 0命令行级别。raw_lint_level_spec从当前节点开始沿着parent向上回溯查找 lint 的级别定义找不到就返回命令行级别或默认值——这正是内层属性优先于外层属性、命令行作为兜底这一语义的代码级体现。封顶的实现与会话Session的lint_cap配置相关并在 rustc_session/src/session.rs 中参与决定can_emit_warnings从而影响常规警告是否输出。实践建议库作者对公共 API 开启#![warn(missing_docs)]在 CI 中用-D warnings把警告升级为错误防止文档缺失悄悄进入发布版本团队统一标准用-D unused、-D nonstandard-style等 lint 组一次性收紧多个检查再用顺序靠后的-A specific-lint对个别 lint 放行关键安全项对unsafe_code等使用#![forbid(...)]确保无论后续配置如何都无法降级对必须让用户看见的信息使用--force-warn依赖管理理解 Cargo 默认对依赖传入--cap-lints allow的行为——依赖中的警告不会出现在你的构建输出里因此不要在依赖编译结果中期待告警信息演进代码当 lint 不再适用时及时移除#[expect]属性借助unfulfilled_lint_expectations警告保持期望与代码同步。完整 lint 清单按默认级别分组与 lint 组定义可继续阅读 lint 列表 和 lint groups 两个章节。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门