Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions compiler/rustc_errors/src/decorate_diag.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// This module provides types and traits for buffering lints until later in compilation.
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::DynSend;
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_error_messages::MultiSpan;
use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId};

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

Expand All @@ -20,7 +27,7 @@ impl std::fmt::Debug for DecorateDiagCompat {
}
}

impl<D: for<'a> Diagnostic<'a, ()> + DynSend + 'static> From<D> for DecorateDiagCompat {
impl<D: for<'a> Diagnostic<'a, ()> + DynSync + DynSend + 'static> From<D> for DecorateDiagCompat {
#[inline]
fn from(d: D) -> Self {
Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level)))
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::panic;
use std::path::PathBuf;
use std::thread::panicking;

use rustc_data_structures::sync::DynSend;
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_macros::{Decodable, Encodable};
Expand Down Expand Up @@ -120,7 +120,9 @@ where
}

impl<'a> Diagnostic<'a, ()>
for Box<dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSend + 'static>
for Box<
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static,
>
{
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
self(dcx, level)
Expand Down
24 changes: 18 additions & 6 deletions compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

use std::ffi::OsStr;
use std::intrinsics::transmute_unchecked;
use std::marker::PhantomData;
use std::mem::MaybeUninit;

use rustc_ast::tokenstream::TokenStream;
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_span::{ErrorGuaranteed, Spanned};

use crate::mir::interpret::EvalToValTreeResult;
Expand All @@ -18,14 +20,25 @@ use crate::traits::solve;
use crate::ty::{self, Ty, TyCtxt};
use crate::{mir, traits};

unsafe extern "C" {
type NoAutoTraits;
}

/// Internal implementation detail of [`Erased`].
#[derive(Copy, Clone)]
pub struct ErasedData<Storage: Copy> {
/// We use `MaybeUninit` here to make sure it's legal to store a transmuted
/// value that isn't actually of type `Storage`.
data: MaybeUninit<Storage>,
/// `Storage` is an erased type, so we use an external type here to opt-out of auto traits
/// as those would be incorrect.
no_auto_traits: PhantomData<NoAutoTraits>,
}

// SAFETY: The bounds on `erase_val` ensure the types we erase are `DynSync` and `DynSend`
unsafe impl<Storage: Copy> DynSync for ErasedData<Storage> {}
unsafe impl<Storage: Copy> DynSend for ErasedData<Storage> {}
Comment on lines +38 to +40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storage should be DynSync and DynSend too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't store Storage or create any instance of that type.


/// Trait for types that can be erased into [`Erased<Self>`].
///
/// Erasing and unerasing values is performed by [`erase_val`] and [`restore_val`].
Expand Down Expand Up @@ -55,13 +68,11 @@ pub type Erased<T: Erasable> = ErasedData<impl Copy>;
///
/// `Erased<T>` and `Erased<U>` are type-checked as distinct types, but codegen
/// can see whether they actually have the same storage type.
///
/// FIXME: This might have soundness issues with erasable types that don't
/// implement the same auto-traits as `[u8; _]`; see
/// <https://github.com/rust-lang/rust/pull/151715#discussion_r2740113250>
#[inline(always)]
#[define_opaque(Erased)]
pub fn erase_val<T: Erasable>(value: T) -> Erased<T> {
// The `DynSend` and `DynSync` bounds on `T` are used to
// justify the safety of the implementations of these traits for `ErasedData`.
pub fn erase_val<T: Erasable + DynSend + DynSync>(value: T) -> Erased<T> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment here referring back to the unsafe DynSend/DynSync impls for ErasedData.

// Ensure the sizes match
const {
if size_of::<T>() != size_of::<T::Storage>() {
Expand All @@ -79,6 +90,7 @@ pub fn erase_val<T: Erasable>(value: T) -> Erased<T> {
//
// SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes.
data: unsafe { transmute_unchecked::<T, MaybeUninit<T::Storage>>(value) },
no_auto_traits: PhantomData,
}
}

Expand All @@ -89,7 +101,7 @@ pub fn erase_val<T: Erasable>(value: T) -> Erased<T> {
#[inline(always)]
#[define_opaque(Erased)]
pub fn restore_val<T: Erasable>(erased_value: Erased<T>) -> T {
let ErasedData { data }: ErasedData<<T as Erasable>::Storage> = erased_value;
let ErasedData { data, .. }: ErasedData<<T as Erasable>::Storage> = erased_value;
// See comment in `erase_val` for why we use `transmute_unchecked`.
//
// SAFETY: Due to the use of impl Trait in `Erased` the only way to safely create an instance
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_session/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::sync::Arc;
use rustc_ast::attr::AttrIdGenerator;
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::sync::{AppendOnlyVec, DynSend, Lock};
use rustc_data_structures::sync::{AppendOnlyVec, DynSend, DynSync, Lock};
use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
use rustc_errors::emitter::{EmitterWithNote, stderr_destination};
use rustc_errors::{
Expand Down Expand Up @@ -332,7 +332,7 @@ impl ParseSess {
}

pub fn dyn_buffer_lint<
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + 'static,
F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSync + DynSend + 'static,
>(
&self,
lint: &'static Lint,
Expand Down
Loading