Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

代码生成属性

以下 属性 用于控制代码生成。

inline属性

inline 属性 建议是将所修饰函数代码的副本放置在调用者中,而不是生成对函数的调用。

例子

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

#[inline(always)]
pub fn example2() {}

#[inline(never)]
pub fn example3() {}
}

注意

rustc 在看起来值得时会自动内联函数。请谨慎使用此属性,因为内联决策不当可能会降低程序速度。

inline 属性的 语法格式 如下:

Syntax
InlineAttribute
      inline ( always )
    | inline ( never )
    | inline

InlineAttribute inline ( always ) inline ( never ) inline

inline 属性只能应用于带有 函数体 的函数——闭包异步块自由函数固有实现特型实现 中的 关联函数,以及 特型定义 中带有 默认定义 的关联函数。

注意

rustc 忽略在其他位置的使用,但会对其进行 lint 检查。这在将来可能会成为错误。

注意

尽管该属性可以应用于 闭包异步块,但其用处有限,因为我们尚不支持表达式上的属性。

#![allow(unused)]
fn main() {
// 我们允许在语句上使用属性。
#[inline] || (); // OK
#[inline] async {}; // OK
}
#![allow(unused)]
fn main() {
// 我们尚不支持在表达式上使用属性。
let f = #[inline] || (); // ERROR
}

inline 在函数上的首次使用才生效。

注意

rustc 会对首次使用之后的任何使用进行 lint 检查。这在将来可能会成为错误。

inline 属性支持以下模式:

  • #[inline] 建议 执行内联展开。
  • #[inline(always)] 建议 始终执行内联展开。
  • #[inline(never)] 建议 永不执行内联展开。

注意

无论何种形式,该属性都只是一个提示。编译器可能会忽略它。

inline 应用于 特型 中的函数时,它仅应用于 默认定义 的代码。

inline 应用于 异步函数异步闭包 时,它仅应用于生成的 poll 函数的代码。

注意

欲了解更多详情,请参阅 Rust issue #129347

如果函数通过 no_mangleexport_name 外部导出,则 inline 属性会被忽略。

cold属性

cold 属性 建议所修饰的函数不太可能被调用,这可能有助于编译器生成更好的代码。

例子

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

cold 属性使用 MetaWord 语法格式。

cold 属性只能应用于带有 函数体 的函数——闭包异步块自由函数固有实现特型实现 中的 关联函数,以及 特型定义 中带有 默认定义 的关联函数。

注意

rustc 忽略在其他位置的使用,但会对其进行 lint 检查。这在将来可能会成为错误。

注意

尽管该属性可以应用于 闭包异步块,但其用处有限,因为我们尚不支持表达式上的属性。

cold 在函数上的首次使用才生效。

注意

rustc 会对首次使用之后的任何使用进行 lint 检查。这在将来可能会成为错误。

cold 应用于 特型 中的函数时,它仅应用于 默认定义 的代码。

naked属性

naked 属性 阻止编译器为所修饰的函数发出函数序言和函数尾声。

函数体 必须由且仅由一个 naked_asm! 宏调用组成。

不会为所修饰的函数生成函数序言或函数尾声。naked_asm! 块中的汇编代码构成了裸函数的完整函数体。

naked 属性是一个 不安全 属性。使用 #[unsafe(naked)] 注解函数附带的安全义务是,函数体必须遵守函数的调用约定,维护其签名,并且要么返回,要么发散(即,不能在汇编代码末尾之后继续执行)。

汇编代码可以假定调用栈和寄存器状态在入口处是有效的,符合函数的签名和调用约定。

除了多态函数单态化时,编译器不得复制汇编代码。

注意

保证汇编代码何时可以或不可以被复制对于定义符号的裸函数很重要。

unused_variables lint 在裸函数内部被抑制。

inline 属性不能应用于裸函数。

track_caller 属性不能应用于裸函数。

测试属性 不能应用于裸函数。

