rust打印闭包的插件实现

背景

“调试”编译器的某些行为时,可以通过编译器错误输出来判断
比如想知道一个类型是否实现了某个trait

fn main() {use std::fmt::Debug;struct A;fn foo<T: Debug>(t: T) {}let a = A;foo(A);
}

提示:required by this bound in foo
意思就是:结构体A没有实现Debug trait

解决方式

有些涉及编译器内部处理的逻辑并不会通过编译提示输出,但研究某段代码时想看看rustc怎么编译
比较暴力的方法就是直接修改编译器源代码插入日志
但是由于编译器项目巨大,想拿到结果会耗时耗力

所幸rustc项目优秀的架构设计和API文档使得程序化调用rustc内部逻辑非常方便
下文写一个编译器插件,输出Rust闭包的内部结构

Rustc Driver 和 Rustc Interface

https://rustcrustc.github.io/rustc-dev-guide-zh/rustc-driver.html

介绍

【大概解释】
rustc_driver 本质上是 rustc 的 main() 函数,它使用 rustc_interface crate 中定义的接口,按正确顺序执行编译器各个阶段

rustc_interface crate 为外部用户提供了一个(不稳定的)API,用于在编译过程中的特定时间运行代码
从而允许第三方有效地使用 rustc 的内部代码作为库来分析 crate 或在进程中模拟编译器(例如 RLS 或 rustdoc )

对于那些将 rustc 作为库使用的用户,rustc_driver工作如下:

  • rustc_interface::run_compiler() 函数是编译器的主要入口点
  • 它接受一个编译器配置参数,以及一个接受 Compiler 参数的闭包
  • run_compiler 从配置中创建一个 Compiler 并将其传递给闭包
  • 在闭包内部,使用 Compiler 来驱动查询以编译 crate 并获取结果

【更详细的解释】
rustc_driver是Rust编译器自带的一个Crate,它提供了一个用于驱动Rust编译过程的接口
具体来说,rustc_driver Crate 提供了使用 Rust 编译器进行编译的功能
可以处理编译相关的任务,包括读取源码、解析语法、类型检查、生成中间代码等
它是 Rust 编译器的核心部分之一,可以作为开发者构建自定义编译工具或进行编译相关操作的重要工具。

将rustc_driver Crate 导入到当前的 Rust 代码文件中,以便使用其中定义的类型和函数来执行与编译器相关的任务
这样,开发者可以利用rustc_driver Crate 提供的功能来扩展和自定义 Rust 编译器的行为

rustc_interface是一个Rust的内置Crate,它提供了与Rust编译器接口交互的能力
它是Rust编译器在编译过程中不可或缺的部分,可以用于将源代码编译为可执行文件或库
具体而言,rustc_interface Crate 包含了一系列类型和函数,用于读取、解析、转译和执行Rust代码

【用法】
通过 rustdocs 查看 Compiler 当前可用的查询

通过查看 rustc_driver 的实现,特别是 rustc_driver::run_compiler 函数(不要与 rustc_interface::run_compiler 混淆)
来查看如何使用它们

rustc_driver::run_compiler 接受一堆命令行参数和一些其他配置,并指定相关的编译参数和源代码,推动编译完成
rustc_driver::run_compiler 接受一个 Callbacks,它是一个允许自定义编译器配置以及允许一些自定义代码在编译的不同阶段之后运行的 trait

【注意】
本质来说,编译器内部 API 总是不稳定的,但是会尽力避免不必要的破坏

方法

rustc_driver::init_rustc_env_logger

pub fn init_rustc_env_logger(handler: &EarlyErrorHandler)

without having to magically match rustc’s tracing crate version
工具可以在不必像魔术般匹配 rustc 的 tracing crate 版本的情况下,启用 Rust 的日志记录(enable rust logging)

rustc_driver::catch_with_exit_code

pub fn catch_with_exit_code(f: impl FnOnce() -> Result<(), ErrorGuaranteed>
) -> i32

Variant of catch_fatal_errors for the interface::Result return type that also computes the exit code
针对 interface::Result 返回类型的 catch_fatal_errors 变种,同时计算退出码
退出码通常用于表示程序在结束时返回给操作系统的状态指示

rustc_driver::catch_fatal_errors

pub fn catch_fatal_errors<F, R>(f: F) -> Result<R, ErrorGuaranteed>
whereF: FnOnce() -> R,

Runs a closure and catches unwinds triggered by fatal errors.
该代码运行一个闭包(closure)并捕获由致命错误引起的异常取消(catches unwinds triggered by fatal errors)

The compiler currently unwinds with a special sentinel value to abort compilation on fatal errors.
This function catches that sentinel and turns the panic into a Result instead.
编译器当前在致命错误发生时会使用特殊的标记值(哨兵值)(a special sentinel value)来取消编译。
该函数捕获该标记值,然后将 panic 转换成一个 Result 类型的返回值。

这段代码用于处理编译器在遇到致命错误时可能引发的 panic。
它将该 panic 转换成一个 Result 类型的返回值,能够以更优雅的方式处理异常状况,而不是直接终止程序的执行。

