资讯动态

Rust 编译器错误 E0670 深度解析:Rust 2015 中禁止使用 `async fn` 及迁移方案

发布时间:2026/9/10 20:07:07 来源:尧图企业网站定制
Rust 编译器错误 E0670 深度解析Rust 2015 中禁止使用async fn及迁移方案【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust导读Rust 编译器错误代码 E0670 是初学者在从 Rust 2015 edition 迁移到新版本时最常遇到的一个编译期错误其核心信息为Rust 2015 does not permit the use ofasync fn。本文以 compiler/rustc_error_codes/src/error_codes/E0670.md 官方错误文档为骨架结合 rustc 解析器源码与 UI 测试用例完整讲解该错误的触发条件、底层检测逻辑以及通过 Cargo 或直接调用 rustc 两种方式切换到新 edition 的实操方案。读完本文你将能够独立定位此类错误、理解编译器内部如何按 edition 差异化检查语法并正确完成项目迁移。E0670 错误概览错误信息原文E0670 的错误信息非常简短官方文档给出的完整描述为Rust 2015 does not permit the use ofasync fn.其附带的错误代码示例也是触发该错误的最简形式async fn foo() {} // error[E0670]: async fn is not permitted in Rust 2015对应的修复指引为切换到 Rust 2018 或更高版本 edition 后即可使用async fn。一个完整的真实报错输出在 2015 edition 下编译上述代码rustc 会输出类似如下的完整诊断引用自仓库 UI 测试的期望输出 tests/ui/async-await/edition-deny-async-fns-2015.stderrerror[E0670]: async fn is not permitted in Rust 2015 -- edition-deny-async-fns-2015.rs:3:1 | LL | async fn foo() {} | ^^^^^ to use async fn, switch to Rust 2018 or later | help: pass --edition 2024 to rustc note: for more on editions, read https://doc.rust-lang.org/edition-guide注意其中的细节主错误标签labelto use async fn, switch to Rust 2018 or later直接指示用户升级 edition帮助信息help根据编译方式自动给出具体命令例如直接调用 rustc 时是pass --edition 2024 to rustc当前仓库对应版本中 2024 为最新稳定 edition而通过 Cargo 构建时会改为set edition 2024 in Cargo.toml备注note指引阅读官方 edition 指南。为什么 Rust 2015 不允许async fnasync/await语法是在 Rust 2018 edition 中正式引入并稳定的语言特性Rust 2015 时代只存在基于 nightly 的实验性异步实现尚无稳定的async fn语法。Rust 通过edition版本代机制管理语言演进edition 允许编译器在保持向后兼容的同时为新语法保留关键字与语法空间。async在 2015 edition 中并非保留关键字因此在 2015 下解析async fn会直接被视为非法语法并报出 E0670而不是静默降级为其他语义。这一设计在 rustc 源码中体现为按 edition 差异化检查解析器在识别到async标记后会检查该标记所在代码是否属于 2015 edition若是则立即发出 E0670 诊断详见下文编译器源码实现一节。哪些位置会触发 E0670async fn并非只能在顶层函数中使用它出现在 Rust 2015 代码的任何位置都会报错。仓库中的 UI 测试 tests/ui/async-await/edition-deny-async-fns-2015.rs标注// edition:2015即强制以 2015 edition 编译系统地覆盖了所有触发场景共产生 9 处 E0670位置代码示例是否报错顶层自由函数async fn foo() {}✅ 报错普通函数体内的嵌套函数fn baz() { async fn foo() {} }✅ 报错异步函数内部的嵌套函数async fn async_baz() { async fn bar() {} }✅ 报错impl块中的方法impl Foo { async fn foo() {} }✅ 报错trait中的方法trait Bar { async fn foo() {} }✅ 报错宏展开产生的项accept_item! { async fn foo() {} }✅ 报错impl块经宏展开accept_item! { impl Foo { async fn bar() {} } }✅ 报错闭包内的嵌套函数let f \|\| { async fn bar() {} };✅ 报错从测试可以看到E0670 的检查覆盖所有语法上下文包括宏展开后的代码——因为宏展开结果会作为新语法树重新参与解析async fn项同样被 edition 检查捕获。这意味着迁移到 2018 时即使是通过宏生成的异步函数也必须满足 edition 要求。编译器源码实现E0670 是如何被触发的诊断结构定义E0670 的诊断结构定义在 compiler/rustc_parse/src/diagnostics.rs#L2202-L2209#[derive(Diagnostic)] #[diag(async fn is not permitted in Rust 2015, code E0670)] pub(crate) struct AsyncFnIn2015 { #[primary_span] #[label(to use async fn, switch to Rust 2018 or later)] pub span: Span, #[subdiagnostic] pub help: HelpUseLatestEdition, }其中HelpUseLatestEdition是一个枚举型子诊断compiler/rustc_parse/src/diagnostics.rs#L3709-L3728它会根据编译方式自动选择提示文案#[derive(Subdiagnostic)] pub(crate) enum HelpUseLatestEdition { #[help(set edition \{$edition}\ in Cargo.toml)] #[note(for more on editions, read https://doc.rust-lang.org/edition-guide)] Cargo { edition: Edition }, #[help(pass --edition {$edition} to rustc)] #[note(for more on editions, read https://doc.rust-lang.org/edition-guide)] Standalone { edition: Edition }, }其构造逻辑通过rustc_session::utils::was_invoked_from_cargo()判断当前 rustc 是否由 Cargo 调用由 Cargo 调用时提示修改Cargo.toml否则提示在命令行传--edition。这就是为什么同一错误在不同构建方式下会给出不同修复建议。解析阶段的 edition 检查E0670 在语法解析阶段而非类型检查阶段就被抛出检测点在函数声明解析器 compiler/rustc_parse/src/parser/function.rs#L435-L443if let Some(coroutine_marker) coroutine_marker let CoroutineKind::Async coroutine_marker.kind coroutine_marker.span.is_rust_2015() { self.dcx().emit_err(diagnostics::AsyncFnIn2015 { span: coroutine_marker.span, help: diagnostics::HelpUseLatestEdition::new(), }); }关键逻辑解读解析器先通过parse_coroutine_marker识别async以及gen等标记然后检查coroutine_marker.span.is_rust_2015()——即该标记所处的代码区域是否属于 2015 edition只有同时满足是async标记且位于 2015 edition 代码两个条件才发出 E0670。Span::is_rust_2015()意味着该检查精确到代码区域粒度即便整个 crate 声明为 2018 edition某些经宏生成或#[path]引入的、标记为 2015 edition 的 span 片段同样会被拦截。这也解释了为何宏展开的项也会报错——宏定义处的 edition 会被传播到展开后的 span 上。解决方案切换到 Rust 2018 或更高版本 editionRust edition 的稳定版本序列为 2015 → 2018 → 2021 → 2024。要修复 E0670只需将代码所属 edition 提升到 2018 或更高当前仓库对应的最新稳定 edition 为 2024。根据项目的构建方式有两种做法方式一通过 Cargo 构建推荐编辑项目根目录的Cargo.toml在[package]段中设置[package] name my_async_project version 0.1.0 edition 2024 # 或 2021 / 2018改完后直接重新cargo build即可。编译器自动检测到这是 Cargo 调用帮助信息会显示set edition 2024 in Cargo.toml。方式二直接调用 rustc不经过 Cargo、直接编译单个文件时在命令行追加--edition参数rustc --edition 2024 main.rs对应帮助信息为pass --edition 2024 to rustc。此方式适合快速验证单文件代码项目级开发仍建议在Cargo.toml中声明 edition。迁移后的验证示例// 切换到 2018 edition 后以下代码可正常编译 async fn foo() - u32 { 42 } fn main() { let fut foo(); // foo 返回一个 Future // 实际运行需要 executor如 async-std / tokio配合 .await println!(async fn accepted); }注意修复 E0670 只解决了语法层面的 edition 门槛。async fn调用后返回的是未执行pending的Future真正运行它还需要搭配异步运行时runtime并通过.await或block_on驱动——这属于 async 编程的后续话题与 E0670 本身无关。相关错误与同类检查E0671已被编译器移除的错误与 E0670 相邻的 compiler/rustc_error_codes/src/error_codes/E0671.md 目前已在文档开头注明this error code is no longer emitted by the compiler其原含义是const 参数不能依赖类型参数现由 E0770 覆盖。这提醒读者错误码文档可能滞后于编译器实现若某个错误码提示不再发出应以最新编译器行为为准。其他受 2015 edition 限制的 async 语法E0670 只是2015 不支持 async系列检查之一。在 compiler/rustc_parse/src/diagnostics.rs 中同文件还定义了AsyncBlockIn2015async块仅允许在 2018、AsyncMoveBlockIn2015async move块、AsyncUseBlockIn2015以及AsyncBoundModifierIn2015asynctrait 约束等诊断结构。也就是说Rust 2015 代码中不仅async fn被禁止async {}块、async move {}块以及asynctrait bound 同样会被拒绝。迁移到 2018 edition 时这些语法会一并解锁。如何验证与深入学习阅读官方错误文档compiler/rustc_error_codes/src/error_codes/E0670.md 是本错误的权威说明入口查看 UI 测试完整覆盖 9 种触发场景的用例在 tests/ui/async-await/edition-deny-async-fns-2015.rs其精确期望输出含每种场景的完整诊断信息在 tests/ui/async-await/edition-deny-async-fns-2015.stderr运行测试可在仓库根目录执行./x test tests/ui/async-await/edition-deny-async-fns-2015.rs验证编译器行为调试源码从解析器检测点 compiler/rustc_parse/src/parser/function.rs#L435-L443 入手配合诊断结构 compiler/rustc_parse/src/diagnostics.rs#L2202-L2209 理解完整链路。小结E0670 是 edition 机制作用于语法层的一个典型示例async fn作为 2018 edition 引入的特性在 2015 代码中任何位置出现都会触发编译错误。其检测发生在 rustc 解析阶段通过Span::is_rust_2015()按代码区域精确判定并依据构建方式Cargo 或裸 rustc给出差异化的修复提示。修复方法非常简单——将Cargo.toml中的edition或 rustc 的--edition参数提升到 2018/2021/2024 即可同时async块、async move块等系列语法也会一并解锁。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价