-
Notifications
You must be signed in to change notification settings - Fork 295
Expand file tree
/
Copy pathdiagnostics.rs
More file actions
205 lines (176 loc) · 5.91 KB
/
diagnostics.rs
File metadata and controls
205 lines (176 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
use colored::Colorize;
use failure::{err_msg, Backtrace, Context, Error, Fail};
use fern::colors::ColoredLevelConfig;
use log::{Level, SetLoggerError};
use std::collections::HashSet;
use std::fmt::{self, Display};
use std::io;
use std::str::FromStr;
use std::sync::Arc;
use strum_macros::{Display, EnumString};
use crate::c_ast::{ClangAstParseErrorKind, DisplaySrcSpan};
use c2rust_ast_exporter::get_clang_major_version;
const DEFAULT_WARNINGS: &[Diagnostic] = &[Diagnostic::ClangAst];
#[derive(PartialEq, Eq, Hash, Debug, Display, EnumString, Clone)]
#[strum(serialize_all = "kebab-case")]
pub enum Diagnostic {
All,
Comments,
ClangAst,
}
macro_rules! diag {
($type:path, $($arg:tt)*) => (log::warn!(target: &$type.to_string(), $($arg)*))
}
pub(crate) use diag;
pub fn init(mut enabled_warnings: HashSet<Diagnostic>, log_level: log::LevelFilter) {
enabled_warnings.extend(DEFAULT_WARNINGS.iter().cloned());
let colors = ColoredLevelConfig::new();
let (max_level, logger) = fern::Dispatch::new()
.format(move |out, message, record| {
let level_label = match record.level() {
Level::Error => "error",
Level::Warn => "warning",
Level::Info => "info",
Level::Debug => "debug",
Level::Trace => "trace",
};
let target = record.target();
let warn_flag = Diagnostic::from_str(target)
.map(|_| format!(" [-W{}]", target))
.unwrap_or_default();
out.finish(format_args!(
"\x1B[{}m{}:\x1B[0m {}{}",
colors.get_color(&record.level()).to_fg_str(),
level_label,
message,
warn_flag,
))
})
.level(log_level)
.filter(move |metadata| {
if enabled_warnings.contains(&Diagnostic::All) {
return true;
}
Diagnostic::from_str(metadata.target())
.map(|d| enabled_warnings.contains(&d))
.unwrap_or(true)
})
.chain(io::stderr())
.into_log();
// Ignore the [`SetLoggerError`] b/c we just want to make sure it's set at least once.
let _: Result<(), SetLoggerError> = log_reroute::init();
log_reroute::reroute_boxed(logger);
log::set_max_level(max_level);
}
#[derive(Debug, Clone)]
pub struct TranslationError {
loc: Vec<DisplaySrcSpan>,
inner: Arc<Context<TranslationErrorKind>>,
}
pub type TranslationResult<T> = Result<T, TranslationError>;
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum TranslationErrorKind {
Generic,
// Not enough simd intrinsics are available in LLVM < 7
OldLLVMSimd,
// We are waiting for va_copy support to land in rustc
VaCopyNotImplemented,
// Clang AST exported by AST-exporter was not valid
InvalidClangAst(ClangAstParseErrorKind),
}
/// Constructs a `TranslationError` using the standard string interpolation syntax.
#[macro_export]
macro_rules! format_translation_err {
($loc:expr, $($arg:tt)*) => {
TranslationError::new(
$loc,
failure::err_msg(format!($($arg)*))
.context(TranslationErrorKind::Generic),
)
}
}
impl Display for TranslationErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::TranslationErrorKind::*;
match self {
Generic => {}
OldLLVMSimd => {
if let Some(version) = get_clang_major_version() {
if version < 7 {
return write!(f, "SIMD intrinsics require LLVM 7 or newer. Please build C2Rust against a newer LLVM version.");
}
}
}
VaCopyNotImplemented => {
return write!(f, "Rust does not yet support a C-compatible va_copy which is required to translate this function. See https://github.com/rust-lang/rust/pull/59625");
}
InvalidClangAst(_) => {
return write!(f, "Exported Clang AST was invalid. Check warnings above for unimplemented features.");
}
}
Ok(())
}
}
impl Fail for TranslationError {
fn cause(&self) -> Option<&dyn Fail> {
self.inner.cause()
}
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl Display for TranslationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(cause) = self.cause() {
writeln!(f, "{}", cause)?;
}
match self.inner.get_context() {
TranslationErrorKind::Generic => {}
ref kind => writeln!(f, "{}", kind)?,
}
for loc in &self.loc {
writeln!(f, "{} {}", "-->".blue(), loc)?;
}
Ok(())
}
}
impl TranslationError {
pub fn kind(&self) -> TranslationErrorKind {
self.inner.get_context().clone()
}
pub fn new(loc: Option<DisplaySrcSpan>, inner: Context<TranslationErrorKind>) -> Self {
Self::from(inner).add_loc(loc)
}
pub fn generic(msg: &'static str) -> Self {
msg.into()
}
pub fn add_loc(mut self, loc: Option<DisplaySrcSpan>) -> Self {
if let Some(loc) = loc {
self.loc.push(loc);
}
self
}
}
impl From<&'static str> for TranslationError {
fn from(msg: &'static str) -> Self {
err_msg(msg).context(TranslationErrorKind::Generic).into()
}
}
impl From<Error> for TranslationError {
fn from(e: Error) -> Self {
e.context(TranslationErrorKind::Generic).into()
}
}
impl From<TranslationErrorKind> for TranslationError {
fn from(kind: TranslationErrorKind) -> Self {
Context::new(kind).into()
}
}
impl From<Context<TranslationErrorKind>> for TranslationError {
fn from(ctx: Context<TranslationErrorKind>) -> Self {
Self {
loc: Vec::new(),
inner: Arc::new(ctx),
}
}
}