Skip to content

Commit 0d74752

Browse files
committed
Safe Transmute: Pass ErrorGuaranteed up to error reporting
This patch updates the `Answer` enum used by Safe Transmute to have a variant for errors, and includes the `ErrorGuaranteed` type so that we know that an error was already emitted. Before this change, we would return `Answer::Yes` for failures, which gives the same end-result, but is confusing because `Answer::Yes` is supposed to mean that safe transmutation is possible. Now, it's clear when we have an error, and we can decide what to do with it during error reporting. Also, we now know for sure that an error was emitted for `LayoutError` (previously, we just assumed without confirming).
1 parent 0fd50f3 commit 0d74752

File tree

7 files changed

+43
-26
lines changed

7 files changed

+43
-26
lines changed

compiler/rustc_middle/src/ty/context/tls.rs

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::dep_graph::TaskDepsRef;
44
use crate::ty::query;
55
use rustc_data_structures::sync::{self, Lock};
66
use rustc_errors::Diagnostic;
7+
use rustc_errors::ErrorGuaranteed;
78
#[cfg(not(parallel_compiler))]
89
use std::cell::Cell;
910
use std::mem;
@@ -153,3 +154,11 @@ where
153154
{
154155
with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
155156
}
157+
158+
pub fn expect_compilation_to_fail() -> ErrorGuaranteed {
159+
if let Some(guar) = with(|tcx| tcx.sess.is_compilation_going_to_fail()) {
160+
guar
161+
} else {
162+
bug!("expect tcx.sess.is_compilation_going_to_fail() to return `Some`");
163+
}
164+
}

compiler/rustc_middle/src/ty/visit.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
5959
self.has_type_flags(TypeFlags::HAS_ERROR)
6060
}
6161
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
62-
if self.references_error() {
63-
if let Some(reported) = ty::tls::with(|tcx| tcx.sess.is_compilation_going_to_fail()) {
64-
Err(reported)
65-
} else {
66-
bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
67-
}
68-
} else {
69-
Ok(())
70-
}
62+
if self.references_error() { Err(ty::tls::expect_compilation_to_fail()) } else { Ok(()) }
7163
}
7264
fn has_non_region_param(&self) -> bool {
7365
self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM)

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
672672
rustc_transmute::Answer::No(_)
673673
| rustc_transmute::Answer::IfTransmutable { .. }
674674
| rustc_transmute::Answer::IfAll(_)
675-
| rustc_transmute::Answer::IfAny(_) => Err(NoSolution),
675+
| rustc_transmute::Answer::IfAny(_)
676+
// FIXME(bryangarza): Pass the `ErrorGuaranteed` along instead of losing it?
677+
| rustc_transmute::Answer::Err(_) => Err(NoSolution),
676678
}
677679
}
678680
}

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -741,11 +741,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
741741
== self.tcx.lang_items().transmute_trait()
742742
{
743743
// Recompute the safe transmute reason and use that for the error reporting
744-
self.get_safe_transmute_error_and_reason(
744+
match self.get_safe_transmute_error_and_reason(
745745
obligation.clone(),
746746
trait_ref,
747747
span,
748-
)
748+
) {
749+
SafeTransmuteError::ShouldReport { err_msg, explanation } => {
750+
(err_msg, Some(explanation))
751+
}
752+
// An error is guaranteed to already have been reported at this point, no need to continue
753+
SafeTransmuteError::ErrorGuaranteed(_) => return,
754+
}
749755
} else {
750756
(err_msg, None)
751757
};
@@ -1631,7 +1637,7 @@ trait InferCtxtPrivExt<'tcx> {
16311637
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
16321638
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
16331639
span: Span,
1634-
) -> (String, Option<String>);
1640+
) -> SafeTransmuteError;
16351641
}
16361642

