1
Fork 0

Handle SrcMgr diagnostics

This is how InlineAsm diagnostics with source information are
reported now. Previously a separate InlineAsm diagnostic handler
was used.
This commit is contained in:
Nikita Popov 2021-07-28 21:31:47 +02:00
parent 2967036f57
commit 621f5146c3
6 changed files with 108 additions and 66 deletions

View file

@ -296,39 +296,8 @@ unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void
} }
let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler)); let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
// Recover the post-substitution assembly code from LLVM for better let smdiag = llvm::diagnostic::SrcMgrDiagnostic::unpack(diag);
// diagnostics. report_inline_asm(cgcx, smdiag.message, smdiag.level, cookie, smdiag.source);
let mut have_source = false;
let mut buffer = String::new();
let mut level = llvm::DiagnosticLevel::Error;
let mut loc = 0;
let mut ranges = [0; 8];
let mut num_ranges = ranges.len() / 2;
let msg = llvm::build_string(|msg| {
buffer = llvm::build_string(|buffer| {
have_source = llvm::LLVMRustUnpackSMDiagnostic(
diag,
msg,
buffer,
&mut level,
&mut loc,
ranges.as_mut_ptr(),
&mut num_ranges,
);
})
.expect("non-UTF8 inline asm");
})
.expect("non-UTF8 SMDiagnostic");
let source = have_source.then(|| {
let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
for i in 0..num_ranges {
spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
}
(buffer, spans)
});
report_inline_asm(cgcx, msg, level, cookie, source);
} }
unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
@ -339,13 +308,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
match llvm::diagnostic::Diagnostic::unpack(info) { match llvm::diagnostic::Diagnostic::unpack(info) {
llvm::diagnostic::InlineAsm(inline) => { llvm::diagnostic::InlineAsm(inline) => {
report_inline_asm( report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source);
cgcx,
llvm::twine_to_string(inline.message),
inline.level,
inline.cookie,
None,
);
} }
llvm::diagnostic::Optimization(opt) => { llvm::diagnostic::Optimization(opt) => {

View file

@ -6,7 +6,8 @@ pub use self::OptimizationDiagnosticKind::*;
use crate::value::Value; use crate::value::Value;
use libc::c_uint; use libc::c_uint;
use super::{DiagnosticInfo, Twine}; use super::{DiagnosticInfo, SMDiagnostic};
use rustc_span::InnerSpan;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum OptimizationDiagnosticKind { pub enum OptimizationDiagnosticKind {
@ -86,36 +87,91 @@ impl OptimizationDiagnostic<'ll> {
} }
} }
#[derive(Copy, Clone)] pub struct SrcMgrDiagnostic {
pub struct InlineAsmDiagnostic<'ll> {
pub level: super::DiagnosticLevel, pub level: super::DiagnosticLevel,
pub cookie: c_uint, pub message: String,
pub message: &'ll Twine, pub source: Option<(String, Vec<InnerSpan>)>,
pub instruction: Option<&'ll Value>,
} }
impl InlineAsmDiagnostic<'ll> { impl SrcMgrDiagnostic {
unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self { pub unsafe fn unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic {
// Recover the post-substitution assembly code from LLVM for better
// diagnostics.
let mut have_source = false;
let mut buffer = String::new();
let mut level = super::DiagnosticLevel::Error;
let mut loc = 0;
let mut ranges = [0; 8];
let mut num_ranges = ranges.len() / 2;
let message = super::build_string(|message| {
buffer = super::build_string(|buffer| {
have_source = super::LLVMRustUnpackSMDiagnostic(
diag,
message,
buffer,
&mut level,
&mut loc,
ranges.as_mut_ptr(),
&mut num_ranges,
);
})
.expect("non-UTF8 inline asm");
})
.expect("non-UTF8 SMDiagnostic");
SrcMgrDiagnostic {
message,
level,
source: have_source.then(|| {
let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
for i in 0..num_ranges {
spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
}
(buffer, spans)
}),
}
}
}
#[derive(Clone)]
pub struct InlineAsmDiagnostic {
pub level: super::DiagnosticLevel,
pub cookie: c_uint,
pub message: String,
pub source: Option<(String, Vec<InnerSpan>)>,
}
impl InlineAsmDiagnostic {
unsafe fn unpackInlineAsm(di: &'ll DiagnosticInfo) -> Self {
let mut cookie = 0; let mut cookie = 0;
let mut message = None; let mut message = None;
let mut instruction = None;
let mut level = super::DiagnosticLevel::Error; let mut level = super::DiagnosticLevel::Error;
super::LLVMRustUnpackInlineAsmDiagnostic( super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);
di,
&mut level,
&mut cookie,
&mut message,
&mut instruction,
);
InlineAsmDiagnostic { level, cookie, message: message.unwrap(), instruction } InlineAsmDiagnostic {
level,
cookie,
message: super::twine_to_string(message.unwrap()),
source: None,
}
}
unsafe fn unpackSrcMgr(di: &'ll DiagnosticInfo) -> Self {
let mut cookie = 0;
let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie));
InlineAsmDiagnostic {
level: smdiag.level,
cookie,
message: smdiag.message,
source: smdiag.source,
}
} }
} }
pub enum Diagnostic<'ll> { pub enum Diagnostic<'ll> {
Optimization(OptimizationDiagnostic<'ll>), Optimization(OptimizationDiagnostic<'ll>),
InlineAsm(InlineAsmDiagnostic<'ll>), InlineAsm(InlineAsmDiagnostic),
PGO(&'ll DiagnosticInfo), PGO(&'ll DiagnosticInfo),
Linker(&'ll DiagnosticInfo), Linker(&'ll DiagnosticInfo),
Unsupported(&'ll DiagnosticInfo), Unsupported(&'ll DiagnosticInfo),
@ -130,7 +186,7 @@ impl Diagnostic<'ll> {
let kind = super::LLVMRustGetDiagInfoKind(di); let kind = super::LLVMRustGetDiagInfoKind(di);
match kind { match kind {
Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)), Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),
Dk::OptimizationRemark => { Dk::OptimizationRemark => {
Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
@ -162,6 +218,8 @@ impl Diagnostic<'ll> {
Dk::Linker => Linker(di), Dk::Linker => Linker(di),
Dk::Unsupported => Unsupported(di), Dk::Unsupported => Unsupported(di),
Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)),
_ => UnknownDiagnostic(di), _ => UnknownDiagnostic(di),
} }
} }