步骤

安装rustup

在macOS上需要提前安装xcode命令行 xcode-select --install

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain none --profile minimal -y

创建插件项目

cargo new --bin rustc-plugin
cd rustc-plugin// 从界面输入中重定向到输出
cat <<EOF > rust-toolchain
[toolchain]
channel = "nightly"
components = [ "rustc-dev", "llvm-tools-preview", "rust-src" ]
EOF

编写插件

// 打开rustc_privatefeature,能够直接调用rust编译器的内置函数和注入回调获取想要的信息
#![feature(rustc_private)]// extern crate语法来导入外部的Crate
// 在之前初始化环境步骤里通过rustup(components = [ "rustc-dev" ])自动安装到本地的
// 相当于rustc编译器的入口函数,通过它们可以程序式地唤起编译流程,比如设置自定义编译配置
// 在最新版本的Rust中,extern crate已被弃用,不再需要显式导入Crate
// 可以使用use语句来引入Rust的内置Crate
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_session;
use rustc_session::config::ErrorOutputType;
use rustc_session::{EarlyErrorHandler};struct MyCallback;fn fatal_deal_function() -> i32 {42 // 在这个例子中,只是返回一个简单的整数
}fn main() {let handler = EarlyErrorHandler::new(ErrorOutputType::default());rustc_driver::init_rustc_env_logger(&handler);let result = rustc_driver::catch_fatal_errors(|| fatal_deal_function());match result {Ok(value) => {println!("Function executed successfully: {}", value);}Err(_) => {println!("Function encountered a fatal error.");}}
}

声明回调类型

rustc的Callbacks trait如下:

