lib.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. mod expand;
  2. use expand::{
  3. Args, BtfTracePoint, CgroupDevice, CgroupSkb, CgroupSock, CgroupSockAddr, CgroupSockopt,
  4. CgroupSysctl, FEntry, FExit, Lsm, Map, PerfEvent, Probe, ProbeKind, RawTracePoint,
  5. SchedClassifier, SkLookup, SkMsg, SkSkb, SkSkbKind, SockAddrArgs, SockOps, SocketFilter,
  6. SockoptArgs, TracePoint, Xdp,
  7. };
  8. use proc_macro::TokenStream;
  9. use syn::{parse_macro_input, ItemFn, ItemStatic};
  10. #[proc_macro_attribute]
  11. pub fn map(attrs: TokenStream, item: TokenStream) -> TokenStream {
  12. let args = parse_macro_input!(attrs as Args);
  13. let item = parse_macro_input!(item as ItemStatic);
  14. Map::from_syn(args, item)
  15. .and_then(|u| u.expand())
  16. .unwrap_or_else(|err| err.to_compile_error())
  17. .into()
  18. }
  19. #[proc_macro_attribute]
  20. pub fn kprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
  21. probe(ProbeKind::KProbe, attrs, item)
  22. }
  23. #[proc_macro_attribute]
  24. pub fn kretprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
  25. probe(ProbeKind::KRetProbe, attrs, item)
  26. }
  27. #[proc_macro_attribute]
  28. pub fn uprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
  29. probe(ProbeKind::UProbe, attrs, item)
  30. }
  31. #[proc_macro_attribute]
  32. pub fn uretprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
  33. probe(ProbeKind::URetProbe, attrs, item)
  34. }
  35. #[proc_macro_attribute]
  36. pub fn sock_ops(attrs: TokenStream, item: TokenStream) -> TokenStream {
  37. let args = parse_macro_input!(attrs as Args);
  38. let item = parse_macro_input!(item as ItemFn);
  39. SockOps::from_syn(args, item)
  40. .and_then(|u| u.expand())
  41. .unwrap_or_else(|err| err.to_compile_error())
  42. .into()
  43. }
  44. #[proc_macro_attribute]
  45. pub fn sk_msg(attrs: TokenStream, item: TokenStream) -> TokenStream {
  46. let args = parse_macro_input!(attrs as Args);
  47. let item = parse_macro_input!(item as ItemFn);
  48. SkMsg::from_syn(args, item)
  49. .and_then(|u| u.expand())
  50. .unwrap_or_else(|err| err.to_compile_error())
  51. .into()
  52. }
  53. #[proc_macro_attribute]
  54. pub fn xdp(attrs: TokenStream, item: TokenStream) -> TokenStream {
  55. let args = parse_macro_input!(attrs as Args);
  56. let item = parse_macro_input!(item as ItemFn);
  57. Xdp::from_syn(args, item)
  58. .and_then(|u| u.expand())
  59. .unwrap_or_else(|err| err.to_compile_error())
  60. .into()
  61. }
  62. #[proc_macro_attribute]
  63. pub fn classifier(attrs: TokenStream, item: TokenStream) -> TokenStream {
  64. let args = parse_macro_input!(attrs as Args);
  65. let item = parse_macro_input!(item as ItemFn);
  66. SchedClassifier::from_syn(args, item)
  67. .and_then(|u| u.expand())
  68. .unwrap_or_else(|err| err.to_compile_error())
  69. .into()
  70. }
  71. #[proc_macro_attribute]
  72. pub fn cgroup_sysctl(attrs: TokenStream, item: TokenStream) -> TokenStream {
  73. let args = parse_macro_input!(attrs as Args);
  74. let item = parse_macro_input!(item as ItemFn);
  75. CgroupSysctl::from_syn(args, item)
  76. .and_then(|u| u.expand())
  77. .unwrap_or_else(|err| err.to_compile_error())
  78. .into()
  79. }
  80. #[proc_macro_attribute]
  81. pub fn cgroup_sockopt(attrs: TokenStream, item: TokenStream) -> TokenStream {
  82. let args = parse_macro_input!(attrs as SockoptArgs);
  83. let attach_type = args.attach_type.to_string();
  84. let item = parse_macro_input!(item as ItemFn);
  85. CgroupSockopt::from_syn(args.args, item, attach_type)
  86. .and_then(|u| u.expand())
  87. .unwrap_or_else(|err| err.to_compile_error())
  88. .into()
  89. }
  90. #[proc_macro_attribute]
  91. pub fn cgroup_skb(attrs: TokenStream, item: TokenStream) -> TokenStream {
  92. let args = parse_macro_input!(attrs as Args);
  93. let item = parse_macro_input!(item as ItemFn);
  94. CgroupSkb::from_syn(args, item)
  95. .and_then(|u| u.expand())
  96. .unwrap_or_else(|err| err.to_compile_error())
  97. .into()
  98. }
  99. /// Marks a function as a [`CgroupSockAddr`] eBPF program.
  100. ///
  101. /// [`CgroupSockAddr`] programs can be used to inspect or modify socket addresses passed to
  102. /// various syscalls within a [cgroup]. The `attach_type` argument specifies a place to attach
  103. /// the eBPF program to. See [`CgroupSockAddrAttachType`] for more details.
  104. ///
  105. /// [cgroup]: https://man7.org/linux/man-pages/man7/cgroups.7.html
  106. /// [`CgroupSockAddrAttachType`]: ../aya/programs/cgroup_sock_addr/enum.CgroupSockAddrAttachType.html
  107. /// [`CgroupSockAddr`]: ../aya/programs/cgroup_sock_addr/struct.CgroupSockAddr.html
  108. ///
  109. /// # Minimum kernel version
  110. ///
  111. /// The minimum kernel version required to use this feature is 4.17.
  112. ///
  113. /// # Examples
  114. ///
  115. /// ```no_run
  116. /// use aya_bpf::{macros::cgroup_sock_addr, programs::SockAddrContext};
  117. ///
  118. /// #[cgroup_sock_addr(connect4)]
  119. /// pub fn connect4(ctx: SockAddrContext) -> i32 {
  120. /// match try_connect4(ctx) {
  121. /// Ok(ret) => ret,
  122. /// Err(ret) => match ret.try_into() {
  123. /// Ok(rt) => rt,
  124. /// Err(_) => 1,
  125. /// },
  126. /// }
  127. /// }
  128. ///
  129. /// fn try_connect4(ctx: SockAddrContext) -> Result<i32, i64> {
  130. /// Ok(0)
  131. /// }
  132. /// ```
  133. #[proc_macro_attribute]
  134. pub fn cgroup_sock_addr(attrs: TokenStream, item: TokenStream) -> TokenStream {
  135. let args = parse_macro_input!(attrs as SockAddrArgs);
  136. let attach_type = args.attach_type.to_string();
  137. let item = parse_macro_input!(item as ItemFn);
  138. CgroupSockAddr::from_syn(args.args, item, attach_type)
  139. .and_then(|u| u.expand())
  140. .unwrap_or_else(|err| err.to_compile_error())
  141. .into()
  142. }
  143. #[proc_macro_attribute]
  144. pub fn cgroup_sock(attrs: TokenStream, item: TokenStream) -> TokenStream {
  145. let args = parse_macro_input!(attrs as Args);
  146. let item = parse_macro_input!(item as ItemFn);
  147. CgroupSock::from_syn(args, item)
  148. .and_then(|u| u.expand())
  149. .unwrap_or_else(|err| err.to_compile_error())
  150. .into()
  151. }
  152. fn probe(kind: ProbeKind, attrs: TokenStream, item: TokenStream) -> TokenStream {
  153. let args = parse_macro_input!(attrs as Args);
  154. let item = parse_macro_input!(item as ItemFn);
  155. Probe::from_syn(kind, args, item)
  156. .and_then(|u| u.expand())
  157. .unwrap_or_else(|err| err.to_compile_error())
  158. .into()
  159. }
  160. #[proc_macro_attribute]
  161. pub fn tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
  162. let args = parse_macro_input!(attrs as Args);
  163. let item = parse_macro_input!(item as ItemFn);
  164. TracePoint::from_syn(args, item)
  165. .and_then(|u| u.expand())
  166. .unwrap_or_else(|err| err.to_compile_error())
  167. .into()
  168. }
  169. #[proc_macro_attribute]
  170. pub fn perf_event(attrs: TokenStream, item: TokenStream) -> TokenStream {
  171. let args = parse_macro_input!(attrs as Args);
  172. let item = parse_macro_input!(item as ItemFn);
  173. PerfEvent::from_syn(args, item)
  174. .and_then(|u| u.expand())
  175. .unwrap_or_else(|err| err.to_compile_error())
  176. .into()
  177. }
  178. /// Marks a function as a raw tracepoint eBPF program that can be attached at a
  179. /// pre-defined kernel trace point.
  180. ///
  181. /// The kernel provides a set of pre-defined trace points that eBPF programs can
  182. /// be attached to. See `/sys/kernel/debug/tracing/events` for a list of which
  183. /// events can be traced.
  184. ///
  185. /// # Minimum kernel version
  186. ///
  187. /// The minimum kernel version required to use this feature is 4.7.
  188. ///
  189. /// # Examples
  190. ///
  191. /// ```no_run
  192. /// use aya_bpf::{macros::raw_tracepoint, programs::RawTracePointContext};
  193. ///
  194. /// #[raw_tracepoint(name = "sys_enter")]
  195. /// pub fn sys_enter(ctx: RawTracePointContext) -> i32 {
  196. /// match unsafe { try_sys_enter(ctx) } {
  197. /// Ok(ret) => ret,
  198. /// Err(ret) => ret,
  199. /// }
  200. /// }
  201. ///
  202. /// unsafe fn try_sys_enter(_ctx: RawTracePointContext) -> Result<i32, i32> {
  203. /// Ok(0)
  204. /// }
  205. /// ```
  206. #[proc_macro_attribute]
  207. pub fn raw_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
  208. let args = parse_macro_input!(attrs as Args);
  209. let item = parse_macro_input!(item as ItemFn);
  210. RawTracePoint::from_syn(args, item)
  211. .and_then(|u| u.expand())
  212. .unwrap_or_else(|err| err.to_compile_error())
  213. .into()
  214. }
  215. /// Marks a function as an LSM program that can be attached to Linux LSM hooks.
  216. /// Used to implement security policy and audit logging.
  217. ///
  218. /// LSM probes can be attached to the kernel's security hooks to implement mandatory
  219. /// access control policy and security auditing.
  220. ///
  221. /// LSM probes require a kernel compiled with `CONFIG_BPF_LSM=y` and `CONFIG_DEBUG_INFO_BTF=y`.
  222. /// In order for the probes to fire, you also need the BPF LSM to be enabled through your
  223. /// kernel's boot paramters (like `lsm=lockdown,yama,bpf`).
  224. ///
  225. /// # Minimum kernel version
  226. ///
  227. /// The minimum kernel version required to use this feature is 5.7.
  228. ///
  229. /// # Examples
  230. ///
  231. /// ```no_run
  232. /// use aya_bpf::{macros::lsm, programs::LsmContext};
  233. ///
  234. /// #[lsm(name = "file_open")]
  235. /// pub fn file_open(ctx: LsmContext) -> i32 {
  236. /// match unsafe { try_file_open(ctx) } {
  237. /// Ok(ret) => ret,
  238. /// Err(ret) => ret,
  239. /// }
  240. /// }
  241. ///
  242. /// unsafe fn try_file_open(_ctx: LsmContext) -> Result<i32, i32> {
  243. /// Ok(0)
  244. /// }
  245. /// ```
  246. #[proc_macro_attribute]
  247. pub fn lsm(attrs: TokenStream, item: TokenStream) -> TokenStream {
  248. let args = parse_macro_input!(attrs as Args);
  249. let item = parse_macro_input!(item as ItemFn);
  250. Lsm::from_syn(args, item)
  251. .and_then(|u| u.expand())
  252. .unwrap_or_else(|err| err.to_compile_error())
  253. .into()
  254. }
  255. /// Marks a function as a [BTF-enabled raw tracepoint][1] eBPF program that can be attached at
  256. /// a pre-defined kernel trace point.
  257. ///
  258. /// The kernel provides a set of pre-defined trace points that eBPF programs can
  259. /// be attached to. See `/sys/kernel/debug/tracing/events` for a list of which
  260. /// events can be traced.
  261. ///
  262. /// # Minimum kernel version
  263. ///
  264. /// The minimum kernel version required to use this feature is 5.5.
  265. ///
  266. /// # Examples
  267. ///
  268. /// ```no_run
  269. /// use aya_bpf::{macros::btf_tracepoint, programs::BtfTracePointContext};
  270. ///
  271. /// #[btf_tracepoint(name = "sched_process_fork")]
  272. /// pub fn sched_process_fork(ctx: BtfTracePointContext) -> u32 {
  273. /// match unsafe { try_sched_process_fork(ctx) } {
  274. /// Ok(ret) => ret,
  275. /// Err(ret) => ret,
  276. /// }
  277. /// }
  278. ///
  279. /// unsafe fn try_sched_process_fork(_ctx: BtfTracePointContext) -> Result<u32, u32> {
  280. /// Ok(0)
  281. /// }
  282. /// ```
  283. ///
  284. /// [1]: https://github.com/torvalds/linux/commit/9e15db66136a14cde3f35691f1d839d950118826
  285. #[proc_macro_attribute]
  286. pub fn btf_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
  287. let args = parse_macro_input!(attrs as Args);
  288. let item = parse_macro_input!(item as ItemFn);
  289. BtfTracePoint::from_syn(args, item)
  290. .and_then(|u| u.expand())
  291. .unwrap_or_else(|err| err.to_compile_error())
  292. .into()
  293. }
  294. /// Marks a function as a SK_SKB Stream Parser eBPF program that can be attached
  295. /// to a SockMap
  296. ///
  297. /// # Minimum kernel version
  298. ///
  299. /// The minimum kernel version required to use this feature is 4.14
  300. ///
  301. /// # Examples
  302. ///
  303. /// ```no_run
  304. /// use aya_bpf::{macros::stream_parser, programs::SkBuffContext};
  305. ///
  306. ///
  307. ///#[stream_parser]
  308. ///fn stream_parser(ctx: SkBuffContext) -> u32 {
  309. /// match { try_stream_parser(ctx) } {
  310. /// Ok(ret) => ret,
  311. /// Err(ret) => ret,
  312. /// }
  313. ///}
  314. ///
  315. ///fn try_stream_parser(ctx: SkBuffContext) -> Result<u32, u32> {
  316. /// Ok(ctx.len())
  317. ///}
  318. /// ```
  319. #[proc_macro_attribute]
  320. pub fn stream_parser(attrs: TokenStream, item: TokenStream) -> TokenStream {
  321. sk_skb(SkSkbKind::StreamParser, attrs, item)
  322. }
  323. /// Marks a function as a SK_SKB Stream Verdict eBPF program that can be attached
  324. /// to a SockMap
  325. ///
  326. /// # Minimum kernel version
  327. ///
  328. /// The minimum kernel version required to use this feature is 4.14
  329. ///
  330. /// # Examples
  331. ///
  332. /// ```no_run
  333. /// use aya_bpf::{macros::stream_verdict, programs::SkBuffContext, bindings::sk_action};
  334. ///
  335. ///
  336. ///#[stream_verdict]
  337. ///fn stream_verdict(ctx: SkBuffContext) -> u32 {
  338. /// match { try_stream_verdict(ctx) } {
  339. /// Ok(ret) => ret,
  340. /// Err(ret) => ret,
  341. /// }
  342. ///}
  343. ///
  344. ///fn try_stream_verdict(_ctx: SkBuffContext) -> Result<u32, u32> {
  345. /// Ok(sk_action::SK_PASS)
  346. ///}
  347. /// ```
  348. #[proc_macro_attribute]
  349. pub fn stream_verdict(attrs: TokenStream, item: TokenStream) -> TokenStream {
  350. sk_skb(SkSkbKind::StreamVerdict, attrs, item)
  351. }
  352. fn sk_skb(kind: SkSkbKind, attrs: TokenStream, item: TokenStream) -> TokenStream {
  353. let args = parse_macro_input!(attrs as Args);
  354. let item = parse_macro_input!(item as ItemFn);
  355. SkSkb::from_syn(kind, args, item)
  356. .and_then(|u| u.expand())
  357. .unwrap_or_else(|err| err.to_compile_error())
  358. .into()
  359. }
  360. /// Marks a function as a eBPF Socket Filter program that can be attached to
  361. /// a socket.
  362. ///
  363. /// # Minimum kernel version
  364. ///
  365. /// The minimum kernel version required to use this feature is 3.19
  366. ///
  367. /// # Examples
  368. ///
  369. /// ```no_run
  370. /// use aya_bpf::{macros::socket_filter, programs::SkBuffContext};
  371. ///
  372. /// #[socket_filter(name = "accept_all")]
  373. /// pub fn accept_all(_ctx: SkBuffContext) -> i64 {
  374. /// return 0
  375. /// }
  376. /// ```
  377. #[proc_macro_attribute]
  378. pub fn socket_filter(attrs: TokenStream, item: TokenStream) -> TokenStream {
  379. let args = parse_macro_input!(attrs as Args);
  380. let item = parse_macro_input!(item as ItemFn);
  381. SocketFilter::from_syn(args, item)
  382. .and_then(|u| u.expand())
  383. .unwrap_or_else(|err| err.to_compile_error())
  384. .into()
  385. }
  386. /// Marks a function as a fentry eBPF program that can be attached to almost
  387. /// any function inside the kernel. The difference between fentry and kprobe
  388. /// is that fexit has practically zero overhead to call before kernel function.
  389. /// fentry programs can be also attached to other eBPF programs.
  390. ///
  391. /// # Minimumm kernel version
  392. ///
  393. /// The minimum kernel version required to use this feature is 5.5.
  394. ///
  395. /// # Examples
  396. ///
  397. /// ```no_run
  398. /// # #![allow(non_camel_case_types)]
  399. /// use aya_bpf::{macros::fentry, programs::FEntryContext};
  400. /// # type filename = u32;
  401. /// # type path = u32;
  402. ///
  403. /// #[fentry(name = "filename_lookup")]
  404. /// fn filename_lookup(ctx: FEntryContext) -> i32 {
  405. /// match unsafe { try_filename_lookup(ctx) } {
  406. /// Ok(ret) => ret,
  407. /// Err(ret) => ret,
  408. /// }
  409. /// }
  410. ///
  411. /// unsafe fn try_filename_lookup(ctx: FEntryContext) -> Result<i32, i32> {
  412. /// let _f: *const filename = ctx.arg(1);
  413. /// let _p: *const path = ctx.arg(3);
  414. ///
  415. /// Ok(0)
  416. /// }
  417. /// ```
  418. #[proc_macro_attribute]
  419. pub fn fentry(attrs: TokenStream, item: TokenStream) -> TokenStream {
  420. let args = parse_macro_input!(attrs as Args);
  421. let item = parse_macro_input!(item as ItemFn);
  422. FEntry::from_syn(args, item)
  423. .and_then(|u| u.expand())
  424. .unwrap_or_else(|err| err.to_compile_error())
  425. .into()
  426. }
  427. /// Marks a function as a fexit eBPF program that can be attached to almost
  428. /// any function inside the kernel. The difference between fexit and kretprobe
  429. /// is that fexit has practically zero overhead to call after kernel function
  430. /// and it focuses on access to arguments rather than the return value. fexit
  431. /// programs can be also attached to other eBPF programs
  432. ///
  433. /// # Minimumm kernel version
  434. ///
  435. /// The minimum kernel version required to use this feature is 5.5.
  436. ///
  437. /// # Examples
  438. ///
  439. /// ```no_run
  440. /// # #![allow(non_camel_case_types)]
  441. /// use aya_bpf::{macros::fexit, programs::FExitContext};
  442. /// # type filename = u32;
  443. /// # type path = u32;
  444. ///
  445. /// #[fexit(name = "filename_lookup")]
  446. /// fn filename_lookup(ctx: FExitContext) -> i32 {
  447. /// match unsafe { try_filename_lookup(ctx) } {
  448. /// Ok(ret) => ret,
  449. /// Err(ret) => ret,
  450. /// }
  451. /// }
  452. ///
  453. /// unsafe fn try_filename_lookup(ctx: FExitContext) -> Result<i32, i32> {
  454. /// let _f: *const filename = ctx.arg(1);
  455. /// let _p: *const path = ctx.arg(3);
  456. ///
  457. /// Ok(0)
  458. /// }
  459. /// ```
  460. #[proc_macro_attribute]
  461. pub fn fexit(attrs: TokenStream, item: TokenStream) -> TokenStream {
  462. let args = parse_macro_input!(attrs as Args);
  463. let item = parse_macro_input!(item as ItemFn);
  464. FExit::from_syn(args, item)
  465. .and_then(|u| u.expand())
  466. .unwrap_or_else(|err| err.to_compile_error())
  467. .into()
  468. }
  469. /// Marks a function as an eBPF Socket Lookup program that can be attached to
  470. /// a network namespace.
  471. ///
  472. /// # Minimum kernel version
  473. ///
  474. /// The minimum kernel version required to use this feature is 5.9
  475. ///
  476. /// # Examples
  477. ///
  478. /// ```no_run
  479. /// use aya_bpf::{macros::sk_lookup, programs::SkLookupContext};
  480. ///
  481. /// #[sk_lookup(name = "redirect")]
  482. /// pub fn accept_all(_ctx: SkLookupContext) -> u32 {
  483. /// // use sk_assign to redirect
  484. /// return 0
  485. /// }
  486. /// ```
  487. #[proc_macro_attribute]
  488. pub fn sk_lookup(attrs: TokenStream, item: TokenStream) -> TokenStream {
  489. let args = parse_macro_input!(attrs as Args);
  490. let item = parse_macro_input!(item as ItemFn);
  491. SkLookup::from_syn(args, item)
  492. .and_then(|u| u.expand())
  493. .unwrap_or_else(|err| err.to_compile_error())
  494. .into()
  495. }
  496. /// Marks a function as a cgroup device eBPF program that can be attached to a
  497. /// cgroup.
  498. ///
  499. /// # Minimum kernel version
  500. ///
  501. /// The minimum kernel version required to use this feature is 4.15.
  502. ///
  503. /// # Examples
  504. ///
  505. /// ```no_run
  506. /// use aya_bpf::{
  507. /// macros::cgroup_device,
  508. /// programs::DeviceContext,
  509. /// };
  510. ///
  511. /// #[cgroup_device(name="cgroup_dev")]
  512. /// pub fn cgroup_dev(ctx: DeviceContext) -> i32 {
  513. /// // Reject all device access
  514. /// return 0;
  515. /// }
  516. /// ```
  517. #[proc_macro_attribute]
  518. pub fn cgroup_device(attrs: TokenStream, item: TokenStream) -> TokenStream {
  519. let args = parse_macro_input!(attrs as Args);
  520. let item = parse_macro_input!(item as ItemFn);
  521. CgroupDevice::from_syn(args, item)
  522. .and_then(|u| u.expand())
  523. .unwrap_or_else(|err| err.to_compile_error())
  524. .into()
  525. }