no_builtins属性

no_builtins 属性 禁用与对假定存在的库函数调用相关的某些代码模式的优化。

例子

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

no_builtins 属性使用 MetaWord 语法格式。

no_builtins 属性只能应用于 crate 根。

no_builtins 属性的首次使用才生效。

注意

rustc 会对首次使用之后的任何使用进行 lint 检查。

target_feature属性

target_feature 属性 可以应用于函数,以启用该函数针对特定平台架构 特性 的代码生成。它使用 MetaListNameValueStr 语法格式,其中包含一个 enable 的键,其值是逗号分隔的 特性 名称字符串,以启用这些 特性。

#![allow(unused)]
fn main() {
#[cfg(target_feature = "avx2")]
#[target_feature(enable = "avx2")]
fn foo_avx2() {}
}

每个 目标架构 都有一组可以启用的 特性。为 crate 未编译的目标架构指定 特性 是一个错误。

在带有 target_feature 注解的函数中定义的闭包会从封闭函数继承该属性。

调用使用当前代码运行平台不支持的 特性 编译的函数是 未定义行为除非 平台明确文档说明这是安全的。

除非以下平台规则另有规定,否则适用以下限制:

  • 安全的 #[target_feature] 函数(以及继承该属性的闭包)只能在启用了被调用者启用所有 target_feature 的调用者中安全地调用。此限制不适用于 unsafe 上下文。
  • 安全的 #[target_feature] 函数(以及继承该属性的闭包)只能在启用了被强制转换者启用所有 target_feature 的上下文中被强制转换为 安全 的函数指针。此限制不适用于 unsafe 函数指针。

隐式启用的 特性 也包含在此规则中。例如,一个 sse2 函数可以调用标记有 sse 的函数。

#![allow(unused)]
fn main() {
#[cfg(target_feature = "sse2")] {
#[target_feature(enable = "sse")]
fn foo_sse() {}

fn bar() {
    // 在这里调用 `foo_sse` 是不安全的,因为我们必须首先确保 SSE 可用,
    // 即使 `sse` 在目标平台上默认启用或通过编译器标志手动启用。
    unsafe {
        foo_sse();
    }
}

#[target_feature(enable = "sse")]
fn bar_sse() {
    // 在这里调用 `foo_sse` 是安全的。
    foo_sse();
    || foo_sse();
}

#[target_feature(enable = "sse2")]
fn bar_sse2() {
    // 在这里调用 `foo_sse` 是安全的,因为 `sse2` 意味着 `sse`。
    foo_sse();
}
}
}

带有 #[target_feature] 属性 的函数 从不 实现 Fn 特型 家族,尽管从封闭函数继承 特性 的闭包会实现。

#[target_feature] 属性不允许在以下位置使用:

标记有 target_feature 的函数不会内联到不支持给定 特性 的上下文中。#[inline(always)] 属性不能与 target_feature 属性一起使用。

可用的特性

以下是可用 特性 名称的列表。

x86x86_64

在此平台上执行带有不支持 特性 的代码是未定义行为。因此,在此平台上使用 #[target_feature] 函数遵循 上述限制

