Skip to content

Rollup of 4 pull requests #114893

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
49 changes: 31 additions & 18 deletions compiler/rustc_lint/src/reference_casting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>)

fn from_casts<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
// <expr> as *mut ...
let e = if let ExprKind::Cast(e, t) = e.kind
let mut e = if let ExprKind::Cast(e, t) = e.kind
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
e
// <expr>.cast_mut()
Expand All @@ -112,23 +112,36 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>)
return None;
};

let e = e.peel_blocks();

// <expr> as *const ...
let e = if let ExprKind::Cast(e, t) = e.kind
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
e
// ptr::from_ref(<expr>)
} else if let ExprKind::Call(path, [arg]) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
arg
} else {
return None;
};

Some(e)
let mut had_at_least_one_cast = false;
loop {
e = e.peel_blocks();
// <expr> as *mut/const ... or <expr> as <uint>
e = if let ExprKind::Cast(expr, t) = e.kind
&& matches!(cx.typeck_results().node_type(t.hir_id).kind(), ty::RawPtr(_) | ty::Uint(_)) {
had_at_least_one_cast = true;
expr
// <expr>.cast(), <expr>.cast_mut() or <expr>.cast_const()
} else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& matches!(
cx.tcx.get_diagnostic_name(def_id),
Some(sym::ptr_cast | sym::const_ptr_cast | sym::ptr_cast_mut | sym::ptr_cast_const)
)
{
had_at_least_one_cast = true;
expr
// ptr::from_ref(<expr>)
} else if let ExprKind::Call(path, [arg]) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
return Some(arg);
} else if had_at_least_one_cast {
return Some(e);
} else {
return None;
};
}
}

