revmc_llvm/
dh.rs

1use inkwell::{
2    context::{AsContextRef, Context},
3    llvm_sys::{core::*, prelude::*, LLVMDiagnosticHandler, LLVMDiagnosticSeverity::*},
4};
5use std::{ffi::c_void, fmt, ptr};
6
7/// LLVM diagnostic handler guard.
8pub(crate) struct DiagnosticHandlerGuard<'ctx> {
9    cx: &'ctx Context,
10    prev_dh: LLVMDiagnosticHandler,
11    prev_dhc: *mut c_void,
12}
13
14impl fmt::Debug for DiagnosticHandlerGuard<'_> {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        f.debug_struct("DiagnosticHandlerGuard").finish_non_exhaustive()
17    }
18}
19
20impl<'ctx> DiagnosticHandlerGuard<'ctx> {
21    pub(crate) fn new(cx: &'ctx Context) -> Self {
22        unsafe {
23            let c = cx.as_ctx_ref();
24            let prev_dh = LLVMContextGetDiagnosticHandler(c);
25            let prev_dhc = LLVMContextGetDiagnosticContext(c);
26            LLVMContextSetDiagnosticHandler(c, Some(Self::diagnostic_handler), ptr::null_mut());
27            Self { cx, prev_dh, prev_dhc }
28        }
29    }
30
31    extern "C" fn diagnostic_handler(di: LLVMDiagnosticInfoRef, _context: *mut c_void) {
32        unsafe {
33            // `LLVMGetDiagInfoDescription` returns an LLVM `Message`.
34            let msg_cstr = crate::llvm_string(LLVMGetDiagInfoDescription(di));
35            let msg = msg_cstr.to_string_lossy();
36            match LLVMGetDiagInfoSeverity(di) {
37                LLVMDSError => error!(target: "llvm", "{msg}"),
38                LLVMDSWarning => warn!(target: "llvm", "{msg}"),
39                LLVMDSRemark => trace!(target: "llvm", "{msg}"),
40                LLVMDSNote => debug!(target: "llvm", "{msg}"),
41            }
42        }
43    }
44}
45
46impl Drop for DiagnosticHandlerGuard<'_> {
47    fn drop(&mut self) {
48        unsafe {
49            LLVMContextSetDiagnosticHandler(self.cx.as_ctx_ref(), self.prev_dh, self.prev_dhc);
50        }
51    }
52}