特性隐式启用描述
adxADX — 多精度加进位指令扩展
aessse2AES — 高级加密标准
avxsse4.2AVX — 高级向量扩展
avx2avxAVX2 — 高级向量扩展 2
avx512bf16avx512bwAVX512-BF16 — 高级向量扩展 512 位 - Bfloat16 扩展
avx512bitalgavx512bwAVX512-BITALG — 高级向量扩展 512 位 - 位算法
avx512bwavx512fAVX512-BW — 高级向量扩展 512 位 - 字节和字指令
avx512cdavx512fAVX512-CD — 高级向量扩展 512 位 - 冲突检测指令
avx512dqavx512fAVX512-DQ — 高级向量扩展 512 位 - 双字和四字指令
avx512favx2, fma, f16cAVX512-F — 高级向量扩展 512 位 - 基础
avx512fp16avx512bwAVX512-FP16 — 高级向量扩展 512 位 - 浮点16 扩展
avx512ifmaavx512fAVX512-IFMA — 高级向量扩展 512 位 - 整数融合乘加
avx512vbmiavx512bwAVX512-VBMI — 高级向量扩展 512 位 - 向量字节操作指令
avx512vbmi2avx512bwAVX512-VBMI2 — 高级向量扩展 512 位 - 向量字节操作指令 2
avx512vlavx512fAVX512-VL — 高级向量扩展 512 位 - 向量长度扩展
avx512vnniavx512fAVX512-VNNI — 高级向量扩展 512 位 - 向量神经网络指令
avx512vp2intersectavx512fAVX512-VP2INTERSECT — 高级向量扩展 512 位 - 向量对交集到一对掩码寄存器
avx512vpopcntdqavx512fAVX512-VPOPCNTDQ — 高级向量扩展 512 位 - 向量人口计数指令
avxifmaavx2AVX-IFMA — 高级向量扩展 - 整数融合乘加
avxneconvertavx2AVX-NE-CONVERT — 高级向量扩展 - 无异常浮点转换指令
avxvnniavx2AVX-VNNI — 高级向量扩展 - 向量神经网络指令
avxvnniint16avx2AVX-VNNI-INT16 — 高级向量扩展 - 带有 16 位整数的向量神经网络指令
avxvnniint8avx2AVX-VNNI-INT8 — 高级向量扩展 - 带有 8 位整数的向量神经网络指令
bmi1BMI1 — 位操作指令集
bmi2BMI2 — 位操作指令集 2
cmpxchg16bcmpxchg16b — 原子地比较和交换 16 字节(128 位)数据
f16cavxF16C — 16 位浮点转换指令
fmaavxFMA3 — 三操作数融合乘加
fxsrfxsavefxrstor — 保存和恢复 x87 FPU、MMX 技术和 SSE 状态
gfnisse2GFNI — 伽罗瓦域新指令
klsse2KEYLOCKER — 英特尔密钥锁定指令
lzcntlzcnt — 前导零计数
movbemovbe — 字节交换后移动数据
pclmulqdqsse2pclmulqdq — 打包无进位乘法四字
popcntpopcnt — 设置为 1 的位数计数
rdrandrdrand — 读取随机数
rdseedrdseed — 读取随机种子
shasse2SHA — 安全散列算法
sha512avx2SHA512 — 安全散列算法与 512 位摘要
sm3avxSM3 — 商密 3 散列算法
sm4avx2SM4 — 商密 4 密码算法
sseSSE — 流式 SIMD 扩展
sse2sseSSE2 — 流式 SIMD 扩展 2
sse3sse2SSE3 — 流式 SIMD 扩展 3
sse4.1ssse3SSE4.1 — 流式 SIMD 扩展 4.1
sse4.2sse4.1SSE4.2 — 流式 SIMD 扩展 4.2
sse4asse3SSE4a — 流式 SIMD 扩展 4a
ssse3sse3SSSE3 — 补充流式 SIMD 扩展 3
tbmTBM — 尾随位操作
vaesavx2, aesVAES — 向量 AES 指令
vpclmulqdqavx, pclmulqdqVPCLMULQDQ — 四字向量无进位乘法
wideklklKEYLOCKER_WIDE — 英特尔宽密钥锁定指令
xsavexsave — 保存处理器扩展状态
xsavecxsavec — 保存处理器带压缩的扩展状态
xsaveoptxsaveopt — 保存处理器优化扩展状态
xsavesxsaves — 保存处理器主管扩展状态

aarch64

在此平台上,#[target_feature] 函数的使用遵循 上述限制

有关这些 特性 的更多文档可以在 ARM Architecture Reference Manualdeveloper.arm.com 上的其他位置找到。

