diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index b6009bd800a5f..3cdca2178657d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -116,8 +116,8 @@ impl TypeLimits { } } -/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint. -/// Returns `true` iff the lint was overridden. +/// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`). +/// Returns `true` iff the lint was emitted. fn lint_overflowing_range_endpoint<'tcx>( cx: &LateContext<'tcx>, lit: &hir::Lit, @@ -140,44 +140,46 @@ fn lint_overflowing_range_endpoint<'tcx>( return false; } - let mut overwritten = false; // We can suggest using an inclusive range // (`..=`) instead only if it is the `end` that is // overflowing and only by 1. - if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max - && let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) - { - cx.struct_span_lint( - OVERFLOWING_LITERALS, - struct_expr.span, - fluent::lint::range_endpoint_out_of_range, - |lint| { - use ast::{LitIntType, LitKind}; - - lint.set_arg("ty", ty); - - // We need to preserve the literal's suffix, - // as it may determine typing information. - let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), - LitKind::Int(_, LitIntType::Unsuffixed) => "", - _ => bug!(), - }; - let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); - lint.span_suggestion( - struct_expr.span, - fluent::lint::suggestion, - suggestion, - Applicability::MachineApplicable, - ); - overwritten = true; + if !(eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max) { + return false; + }; + let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) else { return false }; - lint - }, - ); - } - overwritten + cx.struct_span_lint( + OVERFLOWING_LITERALS, + struct_expr.span, + fluent::lint::range_endpoint_out_of_range, + |lint| { + use ast::{LitIntType, LitKind}; + + lint.set_arg("ty", ty); + + // We need to preserve the literal's suffix, + // as it may determine typing information. + let suffix = match lit.node { + LitKind::Int(_, LitIntType::Signed(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsigned(s)) => s.name_str(), + LitKind::Int(_, LitIntType::Unsuffixed) => "", + _ => bug!(), + }; + let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix); + lint.span_suggestion( + struct_expr.span, + fluent::lint::suggestion, + suggestion, + Applicability::MachineApplicable, + ); + + lint + }, + ); + + // We've just emitted a lint, special cased for `(...)..MAX+1` ranges, + // return `true` so the callers don't also emit a lint + true } // For `isize` & `usize`, be conservative with the warnings, so that the @@ -358,7 +360,7 @@ fn lint_int_literal<'tcx>( } if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) { - // The overflowing literal lint was overridden. + // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`. return; } @@ -427,7 +429,7 @@ fn lint_uint_literal<'tcx>( } } if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) { - // The overflowing literal lint was overridden. + // The overflowing literal lint was emited by `lint_overflowing_range_endpoint`. return; } if let Some(repr_str) = get_bin_hex_repr(cx, lit) { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index afa116ce1bccd..5b466cec8e15b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2051,6 +2051,10 @@ impl<'a> Parser<'a> { if self.token.kind == TokenKind::Semi && matches!(self.token_cursor.frame.delim_sp, Some((Delimiter::Parenthesis, _))) + // HACK: This is needed so we can detect whether we're inside a macro, + // where regular assumptions about what tokens can follow other tokens + // don't necessarily apply. + && self.subparser_name.is_none() { // It is likely that the closure body is a block but where the // braces have been removed. We will recover and eat the next diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 6d247681c6661..9c229665c7e91 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1386,7 +1386,7 @@ impl Rc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| mem.with_metadata_of(ptr as *mut RcBox), + |mem| mem.with_metadata_of(ptr as *const RcBox), ) } } diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 983376a282be5..209abfac6bbf9 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -67,7 +67,7 @@ use core::str::Utf8Chunks; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::collections::TryReserveError; -use crate::str::{self, Chars, Utf8Error}; +use crate::str::{self, from_utf8_unchecked_mut, Chars, Utf8Error}; #[cfg(not(no_global_oom_handling))] use crate::str::{from_boxed_utf8_unchecked, FromStr}; use crate::vec::Vec; @@ -1849,6 +1849,35 @@ impl String { let slice = self.vec.into_boxed_slice(); unsafe { from_boxed_utf8_unchecked(slice) } } + + /// Consumes and leaks the `String`, returning a mutable reference to the contents, + /// `&'a mut str`. + /// + /// This is mainly useful for data that lives for the remainder of + /// the program's life. Dropping the returned reference will cause a memory + /// leak. + /// + /// It does not reallocate or shrink the `String`, + /// so the leaked allocation may include unused capacity that is not part + /// of the returned slice. + /// + /// # Examples + /// + /// Simple usage: + /// + /// ``` + /// #![feature(string_leak)] + /// + /// let x = String::from("bucket"); + /// let static_ref: &'static mut str = x.leak(); + /// assert_eq!(static_ref, "bucket"); + /// ``` + #[unstable(feature = "string_leak", issue = "102929")] + #[inline] + pub fn leak(self) -> &'static mut str { + let slice = self.vec.leak(); + unsafe { from_utf8_unchecked_mut(slice) } + } } impl FromUtf8Error { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index df315dad89324..e8d9de4fb3ce5 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1204,7 +1204,7 @@ impl Arc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| mem.with_metadata_of(ptr as *mut ArcInner), + |mem| mem.with_metadata_of(ptr as *const ArcInner), ) } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index bbcc7c699e036..0bb2566fd4c98 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -80,10 +80,14 @@ impl *mut T { #[unstable(feature = "set_ptr_value", issue = "75091")] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] - pub fn with_metadata_of(self, mut val: *mut U) -> *mut U + pub fn with_metadata_of(self, val: *const U) -> *mut U where U: ?Sized, { + // Prepare in the type system that we will replace the pointer value with a mutable + // pointer, taking the mutable provenance from the `self` pointer. + let mut val = val as *mut U; + // Pointer to the pointer value within the value. let target = &mut val as *mut *mut U as *mut *mut u8; // SAFETY: In case of a thin pointer, this operations is identical // to a simple assignment. In case of a fat pointer, with the current diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index f3ef094cbccc5..7264d57ba6aed 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -2,6 +2,7 @@ use crate::cmp::Ordering; use crate::convert::From; use crate::fmt; use crate::hash; +use crate::intrinsics::assert_unsafe_precondition; use crate::marker::Unsize; use crate::mem::{self, MaybeUninit}; use crate::num::NonZeroUsize; @@ -195,7 +196,10 @@ impl NonNull { #[inline] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { // SAFETY: the caller must guarantee that `ptr` is non-null. - unsafe { NonNull { pointer: ptr as _ } } + unsafe { + assert_unsafe_precondition!([T: ?Sized](ptr: *mut T) => !ptr.is_null()); + NonNull { pointer: ptr as _ } + } } /// Creates a new `NonNull` if `ptr` is non-null. diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 917fc8e4995e6..be6fc2ebb7a27 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -129,6 +129,8 @@ pub const FIONBIO: c_ulong = 0x8004667e; pub const MAX_PATH: usize = 260; +pub const FILE_TYPE_PIPE: u32 = 3; + #[repr(C)] #[derive(Copy)] pub struct WIN32_FIND_DATAW { @@ -1114,6 +1116,7 @@ extern "system" { lpFileInformation: LPVOID, dwBufferSize: DWORD, ) -> BOOL; + pub fn GetFileType(hfile: HANDLE) -> DWORD; pub fn SleepConditionVariableSRW( ConditionVariable: PCONDITION_VARIABLE, SRWLock: PSRWLOCK, diff --git a/library/std/src/sys/windows/io.rs b/library/std/src/sys/windows/io.rs index 0879ef199338e..2cc34c986b990 100644 --- a/library/std/src/sys/windows/io.rs +++ b/library/std/src/sys/windows/io.rs @@ -120,6 +120,11 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { } unsafe fn msys_tty_on(handle: c::HANDLE) -> bool { + // Early return if the handle is not a pipe. + if c::GetFileType(handle) != c::FILE_TYPE_PIPE { + return false; + } + const SIZE: usize = size_of::() + c::MAX_PATH * size_of::(); let mut name_info_bytes = Align8([0u8; SIZE]); let res = c::GetFileInformationByHandleEx( @@ -137,11 +142,13 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool { let name_ptr = name_info_bytes.0.as_ptr().offset(size_of::() as isize).cast::(); let s = core::slice::from_raw_parts(name_ptr, name_len); let name = String::from_utf16_lossy(s); + // Get the file name only. + let name = name.rsplit('\\').next().unwrap_or(&name); // This checks whether 'pty' exists in the file name, which indicates that // a pseudo-terminal is attached. To mitigate against false positives // (e.g., an actual file name that contains 'pty'), we also require that - // either the strings 'msys-' or 'cygwin-' are in the file name as well.) - let is_msys = name.contains("msys-") || name.contains("cygwin-"); + // the file name begins with either the strings 'msys-' or 'cygwin-'.) + let is_msys = name.starts_with("msys-") || name.starts_with("cygwin-"); let is_pty = name.contains("-pty"); is_msys && is_pty } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5f674ed7441ba..13d63ffa0ee3c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1201,21 +1201,19 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } if let ty::TraitContainer = assoc_item.container { - // FIXME(fmease): `tcx.explicit_item_bounds` does not contain the bounds of GATs, - // e.g. the bounds `Copy`, `Display` & (implicitly) `Sized` in - // `type Assoc where T: Display`. This also means that we - // later incorrectly render `where T: ?Sized`. - // - // The result of `tcx.explicit_predicates_of` *does* contain them but - // it does not contain the other bounds / predicates we need. - // Either merge those two interned lists somehow or refactor - // `clean_ty_generics` to call `explicit_item_bounds` by itself. let bounds = tcx.explicit_item_bounds(assoc_item.def_id); - let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; - let mut generics = - clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates); - // Filter out the bounds that are (likely?) directly attached to the associated type, - // as opposed to being located in the where clause. + let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; + let predicates = + tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied()); + let mut generics = clean_ty_generics( + cx, + tcx.generics_of(assoc_item.def_id), + ty::GenericPredicates { parent: None, predicates }, + ); + // Move bounds that are (likely) directly attached to the associated type + // from the where clause to the associated type. + // There is no guarantee that this is what the user actually wrote but we have + // no way of knowing. let mut bounds = generics .where_predicates .drain_filter(|pred| match *pred { @@ -1273,6 +1271,24 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } None => bounds.push(GenericBound::maybe_sized(cx)), } + // Move bounds that are (likely) directly attached to the parameters of the + // (generic) associated type from the where clause to the respective parameter. + // There is no guarantee that this is what the user actually wrote but we have + // no way of knowing. + let mut where_predicates = Vec::new(); + for mut pred in generics.where_predicates { + if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred + && let Some(GenericParamDef { + kind: GenericParamDefKind::Type { bounds: param_bounds, .. }, + .. + }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + { + param_bounds.extend(mem::take(bounds)); + } else { + where_predicates.push(pred); + } + } + generics.where_predicates = where_predicates; if tcx.impl_defaultness(assoc_item.def_id).has_value() { AssocTypeItem( diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html new file mode 100644 index 0000000000000..8934bc1ee339c --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html @@ -0,0 +1 @@ +

type Out0: Support<Item = ()>

\ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html new file mode 100644 index 0000000000000..bf330670ed0fa --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html @@ -0,0 +1 @@ +

type Out2<T>: Support<Item = T>

\ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html similarity index 100% rename from src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html rename to src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs similarity index 79% rename from src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs rename to src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs index 00976aa74420f..5f4712aab5b19 100644 --- a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs @@ -1,13 +1,10 @@ // Regression test for issues #77763, #84579 and #102142. #![crate_name = "main"] -// aux-build:assoc_item_trait_bounds_with_bindings.rs +// aux-build:assoc_item_trait_bounds.rs // build-aux-docs // ignore-cross-compile -extern crate assoc_item_trait_bounds_with_bindings as aux; - -// FIXME(fmease): Don't render an incorrect `T: ?Sized` where-clause for parameters -// of GATs like `Main::Out{2,4}`. Add a snapshot test once it's fixed. +extern crate assoc_item_trait_bounds as aux; // @has main/trait.Main.html // @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support' @@ -24,11 +21,15 @@ extern crate assoc_item_trait_bounds_with_bindings as aux; // @has - '//*[@id="associatedtype.Out11"]' "type Out11: for<'r, 's> Helper = &'s (), B<'r> = ()>" // @has - '//*[@id="associatedtype.Out12"]' "type Out12: for<'w> Helper = Cow<'w, str>, A<'w> = bool>" // @has - '//*[@id="associatedtype.Out13"]' "type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>" +// @has - '//*[@id="associatedtype.Out14"]' "type Out14" // -// Snapshots: Check that we do not render any where-clauses for those associated types since all of -// the trait bounds contained within were moved to the bounds of the respective item. +// Snapshots: +// Check that we don't render any where-clauses for the following associated types since +// all corresponding projection equality predicates should have already been re-sugared +// to associated type bindings: // // @snapshot out0 - '//*[@id="associatedtype.Out0"]/*[@class="code-header"]' +// @snapshot out2 - '//*[@id="associatedtype.Out2"]/*[@class="code-header"]' // @snapshot out9 - '//*[@id="associatedtype.Out9"]/*[@class="code-header"]' // // @has - '//*[@id="tymethod.make"]' \ diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html deleted file mode 100644 index 927a1a42a1f78..0000000000000 --- a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html +++ /dev/null @@ -1 +0,0 @@ -

type Out0: Support<Item = ()>

\ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs similarity index 96% rename from src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs rename to src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs index f451b1a0e9920..d326e61daea26 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs @@ -15,6 +15,7 @@ pub trait Main { type Out11: for<'r, 's> Helper = &'s (), B<'r> = ()>; type Out12: for<'w> Helper = std::borrow::Cow<'w, str>, A<'w> = bool>; type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>; + type Out14; fn make(_: F, _: impl FnMut(&str) -> bool) where diff --git a/src/test/ui/parser/semi-after-closure-in-macro.rs b/src/test/ui/parser/semi-after-closure-in-macro.rs new file mode 100644 index 0000000000000..14efb6100b0a5 --- /dev/null +++ b/src/test/ui/parser/semi-after-closure-in-macro.rs @@ -0,0 +1,14 @@ +// check-pass + +// Checks that the fix in #103222 doesn't also disqualify semicolons after +// closures within parentheses *in macros*, where they're totally allowed. + +macro_rules! m { + (($expr:expr ; )) => { + $expr + }; +} + +fn main() { + let x = m!(( ||() ; )); +}