pub trait Callbacks {// Provided methodsfn config(&mut self, _config: &mut Config) { ... }fn after_crate_root_parsing<'tcx>(&mut self,_compiler: &Compiler,_queries: &'tcx Queries<'tcx>) -> Compilation { ... }fn after_expansion<'tcx>(&mut self,_compiler: &Compiler,_queries: &'tcx Queries<'tcx>) -> Compilation { ... }fn after_analysis<'tcx>(&mut self,_compiler: &Compiler,_queries: &

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/152448.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES6有何新特性?(下篇)

目录 函数参数的默认值设置 rest参数 扩展运算符 Symbol 迭代器 生成器 Promise Class 数值扩展 对象方法扩展 模块化 大家好呀&#xff01;今天这篇文章继续为大家介绍ES6的新特性&#xff0c;上上上篇文章介绍了一部分&#xff0c;这篇文章会将剩下的部分新增的特…

ES索引数据清理脚本示例

说明&#xff1a;我得索引是按月份创建的&#xff0c;索引名后面都有yyyy.MM 需求&#xff1a;删除三个月以前的索引&#xff0c;清理收集的应用日志数据&#xff0c;释放磁盘空间 #!/bin/bash# 定义 Elasticsearch 节点的地址 ELASTICSEARCH_HOST"192.168.53.100" …

虚拟化逻辑架构: 创建KVM中的VM与实现VNC远程登录

目录 一、实验 1.安装KVM环境管理工具并创建VM&#xff08;虚拟机&#xff09; 2.Windows使用VNC Viewer连接KVM中的VM&#xff08;虚拟机&#xff09; 二、问题 1.如何下载安装VNC Viewer 一、实验 1.安装KVM环境管理工具并创建VM&#xff08;虚拟机&#xff09; (1) 采…

德迅云安全和您聊聊关于DDOS高防ip的一些方面

德迅DDoS防护服务是以省骨干网的DDoS防护网络为基础&#xff0c;结合德迅自研的DDoS攻击检测和智能防护体系&#xff0c;向您提供可管理的DDoS防护服务&#xff0c;自动快速的缓解网络攻击对业务造成的延迟增加&#xff0c;访问受限&#xff0c;业务中断等影响&#xff0c;从而…

代码随想录算法训练营第二十九天| 491 递增子序列 46 全排列

目录 491 递增子序列 46 全排列 491 递增子序列 在dfs中进行判断&#xff0c;如果path的长度大于1&#xff0c;则将其添加到res中。 本题nums中的元素的值处于-100与100之间&#xff0c;可以将元素映射0到199之间并且通过布尔数组st来记录此层中元素是否被使用过&#xff0c;…

BeansTalkd 做消息队列服务

无意间看到这个仓库讲php关于 BeanStalkd 的扩展&#xff0c;然后就去了解了一下beanstalkd&#xff0c;用它可以用来做队列服务。 话不多说&#xff0c;安装一下试试。 首先 sudo apt search beanstalk 搜索一下发现 Sorting... Done Full Text Search... Done awscli/focal…

C练习题_14

一、单项选择题&#xff08;本大题共 20小题&#xff0c;每小题 2分&#xff0c;共 40分。在每小题给出的四个备选项中&#xff0c;选出一个正确的答案&#xff0c;并将所选项前的字母填写在答题纸的相应位置上。) 以下叙述不正确的是&#xff08;&#xff09; A.一个C源程序可…

高版本Vivado和Linux 4.x内核移植Digilent Driver

移植环境 Vivado 2022.2Ubuntu 22.04petalinux 2022.2Linux内核4.14&#xff08;xilinx-linux-2018.3&#xff09;linux-digilent 主要问题 https://github.com/Digilent/linux-digilent 这些驱动支持Linux kernel release 4.x&#xff0c;然而和Vitis 2022.2 套件对应的内核…

buildadmin+tp8表格操作(8) 表格下方添加 合计行

表格的下方可以自定义添加一个合计行&#xff0c;如果有其它的需求&#xff0c; 我们可以添加我们自已需要的行&#xff0c; 并不局限于合计行 以上就可以给表格的最下方添加一个合计行了 完整代码如下 <template><div class"default-main ba-table-box"&…

C语言十六弹 --求两个整数二进制位不同的位数

求两个整数二进制位不同的位数 思路&#xff1a;1.要求不同的个数 就必须遍历比较两个数的二进制位&#xff0c;不同就使用一个三方变量接收&#xff0c;相同则跳过。 2.使用一个相同的三方变量来作为两者判断条件的基础&#xff0c;而考虑到需要遍历二进制位 则使用1来作为三…

AVL树你需要了解一下

AVL树介绍 AVL树是一种自平衡二叉查找树&#xff0c;它得名于发明者G.M.Adel’son-Vel’skii和E.M.Landis。AVL树的特点是任何节点的两个子树的高度最大差别为1&#xff0c;因此它也被称为高度平衡树。在AVL树中&#xff0c;每个节点的平衡因子只有-1、0、1三种&#xff0c;通…

人工智能给我们的生活带来了巨大的影响?

1. 人工智能从哪些方面给我们带来了影响&#xff1f; 人工智能出现&#xff0c;极大地影响了人类的生活&#xff0c;下面是人工智能所影响的领域&#xff1a; 1. 日常生活 智能家居: AI驱动的设备&#xff0c;如智能扬声器、灯光、恒温器&#xff0c;正在改变我们与家居环境的…

【鸿蒙最新全套教程】<HarmonyOS第一课>1、运行Hello World

下载与安装DevEco Studio 在HarmonyOS应用开发学习之前&#xff0c;需要进行一些准备工作&#xff0c;首先需要完成开发工具DevEco Studio的下载与安装以及环境配置。 进入DevEco Studio下载官网&#xff0c;单击“立即下载”进入下载页面。 DevEco Studio提供了Windows版本和…

文件上传漏洞(CVE-2022-23043)

简介 CVE-2022-23043是一个与Zenario CMS 9.2文件上传漏洞相关的安全漏洞。该漏洞被定义为文件的不加限制上传&#xff0c;攻击者可以利用这个漏洞上传webshell以执行任意命令。利用这个漏洞的攻击者暂无特定情况。要利用此漏洞&#xff0c;攻击者首先需要访问Zenario CMS的管…

Django 路由配置(二)

一、路由 就是根据用户请求的URL链接来判断对应的出来程序&#xff0c;并返回处理结果&#xff0c;也是就是URL和django的视图建立映射关系. 二、Django请求页面的步骤 1、首先Django确定要使用的根URLconf模块&#xff0c;通过ROOT_URLCONF来设置&#xff0c;在settings.py配置…

服务器数据恢复—OCFS2下raid5磁盘损坏导致阵列崩溃的数据恢复案例

服务器数据恢复环境&#xff1a; IBM某型号存储&#xff0c;6块sas硬盘组建一组raid5&#xff0c;划分一个lun分配给Linux服务器并格式化为OCFS2文件系统&#xff0c;共享给虚拟化使用&#xff0c;存放的数据包括24台liunx和windows虚拟机、压缩包文件和配置文件。 服务器故障…

学习笔记6——垃圾回收

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/190801.html java垃圾回收&#xff08;stop the world&#xff09; 专注于堆和方法区的垃圾回收&#xff0c;年轻代&#xff0c;老年代&#xff0c;永久代判断对象是否还存…

Java8Stream快速使用

将List集合存入流中 List<String> list new ArrayList<>();list.add("张一");list.add("张二");list.add("张三");list.add("李四");list.add("赵五");list.add("张六");list.add("王八"…

Linux进程通信——IPC、管道、FIFO的引入

进程间的通信——IPC 进程间通信 (IPC&#xff0c;InterProcess Communication) 是指在不同进程之间传播或交换信息。 IPC的方式通常有管道 (包括无名管道和命名管道) 、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。 …

Spring的声明式事务

1. Spring声明式事务的使用流程 在Spring中使用声明式事务主要涉及以下几个步骤&#xff1a; 使用 DataSourceTransactionManager 是针对基于JDBC的应用程序。以下是在Spring框架中使用 DataSourceTransactionManager 的步骤&#xff1a; 1. 引入相关依赖 确保你的项目中包…