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