rustc_codegen_llvm/llvm/
diagnostic.rs

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