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 pub struct OptimizationDiagnostic<'ll> { 24 pub kind: OptimizationDiagnosticKind, 25 pub pass_name: String, 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 33 impl<'ll> OptimizationDiagnostic<'ll> { unpack(kind: OptimizationDiagnosticKind, di: &'ll DiagnosticInfo) -> Self34 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| { 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 77 pub struct SrcMgrDiagnostic { 78 pub level: super::DiagnosticLevel, 79 pub message: String, 80 pub source: Option<(String, Vec<InnerSpan>)>, 81 } 82 83 impl SrcMgrDiagnostic { unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic84 pub 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| { 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)] 124 pub struct InlineAsmDiagnostic { 125 pub level: super::DiagnosticLevel, 126 pub cookie: c_uint, 127 pub message: String, 128 pub source: Option<(String, Vec<InnerSpan>)>, 129 } 130 131 impl InlineAsmDiagnostic { unpackInlineAsm(di: &DiagnosticInfo) -> Self132 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 super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); 138 139 InlineAsmDiagnostic { 140 level, 141 cookie, 142 message: super::twine_to_string(message.unwrap()), 143 source: None, 144 } 145 } 146 unpackSrcMgr(di: &DiagnosticInfo) -> Self147 unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self { 148 let mut cookie = 0; 149 let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)); 150 InlineAsmDiagnostic { 151 level: smdiag.level, 152 cookie, 153 message: smdiag.message, 154 source: smdiag.source, 155 } 156 } 157 } 158 159 pub enum Diagnostic<'ll> { 160 Optimization(OptimizationDiagnostic<'ll>), 161 InlineAsm(InlineAsmDiagnostic), 162 PGO(&'ll DiagnosticInfo), 163 Linker(&'ll DiagnosticInfo), 164 Unsupported(&'ll DiagnosticInfo), 165 166 /// LLVM has other types that we do not wrap here. 167 UnknownDiagnostic(&'ll DiagnosticInfo), 168 } 169 170 impl<'ll> Diagnostic<'ll> { unpack(di: &'ll DiagnosticInfo) -> Self171 pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self { 172 use super::DiagnosticKind as Dk; 173 let kind = super::LLVMRustGetDiagInfoKind(di); 174 175 match kind { 176 Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)), 177 178 Dk::OptimizationRemark => { 179 Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) 180 } 181 Dk::OptimizationRemarkOther => { 182 Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di)) 183 } 184 Dk::OptimizationRemarkMissed => { 185 Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)) 186 } 187 188 Dk::OptimizationRemarkAnalysis => { 189 Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) 190 } 191 192 Dk::OptimizationRemarkAnalysisFPCommute => { 193 Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di)) 194 } 195 196 Dk::OptimizationRemarkAnalysisAliasing => { 197 Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di)) 198 } 199 200 Dk::OptimizationFailure => { 201 Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) 202 } 203 204 Dk::PGOProfile => PGO(di), 205 Dk::Linker => Linker(di), 206 Dk::Unsupported => Unsupported(di), 207 208 Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), 209 210 _ => UnknownDiagnostic(di), 211 } 212 } 213 } 214