注意

如果使用以下 特性 对,应同时将其标记为启用或禁用:

  • pacapacg,LLVM 目前将其实现为一个 特性。
特性隐式启用特性 名称
aesneonFEAT_AES & FEAT_PMULL — 高级 SIMD AES 和 PMULL 指令
bf16FEAT_BF16 — BFloat16 指令
btiFEAT_BTI — 分支目标识别
crcFEAT_CRC — CRC32 校验和指令
ditFEAT_DIT — 数据无关时序指令
dotprodneonFEAT_DotProd — 高级 SIMD Int8 点积指令
dpbFEAT_DPB — 数据缓存清理到持久点
dpb2dpbFEAT_DPB2 — 数据缓存清理到深度持久点
f32mmsveFEAT_F32MM — SVE 单精度浮点矩阵乘法指令
f64mmsveFEAT_F64MM — SVE 双精度浮点矩阵乘法指令
fcmaneonFEAT_FCMA — 浮点复数支持
fhmfp16FEAT_FHM — 半精度浮点 FMLAL 指令
flagmFEAT_FLAGM — 条件标志操作
fp16neonFEAT_FP16 — 半精度浮点数据处理
frinttsFEAT_FRINTTS — 浮点到整数辅助指令
i8mmFEAT_I8MM — Int8 矩阵乘法
jsconvneonFEAT_JSCVT — JavaScript 转换指令
lorFEAT_LOR — 有限排序区域扩展
lseFEAT_LSE — 大型系统扩展
mteFEAT_MTE & FEAT_MTE2 — 内存标记扩展
neonFEAT_AdvSimd & FEAT_FP — 浮点和高级 SIMD 扩展
pacaFEAT_PAUTH — 指针认证(地址认证)
pacgFEAT_PAUTH — 指针认证(通用认证)
panFEAT_PAN — 特权访问永不扩展
pmuv3FEAT_PMUv3 — 性能监视器扩展 (v3)
randFEAT_RNG — 随机数生成器
rasFEAT_RAS & FEAT_RASv1p1 — 可靠性、可用性和可服务性扩展
rcpcFEAT_LRCPC — 释放一致处理器一致
rcpc2rcpcFEAT_LRCPC2 — 带立即偏移的 RcPc
rdmneonFEAT_RDM — 舍入双精度乘累加
sbFEAT_SB — 推测屏障
sha2neonFEAT_SHA1 & FEAT_SHA256 — 高级 SIMD SHA 指令
sha3sha2FEAT_SHA512 & FEAT_SHA3 — 高级 SIMD SHA 指令
sm4neonFEAT_SM3 & FEAT_SM4 — 高级 SIMD SM3/4 指令
speFEAT_SPE — 统计分析扩展
ssbsFEAT_SSBS & FEAT_SSBS2 — 推测存储旁路安全
sveneonFEAT_SVE — 可伸缩向量扩展
sve2sveFEAT_SVE2 — 可伸缩向量扩展 2
sve2-aessve2, aesFEAT_SVE_AES & FEAT_SVE_PMULL128 — SVE AES 指令
sve2-bitpermsve2FEAT_SVE2_BitPerm — SVE 位置换
sve2-sha3sve2, sha3FEAT_SVE2_SHA3 — SVE SHA3 指令
sve2-sm4sve2, sm4FEAT_SVE2_SM4 — SVE SM4 指令
tmeFEAT_TME — 事务性内存扩展
vhFEAT_VHE — 虚拟化主机扩展

loongarch

在此平台上,#[target_feature] 函数的使用遵循 上述限制

特性隐式启用描述
fF — 单精度浮点指令
dfD — 双精度浮点指令
frecipeFRECIPE — 倒数近似指令
lasxlsxLASX — 256 位向量指令
lbtLBT — 二进制翻译指令
lsxdLSX — 128 位向量指令
lvzLVZ — 虚拟化指令

riscv32riscv64

