rustc_codegen_llvm/llvm/
diagnostic.rs

1//! LLVM diagnostic reports.
2
3use libc::c_uint;
4use rustc_span::InnerSpan;
5
6pub(crate) use self::Diagnostic::*;
7use self::OptimizationDiagnosticKind::*;
8use super::{DiagnosticInfo, SMDiagnostic};
9use crate::value::Value;
10
11#[derive(Copy, Clone, Debug)]
12pub(crate) enum OptimizationDiagnosticKind {
13    OptimizationRemark,
14    OptimizationMissed,
15    OptimizationAnalysis,
16    OptimizationAnalysisFPCommute,
17    OptimizationAnalysisAliasing,
18    OptimizationFailure,
19    OptimizationRemarkOther,
20}
21
22pub(crate) struct OptimizationDiagnostic<'ll> {
23    pub kind: OptimizationDiagnosticKind,
24    pub pass_name: String,
25    #[expect(dead_code)]
26    pub function: &'ll Value,
27    pub line: c_uint,
28    pub column: c_uint,
29    pub filename: String,
30    pub message: String,
31}
32
33impl<'ll> OptimizationDiagnostic<'ll> {
34    unsafe fn unpack(kind: OptimizationDiagnosticKind, di: &'ll DiagnosticInfo) -> Self {
35        let mut function = None;
36        let mut line = 0;
37        let mut column = 0;
38
39        let mut message = None;
40        let mut filename = None;
41        let pass_name = super::build_string(|pass_name| {
42            message = super::build_string(|message| {
43                filename = super::build_string(|filename| unsafe {
44                    super::LLVMRustUnpackOptimizationDiagnostic(
45                        di,
46                        pass_name,
47                        &mut function,
48                        &mut line,
49                        &mut column,
50                        filename,
51                        message,
52                    )
53                })
54                .ok()
55            })
56            .ok()
57        })
58        .ok();
59
60        let mut filename = filename.unwrap_or_default();
61        if filename.is_empty() {
62            filename.push_str("<unknown file>");
63        }
64
65        OptimizationDiagnostic {
66            kind,
67            pass_name: pass_name.expect("got a non-UTF8 pass name from LLVM"),
68            function: function.unwrap(),
69            line,
70            column,
71            filename,
72            message: message.expect("got a non-UTF8 OptimizationDiagnostic message from LLVM"),
73        }
74    }
75}
76
77pub(crate) struct SrcMgrDiagnostic {
78    pub level: super::DiagnosticLevel,
79    pub message: String,
80    pub source: Option<(String, Vec<InnerSpan>)>,
81}
82
83impl SrcMgrDiagnostic {
84    pub(crate) unsafe fn unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic {
85        // Recover the post-substitution assembly code from LLVM for better
86        // diagnostics.
87        let mut have_source = false;
88        let mut buffer = String::new();
89        let mut level = super::DiagnosticLevel::Error;
90        let mut loc = 0;
91        let mut ranges = [0; 8];
92        let mut num_ranges = ranges.len() / 2;
93        let message = super::build_string(|message| {
94            buffer = super::build_string(|buffer| unsafe {
95                have_source = super::LLVMRustUnpackSMDiagnostic(
96                    diag,
97                    message,
98                    buffer,
99                    &mut level,
100                    &mut loc,
101                    ranges.as_mut_ptr(),
102                    &mut num_ranges,
103                );
104            })
105            .expect("non-UTF8 inline asm");
106        })
107        .expect("non-UTF8 SMDiagnostic");
108
109        SrcMgrDiagnostic {
110            message,
111            level,
112            source: have_source.then(|| {
113                let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
114                for i in 0..num_ranges {
115                    spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
116                }
117                (buffer, spans)
118            }),
119        }
120    }
121}
122
123#[derive(Clone)]
124pub(crate) struct InlineAsmDiagnostic {
125    pub level: super::DiagnosticLevel,
126    pub cookie: u64,
127    pub message: String,
128    pub source: Option<(String, Vec<InnerSpan>)>,
129}
130
131impl InlineAsmDiagnostic {
132    unsafe fn unpackInlineAsm(di: &DiagnosticInfo) -> Self {
133        let mut cookie = 0;
134        let mut message = None;
135        let mut level = super::DiagnosticLevel::Error;
136
137        unsafe {
138            super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);
139        }
140
141        InlineAsmDiagnostic {
142            level,
143            cookie,
144            message: super::twine_to_string(message.unwrap()),
145            source: None,
146        }
147    }
148
149    unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self {
150        let mut cookie = 0;
151        let smdiag =
152            unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) };
153        InlineAsmDiagnostic {
154            level: smdiag.level,
155            cookie,
156            message: smdiag.message,
157            source: smdiag.source,
158        }
159    }
160}
161
162pub(crate) enum Diagnostic<'ll> {
163    Optimization(OptimizationDiagnostic<'ll>),
164    InlineAsm(InlineAsmDiagnostic),
165    PGO(&'ll DiagnosticInfo),
166    Linker(&'ll DiagnosticInfo),
167    Unsupported(&'ll DiagnosticInfo),
168
169    /// LLVM has other types that we do not wrap here.
170    #[expect(dead_code)]
171    UnknownDiagnostic(&'ll DiagnosticInfo),
172}
173
174impl<'ll> Diagnostic<'ll> {
175    pub(crate) unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
176        use super::DiagnosticKind as Dk;
177
178        unsafe {
179            let kind = super::LLVMRustGetDiagInfoKind(di);
180            match kind {
181                Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),
182
183                Dk::OptimizationRemark => {
184                    Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
185                }
186                Dk::OptimizationRemarkOther => {
187                    Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di))
188                }
189                Dk::OptimizationRemarkMissed => {
190                    Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di))
191                }
192
193                Dk::OptimizationRemarkAnalysis => {
194                    Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di))
195                }
196
197                Dk::OptimizationRemarkAnalysisFPCommute => {
198                    Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di))
199                }
200
201                Dk::OptimizationRemarkAnalysisAliasing => {
202                    Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di))
203                }
204
205                Dk::OptimizationFailure => {
206                    Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di))
207                }
208
209                Dk::PGOProfile => PGO(di),
210                Dk::Linker => Linker(di),
211                Dk::Unsupported => Unsupported(di),
212
213                Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)),
214
215                _ => UnknownDiagnostic(di),
216            }
217        }
218    }
219}