Skip to content

Commit 87b89de

Browse files
committed
Auto merge of #154229 - Zoxc:erase-auto-traits, r=<try>
Ensure `ErasedData` only implements appropriate auto traits
2 parents 562dee4 + b0ccfe9 commit 87b89de

4 files changed

Lines changed: 32 additions & 13 deletions

File tree

compiler/rustc_errors/src/decorate_diag.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// This module provides types and traits for buffering lints until later in compilation.
22
use rustc_ast::node_id::NodeId;
33
use rustc_data_structures::fx::FxIndexMap;
4-
use rustc_data_structures::sync::DynSend;
4+
use rustc_data_structures::sync::{DynSend, DynSync};
55
use rustc_error_messages::MultiSpan;
66
use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId};
77

@@ -10,7 +10,14 @@ use crate::{Diag, DiagCtxtHandle, Diagnostic, Level};
1010
/// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its
1111
/// variants requires types we don't have yet. So, handle that case separately.
1212
pub enum DecorateDiagCompat {
13-
Dynamic(Box<dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + 'static>),
13+
Dynamic(
14+
Box<
15+
dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()>
16+
+ DynSync
17+
+ DynSend
18+
+ 'static,
19+
>,
20+
),
1421
Builtin(BuiltinLintDiag),
1522
}
1623

@@ -20,7 +27,7 @@ impl std::fmt::Debug for DecorateDiagCompat {
2027
}
2128
}
2229

23-
impl<D: for<'a> Diagnostic<'a, ()> + DynSend + 'static> From<D> for DecorateDiagCompat {
30+
impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
2431
#[inline]
2532
fn from(d: D) -> Self {
2633
Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level)))

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::panic;
77
use std::path::PathBuf;
88
use std::thread::panicking;
99

10-
use rustc_data_structures::sync::DynSend;
10+
use rustc_data_structures::sync::{DynSend, DynSync};
1111
use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
1212
use rustc_lint_defs::{Applicability, LintExpectationId};
1313
use rustc_macros::{Decodable, Encodable};
@@ -120,7 +120,9 @@ where
120120
}
121121

122122
impl<'a> Diagnostic<'a, ()>
123-
for Box<dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSend + 'static>
123+
for Box<
124+
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static,
125+
>
124126
{
125127
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
126128
self(dcx, level)

compiler/rustc_middle/src/query/erase.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
88
use std::ffi::OsStr;
99
use std::intrinsics::transmute_unchecked;
10+
use std::marker::PhantomData;
1011
use std::mem::MaybeUninit;
1112

1213
use rustc_ast::tokenstream::TokenStream;
14+
use rustc_data_structures::sync::{DynSend, DynSync};
1315
use rustc_span::{ErrorGuaranteed, Spanned};
1416

1517
use crate::mir::interpret::EvalToValTreeResult;
@@ -18,14 +20,25 @@ use crate::traits::solve;
1820
use crate::ty::{self, Ty, TyCtxt};
1921
use crate::{mir, traits};
2022

23+
unsafe extern "C" {
24+
type Hide;
25+
}
26+
2127
/// Internal implementation detail of [`Erased`].
2228
#[derive(Copy, Clone)]
2329
pub struct ErasedData<Storage: Copy> {
2430
/// We use `MaybeUninit` here to make sure it's legal to store a transmuted
2531
/// value that isn't actually of type `Storage`.
2632
data: MaybeUninit<Storage>,
33+
/// `Storage` is an erased type, so we use an external type here to opt-out of auto traits
34+
/// as those would be incorrect.
35+
hide: PhantomData<Hide>,
2736
}
2837

38+
// SAFETY: The bounds on `erase_val` ensure the types we erase are `DynSync` and `DynSend`
39+
unsafe impl<Storage: Copy> DynSync for ErasedData<Storage> {}
40+
unsafe impl<Storage: Copy> DynSend for ErasedData<Storage> {}
41+
2942
/// Trait for types that can be erased into [`Erased<Self>`].
3043
///
3144
/// Erasing and unerasing values is performed by [`erase_val`] and [`restore_val`].
@@ -55,13 +68,9 @@ pub type Erased<T: Erasable> = ErasedData<impl Copy>;
5568
///
5669
/// `Erased<T>` and `Erased<U>` are type-checked as distinct types, but codegen
5770
/// can see whether they actually have the same storage type.
58-
///
59-
/// FIXME: This might have soundness issues with erasable types that don't
60-
/// implement the same auto-traits as `[u8; _]`; see
61-
/// <https://github.com/rust-lang/rust/pull/151715#discussion_r2740113250>
6271
#[inline(always)]
6372
#[define_opaque(Erased)]
64-
pub fn erase_val<T: Erasable>(value: T) -> Erased<T> {
73+
pub fn erase_val<T: Erasable + DynSend + DynSync>(value: T) -> Erased<T> {
6574
// Ensure the sizes match
6675
const {
6776
if size_of::<T>() != size_of::<T::Storage>() {
@@ -79,6 +88,7 @@ pub fn erase_val<T: Erasable>(value: T) -> Erased<T> {
7988
//
8089
// SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes.
8190
data: unsafe { transmute_unchecked::<T, MaybeUninit<T::Storage>>(value) },
91+
hide: PhantomData,
8292
}
8393
}
8494

@@ -89,7 +99,7 @@ pub fn erase_val<T: Erasable>(value: T) -> Erased<T> {
8999
#[inline(always)]
90100
#[define_opaque(Erased)]
91101
pub fn restore_val<T: Erasable>(erased_value: Erased<T>) -> T {
92-
let ErasedData { data }: ErasedData<<T as Erasable>::Storage> = erased_value;
102+
let ErasedData { data, .. }: ErasedData<<T as Erasable>::Storage> = erased_value;
93103
// See comment in `erase_val` for why we use `transmute_unchecked`.
94104
//
95105
// SAFETY: Due to the use of impl Trait in `Erased` the only way to safely create an instance

compiler/rustc_session/src/parse.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::sync::Arc;
77
use rustc_ast::attr::AttrIdGenerator;
88
use rustc_ast::node_id::NodeId;
99
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
10-
use rustc_data_structures::sync::{AppendOnlyVec, DynSend, Lock};
10+
use rustc_data_structures::sync::{AppendOnlyVec, DynSend, DynSync, Lock};
1111
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
1212
use rustc_errors::emitter::{EmitterWithNote, stderr_destination};
1313
use rustc_errors::{
@@ -332,7 +332,7 @@ impl ParseSess {
332332
}
333333

334334
pub fn dyn_buffer_lint<
335-
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + 'static,
335+
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSync + DynSend + 'static,
336336
>(
337337
&self,
338338
lint: &'static Lint,

0 commit comments

Comments
 (0)