View file

@ -490,6 +490,7 @@ pub enum DiagnosticKind {
PGOProfile, PGOProfile,
Linker, Linker,
Unsupported, Unsupported,
SrcMgr,
} }
/// LLVMRustDiagnosticLevel /// LLVMRustDiagnosticLevel
@ -2264,13 +2265,17 @@ extern "C" {
level_out: &mut DiagnosticLevel, level_out: &mut DiagnosticLevel,
cookie_out: &mut c_uint, cookie_out: &mut c_uint,
message_out: &mut Option<&'a Twine>, message_out: &mut Option<&'a Twine>,
instruction_out: &mut Option<&'a Value>,
); );
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString); pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind; pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
pub fn LLVMRustGetSMDiagnostic(
DI: &'a DiagnosticInfo,
cookie_out: &mut c_uint,
) -> &'a SMDiagnostic;
pub fn LLVMRustSetInlineAsmDiagnosticHandler( pub fn LLVMRustSetInlineAsmDiagnosticHandler(
C: &Context, C: &Context,
H: InlineAsmDiagHandler, H: InlineAsmDiagHandler,

View file

@ -1114,15 +1114,13 @@ extern "C" void
LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI, LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI,
LLVMRustDiagnosticLevel *LevelOut, LLVMRustDiagnosticLevel *LevelOut,
unsigned *CookieOut, unsigned *CookieOut,
LLVMTwineRef *MessageOut, LLVMTwineRef *MessageOut) {
LLVMValueRef *InstructionOut) {
// Undefined to call this not on an inline assembly diagnostic! // Undefined to call this not on an inline assembly diagnostic!
llvm::DiagnosticInfoInlineAsm *IA = llvm::DiagnosticInfoInlineAsm *IA =
static_cast<llvm::DiagnosticInfoInlineAsm *>(unwrap(DI)); static_cast<llvm::DiagnosticInfoInlineAsm *>(unwrap(DI));
*CookieOut = IA->getLocCookie(); *CookieOut = IA->getLocCookie();
*MessageOut = wrap(&IA->getMsgStr()); *MessageOut = wrap(&IA->getMsgStr());
*InstructionOut = wrap(IA->getInstruction());
switch (IA->getSeverity()) { switch (IA->getSeverity()) {
case DS_Error: case DS_Error:
@ -1165,6 +1163,7 @@ enum class LLVMRustDiagnosticKind {
PGOProfile, PGOProfile,
Linker, Linker,
Unsupported, Unsupported,
SrcMgr,
}; };
static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
@ -1193,6 +1192,10 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
return LLVMRustDiagnosticKind::Linker; return LLVMRustDiagnosticKind::Linker;
case DK_Unsupported: case DK_Unsupported:
return LLVMRustDiagnosticKind::Unsupported; return LLVMRustDiagnosticKind::Unsupported;
#if LLVM_VERSION_GE(13, 0)
case DK_SrcMgr:
return LLVMRustDiagnosticKind::SrcMgr;
#endif
default: default:
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark) return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
? LLVMRustDiagnosticKind::OptimizationRemarkOther ? LLVMRustDiagnosticKind::OptimizationRemarkOther
@ -1280,6 +1283,17 @@ extern "C" void LLVMRustSetInlineAsmDiagnosticHandler(
#endif #endif
} }
extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(
LLVMDiagnosticInfoRef DI, unsigned *Cookie) {
#if LLVM_VERSION_GE(13, 0)
llvm::DiagnosticInfoSrcMgr *SM = static_cast<llvm::DiagnosticInfoSrcMgr *>(unwrap(DI));
*Cookie = SM->getLocCookie();
return wrap(&SM->getSMDiag());
#else
report_fatal_error("Shouldn't get called on older versions");
#endif
}
extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef,
RustStringRef MessageOut, RustStringRef MessageOut,
RustStringRef BufferOut, RustStringRef BufferOut,

View file

@ -1,5 +1,7 @@
// build-fail // build-fail
// ignore-emscripten no asm! support // ignore-emscripten no asm! support
// The error message differs slightly between LLVM versions
// min-llvm-version: 13.0
// Regression test for #69092 // Regression test for #69092
#![feature(llvm_asm)] #![feature(llvm_asm)]
@ -7,5 +9,5 @@
fn main() { fn main() {
unsafe { llvm_asm!(".ascii \"Xen\0\""); } unsafe { llvm_asm!(".ascii \"Xen\0\""); }
//~^ ERROR: expected string in '.ascii' directive //~^ ERROR: expected string
} }

View file

@ -1,5 +1,5 @@
error: expected string in '.ascii' directive error: expected string
--> $DIR/issue-69092.rs:9:14 --> $DIR/issue-69092.rs:11:14
| |
LL | unsafe { llvm_asm!(".ascii \"Xen\0\""); } LL | unsafe { llvm_asm!(".ascii \"Xen\0\""); }
| ^ | ^