ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Rust 编译器错误码 E0757 详解:`[ffi_const]` 与 `[ffi_pure]` 属性冲突的成因与修复

Rust 编译器错误码 E0757 详解:`[ffi_const]` 与 `[ffi_pure]` 属性冲突的成因与修复 Rust 编译器错误码 E0757 详解#[ffi_const]与#[ffi_pure]属性冲突的成因与修复【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust导读E0757 是 rustc 在同一外部函数foreign function上同时标注#[ffi_const]与#[ffi_pure]两个优化提示属性时触发的编译错误。本文以错误码文档 E0757.md 为主线结合 link_attrs.rs 中两个属性的解析器实现与 diagnostics.rs 中的诊断定义说明该错误的触发条件、两个属性的语义差异、修复方法以及底层实现机制帮助读者在书写 FFI 声明时正确使用这两个 unstable 属性。错误概述一个函数不能同时声明为const和pure当 Rust 编译器在extern块中检测到同一个外部函数被同时赋予ffi_const与ffi_pure属性时会报告 E0757错误信息为#[ffi_const] function cannot be #[ffi_pure]该错误定义位于 diagnostics.rs#[derive(Diagnostic)] #[diag(#[ffi_const] function cannot be #[ffi_pure], code E0757)] pub(crate) struct BothFfiConstAndPure { #[primary_span] pub attr_span: Span, }attr_span指向出错属性所在的位置编译器会据此在源码中精确标注冲突点。触发场景错误示例文档给出的错误示例完整复现如下#![feature(ffi_const, ffi_pure)] extern C { #[unsafe(ffi_const)] #[unsafe(ffi_pure)] //~^ ERROR #[ffi_const] function cannot be #[ffi_pure] pub fn square(num: i32) - i32; }注意示例中的几个关键细节两个属性都必须通过#![feature(ffi_const, ffi_pure)]显式开启对应 unstable 特性门feature gate否则会先触发未启用特性的错误属性书写形式是#[unsafe(ffi_const)]/#[unsafe(ffi_pure)]。从 link_attrs.rs 中可以看到两者的SAFETY均声明为AttributeSafety::Unsafe即这两个属性被定义为 unsafe 属性必须放在unsafe(...)容器中两者都只能应用于外部函数ALLOWED_TARGETS仅允许Target::ForeignFn不能用于普通 Rust 函数由于FfiPureParser::finalize_check在所有属性收集完成后统一检查见下文实现机制一节因此无论ffi_const与ffi_pure的书写先后顺序如何只要同时出现就会报错。语义背景为什么const与pure不能共存E0757 之所以成立是因为ffi_const的保证比ffi_pure更强两者语义存在包含关系#[ffi_const]函数除返回值外不得有任何副作用且返回值只能依赖于函数参数的值不受程序可观察状态内存内容、全局变量等变化的影响。#[ffi_pure]函数除返回值外不得有任何副作用但其返回值允许依赖程序的可观察状态只要求相同参数下连续两次调用返回值不变。这两个语义说明直接内嵌在编译器源码的 unsafe 属性 note 中见 link_attrs.rspub(crate) struct FfiConstParser; impl NoArgsAttributeParser for FfiConstParser { const PATH: [Symbol] [sym::ffi_const]; const SAFETY: AttributeSafety AttributeSafety::Unsafe { note: #[ffi_const] functions shall have no effects except for its return value, which can only depend on the values of the function parameters, and is not affected by changes to the observable state of the program., unsafe_since: None, }; // ... } pub(crate) struct FfiPureParser; impl NoArgsAttributeParser for FfiPureParser { const PATH: [Symbol] [sym::ffi_pure]; const SAFETY: AttributeSafety AttributeSafety::Unsafe { note: #[ffi_pure] functions shall have no effects except for its return value, which shall not change across two consecutive function calls with the same parameters., unsafe_since: None, }; // ... }语义对应关系可以概括为属性允许副作用返回值依赖参数返回值依赖全局可观察状态相对强度#[ffi_const]否仅依赖参数不可依赖更强#[ffi_pure]否可以依赖允许依赖两次调用间不变较弱由于ffi_const蕴含了ffi_pure的全部约束再叠加ffi_pure属于重复且自相矛盾的声明编译器据此判定两者同注为非法组合。这两个属性对应 GCC 编译器中的const与pure函数属性Common Function Attributes在 Rust 中用于向编译器传递外部 C 函数的优化信息从而允许编译器执行更积极的优化如公共子表达式消除、循环外提等。属性语义由声明方承诺rustc 不做运行时验证一旦标注错误将产生未定义行为风险这正是其被设计为 unsafe 属性的原因。修复方法保留保证更强的ffi_const既然ffi_const提供比ffi_pure更强的保证修复方式就是移除ffi_pure只保留ffi_const#![feature(ffi_const)] extern C { #[unsafe(ffi_const)] pub fn square(num: i32) - i32; }修复后的语义square的返回值只取决于参数num不读取也不写入任何全局状态编译器可以放心地缓存其结果、消除重复调用。同理如果被标注函数实际上依赖了全局状态例如读取一个全局配置变量则不应使用ffi_const此时应反过来移除ffi_const而仅保留ffi_pure#![feature(ffi_pure)] extern C { #[unsafe(ffi_pure)] pub fn lookup(key: i32) - i32; }选择原则保证越强编译器优化空间越大但标注错误导致的 UB 风险也越高。只有确认外部函数确实只依赖参数时才能使用ffi_const仅能确认无副作用时使用ffi_pure更安全。源码实现机制错误是在哪里被检查出来的E0757 的产生路径分为三步属性解析FfiConstParser与FfiPureParser分别负责解析ffi_const、ffi_pure两个属性二者均为NoArgsAttributeParser即不接受参数。若给它们传入参数如#[unsafe(ffi_const 1)]会被解析为 malformed 属性报错——这一点在测试 malformed-attrs.rs 中有对应用例。收尾检查finalize_checkFfiPureParser覆写了finalize_check方法在属性处理收尾阶段扫描当前目标即外部函数上的全部属性fn finalize_check(cx: FinalizeCheckContext_, _, attr_span: Span) { // #[ffi_const] functions cannot be #[ffi_pure]. if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) { cx.emit_err(BothFfiConstAndPure { attr_span }); } }实现位于 link_attrs.rs。可以看到只要同一函数上存在ffi_const属性就会以当前ffi_pure属性所在 span 发出BothFfiConstAndPure诊断最终渲染为 E0757 错误。由于检查落在FfiPureParser一侧可以推断诊断的标注位置指向ffi_pure属性。诊断渲染BothFfiConstAndPure通过#[derive(Diagnostic)]宏挂接 E0757 错误码与消息模板见 diagnostics.rs最终呈现给用户完整错误信息。相关约束与注意事项feature gateffi_const、ffi_pure均为 unstable 语言特性解析器中STABILITY: AttributeStability unstable!(...)仅在 nightly 编译器上可用且需要显式#![feature(ffi_const, ffi_pure)]适用目标限定两个属性只允许作用于extern块中的外部函数Allow(Target::ForeignFn)不能用于普通fn、方法或静态项unsafe 容器二者必须写作#[unsafe(ffi_const)]、#[unsafe(ffi_pure)]直接写#[ffi_const]会因 unsafe 属性语法要求而报错无参数形式两个属性均不接受参数任何形如#[unsafe(ffi_const 1)]的写法都会被判定为 malformed 属性相关回归测试见 malformed-attrs.rs语义即契约属性语义无副作用、返回值仅依赖参数等由使用者向编译器承诺编译器据此做优化而不做校验标注与实际行为不符属于未定义行为需谨慎使用。小结E0757 是 rustc 针对 FFI 优化属性组合冲突给出的明确诊断ffi_const的保证严格强于ffi_pure二者同注既冗余又矛盾应当按外部函数的真实语义保留其一。其检查逻辑集中在 link_attrs.rs 的FfiPureParser::finalize_check错误文案定义于 diagnostics.rs两者共同构成了从属性解析、语义校验到诊断输出的完整链路。理解这条错误链有助于在 FFI 边界写出既安全又能充分释放编译器优化能力的属性声明。【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表