Skip to content

Commit

Permalink
Auto merge of #103398 - Dylan-DPC:rollup-cj6w00o, r=Dylan-DPC
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Oct 22, 2022
2 parents f8c86c8 + b453694 commit 289b2b8
Show file tree
Hide file tree
Showing 17 changed files with 153 additions and 67 deletions.
78 changes: 40 additions & 38 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>),
)
}
}
Expand Down
31 changes: 30 additions & 1 deletion library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>),
)
}
}
Expand Down
6 changes: 5 additions & 1 deletion library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 9 additions & 2 deletions library/std/src/sys/windows/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
}
44 changes: 30 additions & 14 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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| &param.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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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>&lt;Item = <a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>&gt;</h4>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h4 class="code-header">type <a href="#associatedtype.Out2" class="associatedtype">Out2</a>&lt;T&gt;: <a class="trait" href="../assoc_item_trait_bounds/trait.Support.html" title="trait assoc_item_trait_bounds::Support">Support</a>&lt;Item = T&gt;</h4>
Original file line number Diff line number Diff line change
@@ -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 = ()>'
Expand All @@ -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"]' \
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/parser/semi-after-closure-in-macro.rs
Original file line number Diff line number Diff line change
@@ -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!(( ||() ; ));
}

0 comments on commit 289b2b8

Please sign in to comment.