2023-10-13 22:40:35 -07:00
|
|
|
//! When things go wrong, we need some error handling.
|
|
|
|
|
//! There are a few different types of errors in StableMIR:
|
|
|
|
|
//!
|
|
|
|
|
//! - [CompilerError]: This represents errors that can be raised when invoking the compiler.
|
|
|
|
|
//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
|
|
|
|
|
|
|
|
|
|
use std::fmt::{Debug, Display, Formatter};
|
2024-02-29 15:23:44 -08:00
|
|
|
use std::{fmt, io};
|
2023-10-13 22:40:35 -07:00
|
|
|
|
2023-11-16 06:24:53 -08:00
|
|
|
macro_rules! error {
|
|
|
|
|
($fmt: literal $(,)?) => { Error(format!($fmt)) };
|
2023-12-06 13:39:55 -08:00
|
|
|
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
|
2024-02-29 15:23:44 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) use error;
|
2023-11-16 06:24:53 -08:00
|
|
|
|
2023-10-13 22:40:35 -07:00
|
|
|
/// An error type used to represent an error that has already been reported by the compiler.
|
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
pub enum CompilerError<T> {
|
Merge `CompilerError::CompilationFailed` and `CompilerError::ICE`.
`CompilerError` has `CompilationFailed` and `ICE` variants, which seems
reasonable at first. But the way it identifies them is flawed:
- If compilation errors out, i.e. `RunCompiler::run` returns an `Err`,
it uses `CompilationFailed`, which is reasonable.
- If compilation panics with `FatalError`, it catches the panic and uses
`ICE`. This is sometimes right, because ICEs do cause `FatalError`
panics, but sometimes wrong, because certain compiler errors also
cause `FatalError` panics. (The compiler/rustdoc/clippy/whatever just
catches the `FatalError` with `catch_with_exit_code` in `main`.)
In other words, certain non-ICE compilation failures get miscategorized
as ICEs. It's not possible to reliably distinguish the two cases, so
this commit merges them. It also renames the combined variant as just
`Failed`, to better match the existing `Interrupted` and `Skipped`
variants.
Here is an example of a non-ICE failure that causes a `FatalError`
panic, from `tests/ui/recursion_limit/issue-105700.rs`:
```
#![recursion_limit="4"]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
//~^ERROR recursion limit reached while expanding
fn main() {{}}
```
2024-02-17 09:13:45 +11:00
|
|
|
/// Compilation failed, either due to normal errors or ICE.
|
|
|
|
|
Failed,
|
2023-10-13 22:40:35 -07:00
|
|
|
/// Compilation was interrupted.
|
|
|
|
|
Interrupted(T),
|
|
|
|
|
/// Compilation skipped. This happens when users invoke rustc to retrieve information such as
|
|
|
|
|
/// --version.
|
|
|
|
|
Skipped,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A generic error to represent an API request that cannot be fulfilled.
|
2023-12-05 12:01:09 -08:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2023-11-16 06:24:53 -08:00
|
|
|
pub struct Error(pub(crate) String);
|
2023-10-13 22:40:35 -07:00
|
|
|
|
|
|
|
|
impl Error {
|
2023-11-16 06:24:53 -08:00
|
|
|
pub fn new(msg: String) -> Self {
|
2023-10-13 22:40:35 -07:00
|
|
|
Self(msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-19 17:06:53 -07:00
|
|
|
impl From<&str> for Error {
|
|
|
|
|
fn from(value: &str) -> Self {
|
|
|
|
|
Self(value.into())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-13 22:40:35 -07:00
|
|
|
impl Display for Error {
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
|
Display::fmt(&self.0, f)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> Display for CompilerError<T>
|
|
|
|
|
where
|
|
|
|
|
T: Display,
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
|
match self {
|
Merge `CompilerError::CompilationFailed` and `CompilerError::ICE`.
`CompilerError` has `CompilationFailed` and `ICE` variants, which seems
reasonable at first. But the way it identifies them is flawed:
- If compilation errors out, i.e. `RunCompiler::run` returns an `Err`,
it uses `CompilationFailed`, which is reasonable.
- If compilation panics with `FatalError`, it catches the panic and uses
`ICE`. This is sometimes right, because ICEs do cause `FatalError`
panics, but sometimes wrong, because certain compiler errors also
cause `FatalError` panics. (The compiler/rustdoc/clippy/whatever just
catches the `FatalError` with `catch_with_exit_code` in `main`.)
In other words, certain non-ICE compilation failures get miscategorized
as ICEs. It's not possible to reliably distinguish the two cases, so
this commit merges them. It also renames the combined variant as just
`Failed`, to better match the existing `Interrupted` and `Skipped`
variants.
Here is an example of a non-ICE failure that causes a `FatalError`
panic, from `tests/ui/recursion_limit/issue-105700.rs`:
```
#![recursion_limit="4"]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
//~^ERROR recursion limit reached while expanding
fn main() {{}}
```
2024-02-17 09:13:45 +11:00
|
|
|
CompilerError::Failed => write!(f, "Compilation Failed"),
|
2023-10-13 22:40:35 -07:00
|
|
|
CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason}"),
|
|
|
|
|
CompilerError::Skipped => write!(f, "Compilation Skipped"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> Debug for CompilerError<T>
|
|
|
|
|
where
|
|
|
|
|
T: Debug,
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
|
match self {
|
Merge `CompilerError::CompilationFailed` and `CompilerError::ICE`.
`CompilerError` has `CompilationFailed` and `ICE` variants, which seems
reasonable at first. But the way it identifies them is flawed:
- If compilation errors out, i.e. `RunCompiler::run` returns an `Err`,
it uses `CompilationFailed`, which is reasonable.
- If compilation panics with `FatalError`, it catches the panic and uses
`ICE`. This is sometimes right, because ICEs do cause `FatalError`
panics, but sometimes wrong, because certain compiler errors also
cause `FatalError` panics. (The compiler/rustdoc/clippy/whatever just
catches the `FatalError` with `catch_with_exit_code` in `main`.)
In other words, certain non-ICE compilation failures get miscategorized
as ICEs. It's not possible to reliably distinguish the two cases, so
this commit merges them. It also renames the combined variant as just
`Failed`, to better match the existing `Interrupted` and `Skipped`
variants.
Here is an example of a non-ICE failure that causes a `FatalError`
panic, from `tests/ui/recursion_limit/issue-105700.rs`:
```
#![recursion_limit="4"]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
#![invalid_attribute]
//~^ERROR recursion limit reached while expanding
fn main() {{}}
```
2024-02-17 09:13:45 +11:00
|
|
|
CompilerError::Failed => write!(f, "Compilation Failed"),
|
2023-10-13 22:40:35 -07:00
|
|
|
CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason:?}"),
|
|
|
|
|
CompilerError::Skipped => write!(f, "Compilation Skipped"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-29 15:23:44 -08:00
|
|
|
impl std::error::Error for Error {}
|
|
|
|
|
|
|
|
|
|
impl<T> std::error::Error for CompilerError<T> where T: Display + Debug {}
|
2023-12-06 13:39:55 -08:00
|
|
|
|
|
|
|
|
impl From<io::Error> for Error {
|
|
|
|
|
fn from(value: io::Error) -> Self {
|
|
|
|
|
Error(value.to_string())
|
|
|
|
|
}
|
|
|
|
|
}
|