在此平台上,#[target_feature] 函数的使用遵循 上述限制

有关这些 特性 的更多文档可以在它们各自的规范中找到。许多规范在 RISC-V ISA Manualversion 20250508,或 RISC-V GitHub Account 上的另一本手册中描述。

特性隐式启用描述
aA — 原子指令
cC — 压缩指令
mM — 整数乘法和除法指令
zbaZba — 地址生成指令
zbbZbb — 基本位操作
zbczbkcZbc — 无进位乘法
zbkbZbkb — 密码学位操作指令
zbkcZbkc — 密码学无进位乘法
zbkxZbkx — 交叉置换
zbsZbs — 单比特指令
zkzkn, zkr, zks, zkt, zbkb, zbkc, zkbxZk — 标量密码学
zknzknd, zkne, zknh, zbkb, zbkc, zkbxZkn — NIST 算法套件扩展
zkndZknd — NIST 套件: AES 解密
zkneZkne — NIST 套件: AES 加密
zknhZknh — NIST 套件: 哈希函数指令
zkrZkr — 熵源扩展
zkszksed, zksh, zbkb, zbkc, zkbxZks — 商密算法套件
zksedZksed — 商密套件: SM4 分组密码指令
zkshZksh — 商密套件: SM3 哈希函数指令
zktZkt — 数据无关执行延迟子集

wasm32wasm64

安全的 #[target_feature] 函数始终可以在 Wasm 平台上在安全上下文中使用。通过 #[target_feature] 属性 造成未定义行为是不可能的,因为尝试使用 Wasm 引擎不支持的指令会在加载时失败,而不会有被以编译器预期之外的方式解释的风险。

s390x

s390x 目标上,使用带有 #[target_feature] 属性 的函数遵循 上述限制

有关这些 特性 的更多文档可以在 z/Architecture Principles of Operation 的第 1 章“对 z/Architecture 的补充”部分中找到。

特性隐式启用描述
vector128 位向量指令
vector-enhancements-1vector向量增强 1
vector-enhancements-2vector-enhancements-1向量增强 2
vector-enhancements-3vector-enhancements-2向量增强 3
vector-packed-decimalvector向量压缩十进制
vector-packed-decimal-enhancementvector-packed-decimal向量压缩十进制增强
vector-packed-decimal-enhancement-2vector-packed-decimal-enhancement-2向量压缩十进制增强 2
vector-packed-decimal-enhancement-3vector-packed-decimal-enhancement-3向量压缩十进制增强 3
nnp-assistvectorNNP 辅助
miscellaneous-extensions-2杂项扩展 2
miscellaneous-extensions-3杂项扩展 3
miscellaneous-extensions-4杂项扩展 4

附加信息

有关根据编译时设置有选择地启用或禁用代码编译,请参阅 target_feature conditional compilation option。请注意,此选项不受 target_feature 属性 的影响,仅由整个 crate 启用的 特性 驱动。

可以在运行时使用标准库中平台特定的宏检查 特性 是否启用,例如 is_x86_feature_detectedis_aarch64_feature_detected

注意

rustc 为每个目标和 CPU 启用了一组默认 特性。可以使用 -C target-cpu 标志选择 CPU。可以使用 -C target-feature 标志为整个 crate 启用或禁用单个 特性。

track_caller属性

track_caller 属性可以应用于任何具有 "Rust" ABI 的函数,但入口点 fn main 除外。

当应用于 特型 声明中的函数和方法时,该属性适用于所有实现。如果 特型 提供带有该属性 的默认实现,则该属性也适用于覆盖实现。

当应用于 extern 块中的函数时,该属性也必须应用于任何链接的实现,否则会导致未定义行为。当应用于可用于 extern 块的函数时,extern 块中的声明也必须具有该属性,否则会导致未定义行为。

行为

