代码生成属性
以下属性用于控制代码生成。
inline 属性
*inline [属性]*建议是否应将属性函数代码的副本放置在调用者中,而不是生成对函数的调用。
Example
#![allow(unused)] fn main() { #[inline] pub fn example1() {} #[inline(always)] pub fn example2() {} #[inline(never)] pub fn example3() {} }
Note
rustc在这样做似乎值得时会自动内联函数。请谨慎使用此属性,因为关于内联什么的错误决定可能会使程序变慢。
inline 属性的语法是:
Syntax
InlineAttribute →
inline ( always )
| inline ( never )
| inline
inline 属性只能应用于具有主体的函数 — 闭包、异步块、自由函数、固有实现或 trait 实现中的关联函数,以及当这些函数具有默认定义时 trait 定义中的关联函数。
Note
rustc会忽略在其他位置的使用,但会发出 lint 警告。这可能在未来成为错误。
Note
虽然该属性可以应用于闭包和异步块,但其用处有限,因为我们尚不支持表达式上的属性。
#![allow(unused)] fn main() { // We allow attributes on statements. #[inline] || (); // OK #[inline] async {}; // OK }#![allow(unused)] fn main() { // We don't yet allow attributes on expressions. let f = #[inline] || (); // ERROR }
只有函数上的第一次使用 inline 才有效果。
Note
rustc会对第一次之后的任何使用发出 lint 警告。这可能在未来成为错误。
inline 属性支持以下模式:
#[inline]建议执行内联展开。#[inline(always)]建议应始终执行内联展开。#[inline(never)]建议应从不执行内联展开。
Note
在每种形式中,该属性都是提示。编译器可能会忽略它。
当 inline 应用于 trait 中的函数时,它仅适用于默认定义的代码。
当 inline 应用于异步函数或异步闭包时,它仅适用于生成的 poll 函数的代码。
Note
有关更多详细信息,请参阅 Rust issue #129347。
如果函数通过 no_mangle 或 export_name 外部导出,则 inline 属性被忽略。
cold 属性
*cold [属性]*建议属性函数不太可能被调用,这可能有助于编译器生成更好的代码。
Example
#![allow(unused)] fn main() { #[cold] pub fn example() {} }
cold 属性使用 MetaWord 语法。
cold 属性只能应用于具有主体的函数 — 闭包、异步块、自由函数、固有实现或 trait 实现中的关联函数,以及当这些函数具有默认定义时 trait 定义中的关联函数。
Note
rustc会忽略在其他位置的使用,但会发出 lint 警告。这可能在未来成为错误。
只有函数上的第一次使用 cold 才有效果。
Note
rustc会对第一次之后的任何使用发出 lint 警告。这可能在未来成为错误。
当 cold 应用于 trait 中的函数时,它仅适用于默认定义的代码。
naked 属性
*naked [属性]*阻止编译器为属性函数发出函数序言和尾声 — 裸函数。
Example
#![allow(unused)] fn main() { #[cfg(target_arch = "x86_64")] { /// Adds 3 to the given number. // SAFETY: The body respects the "sysv64" calling convention, // upholds the signature, and does not fall through. #[unsafe(naked)] pub extern "sysv64" fn add_n(number: u64) -> u64 { core::arch::naked_asm!( "add rdi, {}", "mov rax, rdi", "ret", const 3, ) } } }
naked 属性使用 MetaWord 语法。
naked 属性只能应用于自由函数、固有实现或 trait 实现中的关联函数,以及当这些函数具有默认定义时 trait 定义中的关联函数。
只有函数上的第一次使用 naked 才有效果。
Note
rustc会对第一次之后的任何使用发出 lint 警告。
naked 属性必须用 unsafe 标记,因为主体必须尊重函数的调用约定、维护其签名,并且要么返回要么发散(即不会穿透汇编代码末尾)。
函数主体必须恰好包含一个 naked_asm! 宏调用。
编译器不为裸函数发出序言或尾声:naked_asm! 调用中的汇编代码构成其整个主体。
在入口处,汇编代码可以假设调用栈和寄存器状态根据函数的签名和调用约定是有效的。
编译器不得复制汇编代码,除非在单态化多态函数时。
Note
此保证对于定义符号的裸函数很重要。
unused_variables lint 在裸函数中被抑制。
[inline 属性]不能应用于裸函数。
[track_caller 属性]不能应用于裸函数。
[测试属性]不能应用于裸函数。
[target_feature 属性]不能应用于裸函数。
裸函数不能使用 “Rust” ABI。
no_builtins 属性
*no_builtins [属性]*禁用对假定存在的库函数调用的某些代码模式的优化。
Example
#![allow(unused)] #![no_builtins] fn main() { }
no_builtins 属性使用 MetaWord 语法。
no_builtins 属性只能应用于 crate 根。
只有第一次使用 no_builtins 属性才有效果。
Note
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() {
// Calling `foo_sse` here is unsafe, as we must ensure that SSE is
// available first, even if `sse` is enabled by default on the target
// platform or manually enabled as compiler flags.
unsafe {
foo_sse();
}
}
#[target_feature(enable = "sse")]
fn bar_sse() {
// Calling `foo_sse` here is safe.
foo_sse();
|| foo_sse();
}
#[target_feature(enable = "sse2")]
fn bar_sse2() {
// Calling `foo_sse` here is safe because `sse2` implies `sse`.
foo_sse();
}
}
}
具有 #[target_feature] 属性的函数从不实现 Fn 系列 trait,但从封闭函数继承功能的闭包除外。
#[target_feature] 属性不允许在以下位置:
- the
mainfunction panic_handlerfunction- 安全 trait 方法
- trait 中的安全默认函数
标记为 target_feature 的函数不会内联到不支持给定功能的上下文中。#[inline(always)] 属性不能与 target_feature 属性一起使用。
可用功能
以下是可用功能名称的列表。
x86 或 x86_64
在此平台上,使用不受支持的功能执行代码是未定义行为。因此,在此平台上使用 #[target_feature] 函数遵循上述限制。
| 功能 | 隐式启用 | 描述 |
|---|---|---|
adx | ADX — 多精度加法进位指令扩展 | |
aes | sse2 | AES — 高级加密标准 |
avx | sse4.2 | AVX — 高级向量扩展 |
avx2 | avx | AVX2 — 高级向量扩展 2 |
avx512bf16 | avx512bw | AVX512-BF16 — 高级向量扩展 512 位 - Bfloat16 扩展 |
avx512bitalg | avx512bw | AVX512-BITALG — 高级向量扩展 512 位 - 位算法 |
avx512bw | avx512f | AVX512-BW — 高级向量扩展 512 位 - 字节和字指令 |
avx512cd | avx512f | AVX512-CD — 高级向量扩展 512 位 - 冲突检测指令 |
avx512dq | avx512f | AVX512-DQ — 高级向量扩展 512 位 - 双字和四字指令 |
avx512f | avx2, fma, f16c | AVX512-F — 高级向量扩展 512 位 - 基础 |
avx512fp16 | avx512bw | AVX512-FP16 — 高级向量扩展 512 位 - Float16 扩展 |
avx512ifma | avx512f | AVX512-IFMA — 高级向量扩展 512 位 - 整数融合乘加 |
avx512vbmi | avx512bw | AVX512-VBMI — 高级向量扩展 512 位 - 向量字节操作指令 |
avx512vbmi2 | avx512bw | AVX512-VBMI2 — 高级向量扩展 512 位 - 向量字节操作指令 2 |
avx512vl | avx512f | AVX512-VL — 高级向量扩展 512 位 - 向量长度扩展 |
avx512vnni | avx512f | AVX512-VNNI — 高级向量扩展 512 位 - 向量神经网络指令 |
avx512vp2intersect | avx512f | AVX512-VP2INTERSECT — 高级向量扩展 512 位 - 向量对交集到一对掩码寄存器 |
avx512vpopcntdq | avx512f | AVX512-VPOPCNTDQ — 高级向量扩展 512 位 - 向量总体计数指令 |
avxifma | avx2 | AVX-IFMA — 高级向量扩展 - 整数融合乘加 |
avxneconvert | avx2 | AVX-NE-CONVERT — 高级向量扩展 - 无异常浮点转换指令 |
avxvnni | avx2 | AVX-VNNI — 高级向量扩展 - 向量神经网络指令 |
avxvnniint16 | avx2 | AVX-VNNI-INT16 — 高级向量扩展 - 16 位整数向量神经网络指令 |
avxvnniint8 | avx2 | AVX-VNNI-INT8 — 高级向量扩展 - 8 位整数向量神经网络指令 |
bmi1 | BMI1 — 位操作指令集 | |
bmi2 | BMI2 — 位操作指令集 2 | |
cmpxchg16b | cmpxchg16b — 原子比较和交换 16 字节(128 位)数据 | |
f16c | avx | F16C — 16 位浮点转换指令 |
fma | avx | FMA3 — 三操作数融合乘加 |
fxsr | fxsave 和 fxrstor — 保存和恢复 x87 FPU、MMX 技术和 SSE 状态 | |
gfni | sse2 | GFNI — 伽罗瓦域新指令 |
kl | sse2 | KEYLOCKER — Intel 密钥锁指令 |
lzcnt | lzcnt — 前导零计数 | |
movbe | movbe — 交换字节后移动数据 | |
pclmulqdq | sse2 | pclmulqdq — 打包无进位乘法四字 |
popcnt | popcnt — 设置为 1 的位计数 | |
rdrand | rdrand — 读取随机数 | |
rdseed | rdseed — 读取随机种子 | |
sha | sse2 | SHA — 安全哈希算法 |
sha512 | avx2 | SHA512 — 512 位摘要的安全哈希算法 |
sm3 | avx | SM3 — 商密 3 哈希算法 |
sm4 | avx2 | SM4 — 商密 4 密码算法 |
sse | SSE — 流式 SIMD 扩展 | |
sse2 | sse | SSE2 — 流式 SIMD 扩展 2 |
sse3 | sse2 | SSE3 — 流式 SIMD 扩展 3 |
sse4.1 | ssse3 | SSE4.1 — 流式 SIMD 扩展 4.1 |
sse4.2 | sse4.1 | SSE4.2 — 流式 SIMD 扩展 4.2 |
sse4a | sse3 | SSE4a — 流式 SIMD 扩展 4a |
ssse3 | sse3 | SSSE3 — 补充流式 SIMD 扩展 3 |
tbm | TBM — 尾部位操作 | |
vaes | avx2, aes | VAES — 向量 AES 指令 |
vpclmulqdq | avx, pclmulqdq | VPCLMULQDQ — 向量四字无进位乘法 |
widekl | kl | KEYLOCKER_WIDE — Intel 宽密钥锁指令 |
xsave | xsave — 保存处理器扩展状态 | |
xsavec | xsavec — 压缩保存处理器扩展状态 | |
xsaveopt | xsaveopt — 优化保存处理器扩展状态 | |
xsaves | xsaves — 监督者保存处理器扩展状态 |
aarch64
在此平台上使用 #[target_feature] 函数遵循上述限制。
有关这些功能的进一步文档可在 ARM 架构参考手册或 developer.arm.com 上找到。
Note
如果使用以下功能对,应同时标记为启用或禁用:
paca和pacg,LLVM 目前将其实现为一个功能。
| 功能 | 隐式启用 | 功能名称 |
|---|---|---|
aes | neon | FEAT_AES & FEAT_PMULL — 高级 SIMD AES 和 PMULL 指令 |
bf16 | FEAT_BF16 — BFloat16 指令 | |
bti | FEAT_BTI — 分支目标识别 | |
crc | FEAT_CRC — CRC32 校验和指令 | |
dit | FEAT_DIT — 数据独立时序指令 | |
dotprod | neon | FEAT_DotProd — 高级 SIMD Int8 点积指令 |
dpb | FEAT_DPB — 数据缓存清理到持久点 | |
dpb2 | dpb | FEAT_DPB2 — 数据缓存清理到深度持久点 |
f32mm | sve | FEAT_F32MM — SVE 单精度 FP 矩阵乘法指令 |
f64mm | sve | FEAT_F64MM — SVE 双精度 FP 矩阵乘法指令 |
fcma | neon | FEAT_FCMA — 浮点复数支持 |
fhm | fp16 | FEAT_FHM — 半精度 FP FMLAL 指令 |
flagm | FEAT_FLAGM — 条件标志操作 | |
fp16 | neon | FEAT_FP16 — 半精度 FP 数据处理 |
frintts | FEAT_FRINTTS — 浮点到整数辅助指令 | |
i8mm | FEAT_I8MM — Int8 矩阵乘法 | |
jsconv | neon | FEAT_JSCVT — JavaScript 转换指令 |
lor | FEAT_LOR — 有限排序区域扩展 | |
lse | FEAT_LSE — 大型系统扩展 | |
mte | FEAT_MTE & FEAT_MTE2 — 内存标记扩展 | |
neon | FEAT_AdvSimd & FEAT_FP — 浮点和高级 SIMD 扩展 | |
paca | FEAT_PAUTH — 指针认证(地址认证) | |
pacg | FEAT_PAUTH — 指针认证(通用认证) | |
pan | FEAT_PAN — 特权访问禁止扩展 | |
pmuv3 | FEAT_PMUv3 — 性能监视器扩展(v3) | |
rand | FEAT_RNG — 随机数生成器 | |
ras | FEAT_RAS & FEAT_RASv1p1 — 可靠性、可用性和可维护性扩展 | |
rcpc | FEAT_LRCPC — 释放一致处理器一致 | |
rcpc2 | rcpc | FEAT_LRCPC2 — 带立即偏移的 RcPc |
rdm | neon | FEAT_RDM — 舍入双乘累加 |
sb | FEAT_SB — 推测屏障 | |
sha2 | neon | FEAT_SHA1 & FEAT_SHA256 — 高级 SIMD SHA 指令 |
sha3 | sha2 | FEAT_SHA512 & FEAT_SHA3 — 高级 SIMD SHA 指令 |
sm4 | neon | FEAT_SM3 & FEAT_SM4 — 高级 SIMD SM3/4 指令 |
spe | FEAT_SPE — 统计分析扩展 | |
ssbs | FEAT_SSBS & FEAT_SSBS2 — 推测存储旁路安全 | |
sve | neon | FEAT_SVE — 可伸缩向量扩展 |
sve2 | sve | FEAT_SVE2 — 可伸缩向量扩展 2 |
sve2-aes | sve2, aes | FEAT_SVE_AES & FEAT_SVE_PMULL128 — SVE AES 指令 |
sve2-bitperm | sve2 | FEAT_SVE2_BitPerm — SVE 位排列 |
sve2-sha3 | sve2, sha3 | FEAT_SVE2_SHA3 — SVE SHA3 指令 |
sve2-sm4 | sve2, sm4 | FEAT_SVE2_SM4 — SVE SM4 指令 |
tme | FEAT_TME — 事务内存扩展 | |
vh | FEAT_VHE — 虚拟化主机扩展 |
loongarch
在此平台上使用 #[target_feature] 函数遵循上述限制。
| 功能 | 隐式启用 | 描述 |
|---|---|---|
f | F — 单精度浮点指令 | |
d | f | D — 双精度浮点指令 |
frecipe | FRECIPE — 倒数近似指令 | |
lasx | lsx | LASX — 256 位向量指令 |
lbt | LBT — 二进制翻译指令 | |
lsx | d | LSX — 128 位向量指令 |
lvz | LVZ — 虚拟化指令 | |
div32 | DIV32 — 接受非符号扩展 32 位操作数的除法指令 | |
lam-bh | LAM-BH — 字节和半字的原子交换和加法指令 | |
lamcas | LAMCAS — 字节、半字、字和双字的原子比较交换指令 | |
ld-seq-sa | LD-SEQ-SA — 对同一地址的加载操作的顺序排序 | |
scq | SCQ — 条件存储四字指令 |
riscv32 或 riscv64
在此平台上使用 #[target_feature] 函数遵循上述限制。
有关这些功能的进一步文档可在各自的规范中找到。许多规范在 RISC-V ISA 手册、[版本 20250508] 或 [RISC-V GitHub 账户]上托管的其他手册中描述。
| 功能 | 隐式启用 | 描述 |
|---|---|---|
a | zaamo, zalrsc | A — 原子指令 |
b | zba, zbc, zbs | B — 位操作指令 |
c | zca | C — 压缩指令 |
m | M — 整数乘法和除法指令 | |
za64rs | za128rs | Za64rs — 平台行为:自然对齐的保留集 ≦ 64 字节 |
za128rs | Za128rs — 平台行为:自然对齐的保留集 ≦ 128 字节 | |
zaamo | Zaamo — 原子内存操作指令 | |
zabha | zaamo | Zabha — 字节和半字原子内存操作指令 |
zacas | zaamo | Zacas — 原子比较交换(CAS)指令 |
zalrsc | Zalrsc — 加载保留/条件存储指令 | |
zama16b | Zama16b — 平台行为:不对齐的加载、存储和 AMO 到不跨越自然对齐 16 字节边界的主内存区域是原子的 | |
zawrs | Zawrs — 等待保留集指令 | |
zba | Zba — 地址生成指令 | |
zbb | Zbb — 基本位操作 | |
zbc | zbkc | Zbc — 无进位乘法 |
zbkb | Zbkb — 密码学位操作指令 | |
zbkc | Zbkc — 密码学无进位乘法 | |
zbkx | Zbkx — 纵横排列 | |
zbs | Zbs — 单位指令 | |
zca | Zca — 压缩指令:整数部分子集 | |
zcb | zca | Zcb — 简单代码大小节省压缩指令 |
zcmop | zca | Zcmop — 压缩可能是操作 |
zic64b | Zic64b — 平台行为:自然对齐的 64 字节缓存块 | |
zicbom | Zicbom — 缓存块管理指令 | |
zicbop | Zicbop — 缓存块预取提示指令 | |
zicboz | Zicboz — 缓存块清零指令 | |
ziccamoa | Ziccamoa — 平台行为:可缓存和一致的主内存支持所有基本原子操作 | |
ziccif | Ziccif — 平台行为:可缓存和一致的主内存支持指令获取和自然对齐的 2 的幂大小的获取是原子的 | |
zicclsm | Zicclsm — 平台行为:可缓存和一致的主内存支持不对齐的加载/存储访问 | |
ziccrse | Ziccrse — 平台行为:可缓存和一致的主内存保证 LR/SC 序列最终成功 | |
zicntr | zicsr | Zicntr — 基本计数器和定时器 |
zicond | Zicond — 整数条件操作指令 | |
zicsr | Zicsr — 控制和状态寄存器(CSR)指令 | |
zifencei | Zifencei — 指令获取屏障指令 | |
zihintntl | Zihintntl — 非时间局部性提示指令 | |
zihintpause | Zihintpause — 暂停提示指令 | |
zihpm | zicsr | Zihpm — 硬件性能计数器 |
zimop | Zimop — 可能是操作 | |
zk | zkn, zkr, zks, zkt, zbkb, zbkc, zkbx | Zk — 标量密码学 |
zkn | zknd, zkne, zknh, zbkb, zbkc, zkbx | Zkn — NIST 算法套件扩展 |
zknd | Zknd — NIST 套件:AES 解密 | |
zkne | Zkne — NIST 套件:AES 加密 | |
zknh | Zknh — NIST 套件:哈希函数指令 | |
zkr | Zkr — 熵源扩展 | |
zks | zksed, zksh, zbkb, zbkc, zkbx | Zks — 商密算法套件 |
zksed | Zksed — 商密套件:SM4 分组密码指令 | |
zksh | Zksh — 商密套件:SM3 哈希函数指令 | |
zkt | Zkt — 数据独立执行延迟子集 | |
ztso | Ztso — 全存储排序 |
wasm32 或 wasm64
安全的 #[target_feature] 函数在 Wasm 平台上始终可以在安全上下文中使用。不可能通过 #[target_feature] 属性导致未定义行为,因为尝试使用 Wasm 引擎不支持的指令将在加载时失败,而不会以与编译器预期不同的方式被解释的风险。
| 功能 | 隐式启用 | 描述 |
|---|---|---|
bulk-memory | WebAssembly 批量内存操作提案 | |
extended-const | WebAssembly 扩展常量表达式提案 | |
mutable-globals | WebAssembly 可变全局提案 | |
nontrapping-fptoint | WebAssembly 非捕获浮点到整数转换提案 | |
relaxed-simd | simd128 | WebAssembly 宽松 simd 提案 |
sign-ext | WebAssembly 符号扩展运算符提案 | |
simd128 | WebAssembly simd 提案 | |
multivalue | WebAssembly 多值提案 | |
reference-types | WebAssembly 引用类型提案 | |
tail-call | WebAssembly 尾调用提案 |
s390x
在 s390x 目标上,使用具有 #[target_feature] 属性的函数遵循上述限制。
有关这些功能的进一步文档可在 z/Architecture Principles of Operation 第 1 章的“Additions to z/Architecture“部分找到。
| 功能 | 隐式启用 | 描述 |
|---|---|---|
vector | 128 位向量指令 | |
vector-enhancements-1 | vector | 向量增强 1 |
vector-enhancements-2 | vector-enhancements-1 | 向量增强 2 |
vector-enhancements-3 | vector-enhancements-2 | 向量增强 3 |
vector-packed-decimal | vector | 向量压缩十进制 |
vector-packed-decimal-enhancement | vector-packed-decimal | 向量压缩十进制增强 |
vector-packed-decimal-enhancement-2 | vector-packed-decimal-enhancement-2 | 向量压缩十进制增强 2 |
vector-packed-decimal-enhancement-3 | vector-packed-decimal-enhancement-3 | 向量压缩十进制增强 3 |
nnp-assist | vector | nnp 辅助 |
miscellaneous-extensions-2 | 杂项扩展 2 | |
miscellaneous-extensions-3 | 杂项扩展 3 | |
miscellaneous-extensions-4 | 杂项扩展 4 |
附加信息
有关基于编译时设置选择性启用或禁用代码编译的信息,请参阅 target_feature 条件编译选项。请注意,此选项不受 target_feature 属性影响,仅由整个 crate 启用的功能驱动。
可以在运行时使用标准库中特定于平台的宏检查功能是否已启用,例如 is_x86_feature_detected 或 is_aarch64_feature_detected。
Note
rustc为每个目标和 CPU 启用了一组默认功能。可以使用-C target-cpu标志选择 CPU。可以使用-C target-feature标志为整个 crate 启用或禁用单个功能。
track_caller 属性
track_caller 属性可应用于任何具有 "Rust" ABI 的函数,入口点 fn main 除外。
当应用于 trait 声明中的函数和方法时,该属性适用于所有实现。如果 trait 提供了具有该属性的默认实现,则该属性也适用于全面实现。
当应用于 extern 块中的函数时,该属性也必须应用于任何链接的实现,否则会导致未定义行为。当应用于提供给 extern 块的函数时,extern 块中的声明也必须具有该属性,否则会导致未定义行为。
行为
将属性应用于函数 f 允许 f 内的代码获取导致 f 调用的“最顶层“跟踪调用的 Location 提示。在观察点,实现的行为就像它从 f 的帧向上遍历栈以找到最近的未属性化函数 outer 的帧,并返回 outer 中跟踪调用的 Location。
#![allow(unused)]
fn main() {
#[track_caller]
fn f() {
println!("{}", std::panic::Location::caller());
}
}
Note
core提供core::panic::Location::caller用于观察调用者位置。它包装了rustc实现的core::intrinsics::caller_location内部函数。
Note
因为结果
Location是一个提示,实现可能会提前停止向上遍历栈。有关重要注意事项,请参阅限制。
示例
当 f 被 calls_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 调用时,f 和 g 中的代码都观察 g 在 calls_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 调用时,f、g 和 h 中的所有代码都观察 h 在 calls_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] 的函数强制转换为函数指针会创建一个垫片,在观察者看来就像在属性函数的定义位置被调用一样,在虚拟调用中丢失了实际的调用者信息。这种强制转换的常见示例是创建其方法被属性化的 trait 对象。
Note
上述函数指针的垫片是必要的,因为
rustc通过向函数 ABI 追加隐式参数在代码生成上下文中实现track_caller,但这对于间接调用将是不健全的,因为该参数不是函数类型的一部分,并且给定的函数指针类型可能引用也可能不引用具有该属性的函数。垫片的创建对函数指针的调用者隐藏了隐式参数,保持了健全性。
instruction_set 属性
*instruction_set [属性]*指定函数在代码生成期间使用的指令集。这允许在单个程序中混合多个指令集。
Example
#[instruction_set(arm::a32)] fn arm_code() {} #[instruction_set(arm::t32)] fn thumb_code() {}
instruction_set 属性使用 MetaListPaths 语法指定由架构系列名称和指令集名称组成的单个路径。
instruction_set 属性只能应用于具有主体的函数 — 闭包、异步块、自由函数、固有实现或 trait 实现中的关联函数,以及当这些函数具有默认定义时 trait 定义中的关联函数。
Note
rustc会忽略在其他位置的使用,但会发出 lint 警告。这可能在未来成为错误。
instruction_set 属性只能在函数上使用一次。
instruction_set 属性只能在支持给定值的目标上使用。
使用 instruction_set 属性时,函数中的任何内联汇编必须使用指定的指令集,而不是目标默认值。
ARM 上的 instruction_set
以 ARMv4T 和 ARMv5te 架构为目标时,instruction_set 的支持值为:
arm::a32— 将函数生成为 A32 “ARM” 代码。arm::t32— 将函数生成为 T32 “Thumb” 代码。
如果将函数的地址作为函数指针获取,地址的低位将取决于所选的指令集:
- 对于
arm::a32(“ARM”),它将是 0。 - 对于
arm::t32(“Thumb”),它将是 1。