fn from_transmute<'tcx>(
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ symbols! {
const_panic_fmt,
const_param_ty,
const_precise_live_drops,
const_ptr_cast,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,
const_refs_to_cell,
Expand Down Expand Up @@ -1160,6 +1161,7 @@ symbols! {
profiler_runtime,
ptr,
ptr_cast,
ptr_cast_const,
ptr_cast_mut,
ptr_const_is_null,
ptr_from_mut,
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl<T: ?Sized> *const T {
/// Casts to a pointer of another type.
#[stable(feature = "ptr_cast", since = "1.38.0")]
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
#[rustc_diagnostic_item = "const_ptr_cast"]
#[inline(always)]
pub const fn cast<U>(self) -> *const U {
self as _
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ impl<T: ?Sized> *mut T {
/// [`cast_mut`]: #method.cast_mut
#[stable(feature = "ptr_const_cast", since = "1.65.0")]
#[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
#[rustc_diagnostic_item = "ptr_cast_const"]
#[inline(always)]
pub const fn cast_const(self) -> *const T {
self as _
Expand Down
38 changes: 25 additions & 13 deletions library/proc_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,21 +916,34 @@ impl !Send for Punct {}
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl !Sync for Punct {}

/// Describes whether a `Punct` is followed immediately by another `Punct` ([`Spacing::Joint`]) or
/// by a different token or whitespace ([`Spacing::Alone`]).
/// Indicates whether a `Punct` token can join with the following token
/// to form a multi-character operator.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub enum Spacing {
/// A `Punct` is not immediately followed by another `Punct`.
/// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
Alone,
/// A `Punct` is immediately followed by another `Punct`.
/// E.g. `+` is `Joint` in `+=` and `++`.
/// A `Punct` token can join with the following token to form a multi-character operator.
///
/// In token streams constructed using proc macro interfaces `Joint` punctuation tokens can be
/// followed by any other tokens. \
/// However, in token streams parsed from source code compiler will only set spacing to `Joint`
/// in the following cases:
/// - A `Punct` is immediately followed by another `Punct` without a whitespace. \
/// E.g. `+` is `Joint` in `+=` and `++`.
/// - A single quote `'` is immediately followed by an identifier without a whitespace. \
/// E.g. `'` is `Joint` in `'lifetime`.
///
/// Additionally, single quote `'` can join with identifiers to form lifetimes: `'ident`.
/// This list may be extended in the future to enable more token combinations.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
Joint,
/// A `Punct` token cannot join with the following token to form a multi-character operator.
///
/// `Alone` punctuation tokens can be followed by any other tokens. \
/// In token streams parsed from source code compiler will set spacing to `Alone` in all cases
/// not covered by the conditions for `Joint` above. \
/// E.g. `+` is `Alone` in `+ =`, `+ident` and `+()`.
/// In particular, token not followed by anything will also be marked as `Alone`.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
Alone,
}

impl Punct {
Expand Down Expand Up @@ -962,10 +975,9 @@ impl Punct {
self.0.ch as char
}

/// Returns the spacing of this punctuation character, indicating whether it's immediately
/// followed by another `Punct` in the token stream, so they can potentially be combined into
/// a multi-character operator (`Joint`), or it's followed by some other token or whitespace
/// (`Alone`) so the operator has certainly ended.
/// Returns the spacing of this punctuation character, indicating whether it can be potentially
/// combined into a multi-character operator with the following token (`Joint`), or the operator
/// has certainly ended (`Alone`).
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
pub fn spacing(&self) -> Spacing {
if self.0.joint { Spacing::Joint } else { Spacing::Alone }
Expand Down
3 changes: 3 additions & 0 deletions src/doc/rustc/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ title = "The rustc book"
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}"

[output.html.search]
use-boolean-and = true

[output.html.playground]
runnable = false
2 changes: 1 addition & 1 deletion src/librustdoc/html/templates/STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Askama templates support quite sophisticated control flow. To keep our templates
simple and understandable, we use only a subset: `if` and `for`. In particular
we avoid [assignments in the template logic][assignments] and [Askama
macros][macros]. This also may make things easier if we switch to a different
Jinja-style template system, like Askama, in the future.
Jinja-style template system in the future.

[assignments]: https://djc.github.io/askama/template_syntax.html#assignments
[macros]: https://djc.github.io/askama/template_syntax.html#macros
29 changes: 29 additions & 0 deletions tests/ui/lint/reference_casting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ extern "C" {
fn int_ffi(c: *mut i32);
}

fn static_u8() -> &'static u8 {
&8
}

unsafe fn ref_to_mut() {
let num = &3i32;

Expand All @@ -24,12 +28,28 @@ unsafe fn ref_to_mut() {
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
let _num = &mut *(num as *const i32).cast::<i32>().cast_mut();
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
let _num = &mut *(num as *const i32).cast::<i32>().cast_mut().cast_const().cast_mut();
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32);
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
let _num = &mut *std::mem::transmute::<_, *mut i32>(num);
//~^ ERROR casting `&T` to `&mut T` is undefined behavior

let deferred = num as *const i32 as *mut i32;
let _num = &mut *deferred;
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
let deferred = (std::ptr::from_ref(num) as *const i32 as *const i32).cast_mut() as *mut i32;
let _num = &mut *deferred;
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
let _num = &mut *(num as *const _ as usize as *mut i32);
//~^ ERROR casting `&T` to `&mut T` is undefined behavior

unsafe fn generic_ref_cast_mut<T>(this: &T) -> &mut T {
&mut *((this as *const _) as *mut _)
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
}
}

unsafe fn assign_to_ref() {
Expand All @@ -55,6 +75,15 @@ unsafe fn assign_to_ref() {
let value = num as *const i32 as *mut i32;
*value = 1;
//~^ ERROR assigning to `&T` is undefined behavior
*(num as *const i32).cast::<i32>().cast_mut() = 2;
//~^ ERROR assigning to `&T` is undefined behavior
*(num as *const _ as usize as *mut i32) = 2;
//~^ ERROR assigning to `&T` is undefined behavior

unsafe fn generic_assign_to_ref<T>(this: &T, a: T) {
*(this as *const _ as *mut _) = a;
//~^ ERROR assigning to `&T` is undefined behavior
}
}

unsafe fn no_warn() {
Expand Down
Loading