将该属性应用于函数 f 允许 f 内的代码获取导致 f 被调用的“最顶层”跟踪调用的 Location 提示。在观察点,实现的行为就像它从 f 的栈帧向上查找最近的 未修饰 函数 outer 的栈帧,并返回 outer 中跟踪调用的 Location

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
}

注意

core 提供 core::panic::Location::caller 用于观察调用者位置。它包装了 rustc 实现的 core::intrinsics::caller_location 内部函数。

注意

因为生成的 Location 是一个提示,实现可能会提前停止其栈向上查找。有关重要的注意事项,请参阅 限制

示例

fcalls_f 直接调用时,f 中的代码观察到其在 calls_f 中的调用点:

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
fn calls_f() {
    f(); // <-- f() prints this location
}
}

f 被另一个带有属性 的函数 g 调用,而 g 又被 calls_g 调用时,fg 中的代码都观察到 gcalls_g 中的调用点:

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
#[track_caller]
fn g() {
    println!("{}", std::panic::Location::caller());
    f();
}

fn calls_g() {
    g(); // <-- g() prints this location twice, once itself and once from f()
}
}

g 被另一个带有属性 的函数 h 调用,而 h 又被 calls_h 调用时,fgh 中的所有代码都观察到 hcalls_h 中的调用点:

#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
    println!("{}", std::panic::Location::caller());
}
#[track_caller]
fn g() {
    println!("{}", std::panic::Location::caller());
    f();
}
#[track_caller]
fn h() {
    println!("{}", std::panic::Location::caller());
    g();
}

fn calls_h() {
    h(); // <-- prints this location three times, once itself, once from g(), once from f()
}
}

依此类推。

限制

此信息是一个提示,不要求实现保留它。

特别是,将带有 #[track_caller] 的函数强制转换为函数指针会创建一个 shim,该 shim 在观察者看来是在所修饰函数的定义点被调用,从而在虚拟调用中丢失实际的调用者信息。这种强制转换的一个常见示例是创建其方法带有属性 的 特型 对象。

注意

上述函数指针的 shim 是必要的,因为 rustc 在代码生成上下文中通过向函数 ABI 附加一个隐式参数来实现 track_caller,但对于间接调用来说,这会是不健全的,因为该参数不是函数类型的一部分,并且给定的函数指针类型可能引用也可能不引用带有该属性 的函数。创建 shim 隐藏了函数指针调用者中的隐式参数,从而保持了健全性。

instruction_set属性

instruction_set 属性 指定函数在代码生成过程中将使用的指令集。这允许在单个程序中混合使用多个指令集。

例子

#[instruction_set(arm::a32)]
fn arm_code() {}

#[instruction_set(arm::t32)]
fn thumb_code() {}

instruction_set 属性使用 MetaListPaths 语法格式来指定一个由架构家族名称和指令集名称组成的单一路径。

instruction_set 属性只能应用于带有 函数体 的函数——闭包异步块自由函数固有实现特型实现 中的 关联函数,以及 特型定义 中带有 默认定义 的关联函数。

注意

rustc 忽略在其他位置的使用,但会对其进行 lint 检查。这在将来可能会成为错误。

注意

尽管该属性可以应用于 闭包异步块,但其用处有限,因为我们尚不支持表达式上的属性。

instruction_set 属性在函数上只能使用一次。

instruction_set 属性只能与支持给定值的目标一起使用。

当使用 instruction_set 属性时,函数中的任何内联汇编都必须使用指定的指令集而不是目标默认指令集。

ARM上的instruction_set

当目标为 ARMv4TARMv5te 架构时,instruction_set 支持的值有:

  • arm::a32 — 将函数生成为 A32 “ARM” 代码。
  • arm::t32 — 将函数生成为 T32 “Thumb” 代码。

如果将函数的地址作为函数指针,则地址的低位将取决于所选的指令集:

  • 对于 arm::a32 (“ARM”),它将为 0。
  • 对于 arm::t32 (“Thumb”),它将为 1。