Skip to content

Rollup of 7 pull requests #103398

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

Merged
merged 16 commits into from
Oct 22, 2022
Merged
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
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!(( ||() ; ));
}