16371643
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
@@ -2922,7 +2928,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
29222928
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
29232929
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
29242930
span: Span,
2925-
) -> (String, Option<String>) {
2931+
) -> SafeTransmuteError {
29262932
// Erase regions because layout code doesn't particularly care about regions.
29272933
let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
29282934

@@ -2944,10 +2950,10 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
29442950
rustc_transmute::Answer::No(reason) => {
29452951
let dst = trait_ref.substs.type_at(0);
29462952
let src = trait_ref.substs.type_at(1);
2947-
let custom_err_msg = format!(
2953+
let err_msg = format!(
29482954
"`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
29492955
);
2950-
let reason_msg = match reason {
2956+
let explanation = match reason {
29512957
rustc_transmute::Reason::SrcIsUnspecified => {
29522958
format!("`{src}` does not have a well-specified layout")
29532959
}
@@ -2968,13 +2974,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
29682974
format!("The size of `{src}` is smaller than the size of `{dst}`")
29692975
}
29702976
};
2971-
(custom_err_msg, Some(reason_msg))
2977+
SafeTransmuteError::ShouldReport { err_msg, explanation }
29722978
}
29732979
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
29742980
rustc_transmute::Answer::Yes => span_bug!(
29752981
span,
29762982
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
29772983
),
2984+
rustc_transmute::Answer::Err(guar) => SafeTransmuteError::ErrorGuaranteed(guar),
29782985
_ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"),
29792986
}
29802987
}
@@ -3103,3 +3110,8 @@ pub enum DefIdOrName {
31033110
DefId(DefId),
31043111
Name(&'static str),
31053112
}
3113+
3114+
enum SafeTransmuteError {
3115+
ShouldReport { err_msg: String, explanation: String },
3116+
ErrorGuaranteed(ErrorGuaranteed),
3117+
}

compiler/rustc_transmute/src/layout/tree.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,15 @@ pub(crate) mod rustc {
187187
pub(crate) enum Err {
188188
/// The layout of the type is unspecified.
189189
Unspecified,
190-
/// This error will be surfaced elsewhere by rustc, so don't surface it.
191-
Unknown,
190+
Unknown(ErrorGuaranteed),
192191
TypeError(ErrorGuaranteed),
193192
}
194193

195194
impl<'tcx> From<LayoutError<'tcx>> for Err {
196195
fn from(err: LayoutError<'tcx>) -> Self {
196+
let guar = rustc_middle::ty::tls::expect_compilation_to_fail();
197197
match err {
198-
LayoutError::Unknown(..) => Self::Unknown,
198+
LayoutError::Unknown(..) => Self::Unknown(guar),
199199
err => unimplemented!("{:?}", err),
200200
}
201201
}

compiler/rustc_transmute/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ where
3939

4040
/// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
4141
IfAny(Vec<Answer<R>>),
42+
43+
/// Encountered an error during safe transmute computation
44+
Err(ErrorGuaranteed),
4245
}
4346

4447
/// Answers: Why wasn't the source type transmutable into the destination type?
@@ -162,3 +165,4 @@ mod rustc {
162165

163166
#[cfg(feature = "rustc")]
164167
pub use rustc::*;
168+
use rustc_span::ErrorGuaranteed;

compiler/rustc_transmute/src/maybe_transmutable/mod.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,10 @@ mod rustc {
7575
let dst = Tree::from_ty(dst, context);
7676

7777
match (src, dst) {
78-
// Answer `Yes` here, because 'unknown layout' and type errors will already
79-
// be reported by rustc. No need to spam the user with more errors.
80-
(Err(Err::TypeError(_)), _) => Err(Answer::Yes),
81-
(_, Err(Err::TypeError(_))) => Err(Answer::Yes),
82-
(Err(Err::Unknown), _) => Err(Answer::Yes),
83-
(_, Err(Err::Unknown)) => Err(Answer::Yes),
78+
(Err(Err::TypeError(guar)), _) => Err(Answer::Err(guar)),
79+
(_, Err(Err::TypeError(guar))) => Err(Answer::Err(guar)),
80+
(Err(Err::Unknown(guar)), _) => Err(Answer::Err(guar)),
81+
(_, Err(Err::Unknown(guar))) => Err(Answer::Err(guar)),
8482
(Err(Err::Unspecified), _) => Err(Answer::No(Reason::SrcIsUnspecified)),
8583
(_, Err(Err::Unspecified)) => Err(Answer::No(Reason::DstIsUnspecified)),
8684
(Ok(src), Ok(dst)) => Ok((src, dst)),

0 commit comments

Comments
 (0)