Auto merge of #76912 - RalfJung:rollup-q9ur56h, r=RalfJung
Rollup of 14 pull requests Successful merges: - #73963 (deny(unsafe_op_in_unsafe_fn) in libstd/path.rs) - #75099 (lint/ty: move fns to avoid abstraction violation) - #75502 (Use implicit (not explicit) rules for promotability by default in `const fn`) - #75580 (Add test for checking duplicated branch or-patterns) - #76310 (Add `[T; N]: TryFrom<Vec<T>>` (insta-stable)) - #76400 (Clean up vec benches bench_in_place style) - #76434 (do not inline black_box when building for Miri) - #76492 (Add associated constant `BITS` to all integer types) - #76525 (Add as_str() to string::Drain.) - #76636 (assert ScalarMaybeUninit size) - #76749 (give *even better* suggestion when matching a const range) - #76757 (don't convert types to the same type with try_into (clippy::useless_conversion)) - #76796 (Give a better error message when x.py uses the wrong stage for CI) - #76798 (Build fixes for RISC-V 32-bit Linux support) Failed merges: r? `@ghost`
This commit is contained in:
commit
8e9d5db839
46 changed files with 456 additions and 181 deletions
|
@ -14,6 +14,7 @@
|
|||
#![feature(generators)]
|
||||
#![feature(generator_trait)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(int_bits_const)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(nll)]
|
||||
|
|
|
@ -48,7 +48,7 @@ where
|
|||
P: Pointer,
|
||||
T: Tag,
|
||||
{
|
||||
const TAG_BIT_SHIFT: usize = (8 * std::mem::size_of::<usize>()) - T::BITS;
|
||||
const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS;
|
||||
const ASSERTION: () = {
|
||||
assert!(T::BITS <= P::BITS);
|
||||
// Used for the transmute_copy's below
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
//! `late_lint_methods!` invocation in `lib.rs`.
|
||||
|
||||
use crate::{
|
||||
types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
||||
types::{transparent_newtype_field, CItemKind},
|
||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
||||
};
|
||||
use rustc_ast::attr::{self, HasAttrs};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
|
@ -2688,8 +2689,7 @@ impl ClashingExternDeclarations {
|
|||
if is_transparent && !is_non_null {
|
||||
debug_assert!(def.variants.len() == 1);
|
||||
let v = &def.variants[VariantIdx::new(0)];
|
||||
ty = v
|
||||
.transparent_newtype_field(tcx)
|
||||
ty = transparent_newtype_field(tcx, v)
|
||||
.expect(
|
||||
"single-variant transparent structure with zero-sized field",
|
||||
)
|
||||
|
|
|
@ -639,6 +639,26 @@ crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtD
|
|||
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
|
||||
}
|
||||
|
||||
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that
|
||||
/// field.
|
||||
pub fn transparent_newtype_field<'a, 'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
variant: &'a ty::VariantDef,
|
||||
) -> Option<&'a ty::FieldDef> {
|
||||
let param_env = tcx.param_env(variant.def_id);
|
||||
for field in &variant.fields {
|
||||
let field_ty = tcx.type_of(field.did);
|
||||
let is_zst =
|
||||
tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false);
|
||||
|
||||
if !is_zst {
|
||||
return Some(field);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Is type known to be non-null?
|
||||
crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
||||
let tcx = cx.tcx;
|
||||
|
@ -654,7 +674,7 @@ crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: C
|
|||
}
|
||||
|
||||
for variant in &def.variants {
|
||||
if let Some(field) = variant.transparent_newtype_field(tcx) {
|
||||
if let Some(field) = transparent_newtype_field(cx.tcx, variant) {
|
||||
if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
|
||||
return true;
|
||||
}
|
||||
|
@ -675,7 +695,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
|
|||
ty::Adt(field_def, field_substs) => {
|
||||
let inner_field_ty = {
|
||||
let first_non_zst_ty =
|
||||
field_def.variants.iter().filter_map(|v| v.transparent_newtype_field(tcx));
|
||||
field_def.variants.iter().filter_map(|v| transparent_newtype_field(cx.tcx, v));
|
||||
debug_assert_eq!(
|
||||
first_non_zst_ty.clone().count(),
|
||||
1,
|
||||
|
@ -816,7 +836,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
|||
if def.repr.transparent() {
|
||||
// Can assume that only one field is not a ZST, so only check
|
||||
// that field's type for FFI-safety.
|
||||
if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) {
|
||||
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
|
||||
self.check_field_type_for_ffi(cache, field, substs)
|
||||
} else {
|
||||
bug!("malformed transparent type");
|
||||
|
|
|
@ -578,6 +578,9 @@ pub enum ScalarMaybeUninit<Tag = ()> {
|
|||
Uninit,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static_assert_size!(ScalarMaybeUninit, 24);
|
||||
|
||||
impl<Tag> From<Scalar<Tag>> for ScalarMaybeUninit<Tag> {
|
||||
#[inline(always)]
|
||||
fn from(s: Scalar<Tag>) -> Self {
|
||||
|
|
|
@ -1999,7 +1999,7 @@ pub struct VariantDef {
|
|||
flags: VariantFlags,
|
||||
}
|
||||
|
||||
impl<'tcx> VariantDef {
|
||||
impl VariantDef {
|
||||
/// Creates a new `VariantDef`.
|
||||
///
|
||||
/// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef`
|
||||
|
@ -2065,19 +2065,6 @@ impl<'tcx> VariantDef {
|
|||
pub fn is_recovered(&self) -> bool {
|
||||
self.flags.intersects(VariantFlags::IS_RECOVERED)
|
||||
}
|
||||
|
||||
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that
|
||||
/// field.
|
||||
pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> {
|
||||
for field in &self.fields {
|
||||
let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id));
|
||||
if !field_ty.is_zst(tcx, self.def_id) {
|
||||
return Some(field);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||
|
|
|
@ -2322,9 +2322,4 @@ impl<'tcx> TyS<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Is this a zero-sized type?
|
||||
pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool {
|
||||
tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::mem;
|
||||
|
||||
use super::abs_domain::Lift;
|
||||
|
@ -481,12 +480,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
};
|
||||
let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty;
|
||||
let len: u64 = match base_ty.kind() {
|
||||
ty::Array(_, size) => {
|
||||
let length = size.eval_usize(self.builder.tcx, self.builder.param_env);
|
||||
length
|
||||
.try_into()
|
||||
.expect("slice pattern of array with more than u32::MAX elements")
|
||||
}
|
||||
ty::Array(_, size) => size.eval_usize(self.builder.tcx, self.builder.param_env),
|
||||
_ => bug!("from_end: false slice pattern of non-array type"),
|
||||
};
|
||||
for offset in from..to {
|
||||
|
|
|
@ -551,7 +551,7 @@ where
|
|||
let n = base.len(self)?;
|
||||
if n < min_length {
|
||||
// This can only be reached in ConstProp and non-rustc-MIR.
|
||||
throw_ub!(BoundsCheckFailed { len: min_length.into(), index: n });
|
||||
throw_ub!(BoundsCheckFailed { len: min_length, index: n });
|
||||
}
|
||||
|
||||
let index = if from_end {
|
||||
|
@ -565,9 +565,7 @@ where
|
|||
self.mplace_index(base, index)?
|
||||
}
|
||||
|
||||
Subslice { from, to, from_end } => {
|
||||
self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)?
|
||||
}
|
||||
Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -734,7 +734,14 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
) -> Result<(), Unpromotable> {
|
||||
let fn_ty = callee.ty(self.body, self.tcx);
|
||||
|
||||
if !self.explicit && self.const_kind.is_none() {
|
||||
// `const` and `static` use the explicit rules for promotion regardless of the `Candidate`,
|
||||
// meaning calls to `const fn` can be promoted.
|
||||
let context_uses_explicit_promotion_rules = matches!(
|
||||
self.const_kind,
|
||||
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
|
||||
);
|
||||
|
||||
if !self.explicit && !context_uses_explicit_promotion_rules {
|
||||
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
|
||||
// Never promote runtime `const fn` calls of
|
||||
// functions without `#[rustc_promotable]`.
|
||||
|
|
|
@ -33,7 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let tcx = self.hir.tcx();
|
||||
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() {
|
||||
ty::Array(_, length) => {
|
||||
(length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), true)
|
||||
(length.eval_usize(tcx, self.hir.param_env), true)
|
||||
}
|
||||
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::check::FnCtxt;
|
||||
use rustc_ast as ast;
|
||||
|
||||
use rustc_ast::util::lev_distance::find_best_match_for_name;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
||||
|
@ -740,6 +741,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pat_ty
|
||||
}
|
||||
|
||||
fn maybe_suggest_range_literal(
|
||||
&self,
|
||||
e: &mut DiagnosticBuilder<'_>,
|
||||
opt_def_id: Option<hir::def_id::DefId>,
|
||||
ident: Ident,
|
||||
) -> bool {
|
||||
match opt_def_id {
|
||||
Some(def_id) => match self.tcx.hir().get_if_local(def_id) {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Const(_, body_id), ..
|
||||
})) => match self.tcx.hir().get(body_id.hir_id) {
|
||||
hir::Node::Expr(expr) => {
|
||||
if hir::is_range_literal(expr) {
|
||||
let span = self.tcx.hir().span(body_id.hir_id);
|
||||
if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||
e.span_suggestion_verbose(
|
||||
ident.span,
|
||||
"you may want to move the range into the match block",
|
||||
snip,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn emit_bad_pat_path(
|
||||
&self,
|
||||
mut e: DiagnosticBuilder<'_>,
|
||||
|
@ -772,12 +807,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
_ => {
|
||||
let const_def_id = match pat_ty.kind() {
|
||||
let (type_def_id, item_def_id) = match pat_ty.kind() {
|
||||
Adt(def, _) => match res {
|
||||
Res::Def(DefKind::Const, _) => Some(def.did),
|
||||
_ => None,
|
||||
Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)),
|
||||
_ => (None, None),
|
||||
},
|
||||
_ => None,
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
let ranges = &[
|
||||
|
@ -788,11 +823,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.tcx.lang_items().range_inclusive_struct(),
|
||||
self.tcx.lang_items().range_to_inclusive_struct(),
|
||||
];
|
||||
if const_def_id != None && ranges.contains(&const_def_id) {
|
||||
let msg = "constants only support matching by type, \
|
||||
if you meant to match against a range of values, \
|
||||
consider using a range pattern like `min ..= max` in the match block";
|
||||
e.note(msg);
|
||||
if type_def_id != None && ranges.contains(&type_def_id) {
|
||||
if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
|
||||
let msg = "constants only support matching by type, \
|
||||
if you meant to match against a range of values, \
|
||||
consider using a range pattern like `min ..= max` in the match block";
|
||||
e.note(msg);
|
||||
}
|
||||
} else {
|
||||
let msg = "introduce a new binding instead";
|
||||
let sugg = format!("other_{}", ident.as_str().to_lowercase());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue