mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-17 01:13:11 +00:00
Auto merge of #103398 - Dylan-DPC:rollup-cj6w00o, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #102602 (Slightly tweak comments wrt `lint_overflowing_range_endpoint`) - #103190 (rustdoc: render bounds of cross-crate GAT params) - #103224 (Allow semicolon after closure within parentheses in macros) - #103280 ((#102929) Implement `String::leak` (attempt 2)) - #103329 (Add a forgotten check for NonNull::new_unchecked's precondition) - #103346 (Adjust argument type for mutable with_metadata_of (#75091)) - #103360 (Reduce false positives in msys2 detection) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
289b2b8cf9
@ -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};
|
||||
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.set_arg("ty", ty);
|
||||
cx.struct_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
struct_expr.span,
|
||||
fluent::lint::range_endpoint_out_of_range,
|
||||
|lint| {
|
||||
use ast::{LitIntType, LitKind};
|
||||
|
||||
// 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;
|
||||
lint.set_arg("ty", ty);
|
||||
|
||||
lint
|
||||
},
|
||||
);
|
||||
}
|
||||
overwritten
|
||||
// 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) {
|
||||
|
@ -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
|
||||
|
@ -1386,7 +1386,7 @@ impl<T: ?Sized> Rc<T> {
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|layout| Global.allocate(layout),
|
||||
|mem| mem.with_metadata_of(ptr as *mut RcBox<T>),
|
||||
|mem| mem.with_metadata_of(ptr as *const RcBox<T>),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -1204,7 +1204,7 @@ impl<T: ?Sized> Arc<T> {
|
||||
Self::allocate_for_layout(
|
||||
Layout::for_value(&*ptr),
|
||||
|layout| Global.allocate(layout),
|
||||
|mem| mem.with_metadata_of(ptr as *mut ArcInner<T>),
|
||||
|mem| mem.with_metadata_of(ptr as *const ArcInner<T>),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -80,10 +80,14 @@ impl<T: ?Sized> *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<U>(self, mut val: *mut U) -> *mut U
|
||||
pub fn with_metadata_of<U>(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
|
||||
|
@ -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<T: ?Sized> NonNull<T> {
|
||||
#[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.
|
||||
|
@ -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,
|
||||
|
@ -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::FILE_NAME_INFO>() + c::MAX_PATH * size_of::<c::WCHAR>();
|
||||
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::<c::DWORD>() as isize).cast::<u16>();
|
||||
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
|
||||
}
|
||||
|
@ -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<T: Copy> 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(
|
||||
|
@ -0,0 +1 @@
|
||||
<h4 class="code-header">type <a href="#associatedtype.Out0" class="associatedtype">Out0</a>: <a class="trait" href="../assoc_item_trait_bounds/trait.Support.html" title="trait assoc_item_trait_bounds::Support">Support</a><Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>></h4>
|
@ -0,0 +1 @@
|
||||
<h4 class="code-header">type <a href="#associatedtype.Out2" class="associatedtype">Out2</a><T>: <a class="trait" href="../assoc_item_trait_bounds/trait.Support.html" title="trait assoc_item_trait_bounds::Support">Support</a><Item = T></h4>
|
@ -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<Item = ()>'
|
||||
@ -24,11 +21,15 @@ extern crate assoc_item_trait_bounds_with_bindings as aux;
|
||||
// @has - '//*[@id="associatedtype.Out11"]' "type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>"
|
||||
// @has - '//*[@id="associatedtype.Out12"]' "type Out12: for<'w> Helper<B<'w> = 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<P: Copy + Eq, Q: ?Sized>"
|
||||
//
|
||||
// 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"]' \
|
@ -1 +0,0 @@
|
||||
<h4 class="code-header">type <a href="#associatedtype.Out0" class="associatedtype">Out0</a>: <a class="trait" href="../assoc_item_trait_bounds_with_bindings/trait.Support.html" title="trait assoc_item_trait_bounds_with_bindings::Support">Support</a><Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>></h4>
|
@ -15,6 +15,7 @@ pub trait Main {
|
||||
type Out11: for<'r, 's> Helper<A<'s> = &'s (), B<'r> = ()>;
|
||||
type Out12: for<'w> Helper<B<'w> = std::borrow::Cow<'w, str>, A<'w> = bool>;
|
||||
type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>;
|
||||
type Out14<P: Copy + Eq, Q: ?Sized>;
|
||||
|
||||
fn make<F>(_: F, _: impl FnMut(&str) -> bool)
|
||||
where
|
14
src/test/ui/parser/semi-after-closure-in-macro.rs
Normal file
14
src/test/ui/parser/semi-after-closure-in-macro.rs
Normal file
@ -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!(( ||() ; ));
|
||||
}
|
Loading…
Reference in New Issue
Block a user