1
Fork 0

Auto merge of #102704 - Dylan-DPC:rollup-66ff8sm, r=Dylan-DPC

Rollup of 5 pull requests

Successful merges:

 - #100986 (Stop suggesting adding generic args for turbofish)
 - #101061 (panic-on-uninit: adjust checks to 0x01-filling)
 - #102440 (Only export `__tls_*` on wasm32-unknown-unknown.)
 - #102496 (Suggest `.into()` when all other coercion suggestions fail)
 - #102699 (Fix hamburger button color)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-10-05 14:48:17 +00:00
commit 24ac6a26bc
28 changed files with 684 additions and 360 deletions

View file

@ -1180,16 +1180,19 @@ impl<'a> WasmLd<'a> {
// sharing memory and instantiating the module multiple times. As a
// result if it were exported then we'd just have no sharing.
//
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
// symbols are how the TLS segments are initialized and configured.
// On wasm32-unknown-unknown, we also export symbols for glue code to use:
// * `--export=*tls*` - when `#[thread_local]` symbols are used these
// symbols are how the TLS segments are initialized and configured.
if sess.target_features.contains(&sym::atomics) {
cmd.arg("--shared-memory");
cmd.arg("--max-memory=1073741824");
cmd.arg("--import-memory");
cmd.arg("--export=__wasm_init_tls");
cmd.arg("--export=__tls_size");
cmd.arg("--export=__tls_align");
cmd.arg("--export=__tls_base");
if sess.target.os == "unknown" {
cmd.arg("--export=__wasm_init_tls");
cmd.arg("--export=__tls_size");
cmd.arg("--export=__tls_align");
cmd.arg("--export=__tls_base");
}
}
WasmLd { cmd, sess }
}

View file

@ -32,7 +32,6 @@ extern crate rustc_middle;
pub mod const_eval;
mod errors;
pub mod interpret;
mod might_permit_raw_init;
pub mod transform;
pub mod util;
@ -61,7 +60,6 @@ pub fn provide(providers: &mut Providers) {
const_eval::deref_mir_constant(tcx, param_env, value)
};
providers.permits_uninit_init =
|tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Uninit);
providers.permits_zero_init =
|tcx, ty| might_permit_raw_init::might_permit_raw_init(tcx, ty, InitKind::Zero);
|tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill);
providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero);
}

View file

@ -1,44 +0,0 @@
use crate::const_eval::CompileTimeInterpreter;
use crate::interpret::{InterpCx, MemoryKind, OpTy};
use rustc_middle::ty::layout::LayoutCx;
use rustc_middle::ty::{layout::TyAndLayout, ParamEnv, TyCtxt};
use rustc_session::Limit;
use rustc_target::abi::InitKind;
pub fn might_permit_raw_init<'tcx>(
tcx: TyCtxt<'tcx>,
ty: TyAndLayout<'tcx>,
kind: InitKind,
) -> bool {
let strict = tcx.sess.opts.unstable_opts.strict_init_checks;
if strict {
let machine = CompileTimeInterpreter::new(
Limit::new(0),
/*can_access_statics:*/ false,
/*check_alignment:*/ true,
);
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
let allocated = cx
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
.expect("OOM: failed to allocate for uninit check");
if kind == InitKind::Zero {
cx.write_bytes_ptr(
allocated.ptr,
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
)
.expect("failed to write bytes for zero valid check");
}
let ot: OpTy<'_, _> = allocated.into();
// Assume that if it failed, it's a validation failure.
cx.validate_operand(&ot).is_ok()
} else {
let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
ty.might_permit_raw_init(&layout_cx, kind)
}
}

View file

@ -0,0 +1,151 @@
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
use rustc_middle::ty::{ParamEnv, TyCtxt};
use rustc_session::Limit;
use rustc_target::abi::{Abi, FieldsShape, InitKind, Scalar, Variants};
use crate::const_eval::CompileTimeInterpreter;
use crate::interpret::{InterpCx, MemoryKind, OpTy};
/// Determines if this type permits "raw" initialization by just transmuting some memory into an
/// instance of `T`.
///
/// `init_kind` indicates if the memory is zero-initialized or left uninitialized. We assume
/// uninitialized memory is mitigated by filling it with 0x01, which reduces the chance of causing
/// LLVM UB.
///
/// By default we check whether that operation would cause *LLVM UB*, i.e., whether the LLVM IR we
/// generate has UB or not. This is a mitigation strategy, which is why we are okay with accepting
/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
/// to the full uninit check).
pub fn might_permit_raw_init<'tcx>(
tcx: TyCtxt<'tcx>,
ty: TyAndLayout<'tcx>,
kind: InitKind,
) -> bool {
if tcx.sess.opts.unstable_opts.strict_init_checks {
might_permit_raw_init_strict(ty, tcx, kind)
} else {
let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
might_permit_raw_init_lax(ty, &layout_cx, kind)
}
}
/// Implements the 'strict' version of the `might_permit_raw_init` checks; see that function for
/// details.
fn might_permit_raw_init_strict<'tcx>(
ty: TyAndLayout<'tcx>,
tcx: TyCtxt<'tcx>,
kind: InitKind,
) -> bool {
let machine = CompileTimeInterpreter::new(
Limit::new(0),
/*can_access_statics:*/ false,
/*check_alignment:*/ true,
);
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
let allocated = cx
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
.expect("OOM: failed to allocate for uninit check");
if kind == InitKind::Zero {
cx.write_bytes_ptr(
allocated.ptr,
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
)
.expect("failed to write bytes for zero valid check");
}
let ot: OpTy<'_, _> = allocated.into();
// Assume that if it failed, it's a validation failure.
// This does *not* actually check that references are dereferenceable, but since all types that
// require dereferenceability also require non-null, we don't actually get any false negatives
// due to this.
cx.validate_operand(&ot).is_ok()
}
/// Implements the 'lax' (default) version of the `might_permit_raw_init` checks; see that function for
/// details.
fn might_permit_raw_init_lax<'tcx>(
this: TyAndLayout<'tcx>,
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
init_kind: InitKind,
) -> bool {
let scalar_allows_raw_init = move |s: Scalar| -> bool {
match init_kind {
InitKind::Zero => {
// The range must contain 0.
s.valid_range(cx).contains(0)
}
InitKind::UninitMitigated0x01Fill => {
// The range must include an 0x01-filled buffer.
let mut val: u128 = 0x01;
for _ in 1..s.size(cx).bytes() {
// For sizes >1, repeat the 0x01.
val = (val << 8) | 0x01;
}
s.valid_range(cx).contains(val)
}
}
};
// Check the ABI.
let valid = match this.abi {
Abi::Uninhabited => false, // definitely UB
Abi::Scalar(s) => scalar_allows_raw_init(s),
Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
Abi::Aggregate { .. } => true, // Fields are checked below.
};
if !valid {
// This is definitely not okay.
return false;
}
// Special magic check for references and boxes (i.e., special pointer types).
if let Some(pointee) = this.ty.builtin_deref(false) {
let pointee = cx.layout_of(pointee.ty).expect("need to be able to compute layouts");
// We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
if pointee.align.abi.bytes() > 1 {
// 0x01-filling is not aligned.
return false;
}
if pointee.size.bytes() > 0 {
// A 'fake' integer pointer is not sufficiently dereferenceable.
return false;
}
}
// If we have not found an error yet, we need to recursively descend into fields.
match &this.fields {
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
FieldsShape::Array { .. } => {
// Arrays never have scalar layout in LLVM, so if the array is not actually
// accessed, there is no LLVM UB -- therefore we can skip this.
}
FieldsShape::Arbitrary { offsets, .. } => {
for idx in 0..offsets.len() {
if !might_permit_raw_init_lax(this.field(cx, idx), cx, init_kind) {
// We found a field that is unhappy with this kind of initialization.
return false;
}
}
}
}
match &this.variants {
Variants::Single { .. } => {
// All fields of this single variant have already been checked above, there is nothing
// else to do.
}
Variants::Multiple { .. } => {
// We cannot tell LLVM anything about the details of this multi-variant layout, so
// invalid values "hidden" inside the variant cannot cause LLVM trouble.
}
}
true
}

View file

@ -3,8 +3,10 @@ mod alignment;
mod call_kind;
pub mod collect_writes;
mod find_self_call;
mod might_permit_raw_init;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
pub use self::find_self_call::find_self_call;
pub use self::might_permit_raw_init::might_permit_raw_init;

View file

@ -32,17 +32,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: Option<TypeError<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr, error);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
return;
}
self.suggest_no_capture_closure(err, expected, expr_ty);
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected);
self.suggest_copied_or_cloned(err, expr, expr_ty, expected);
// Use `||` to give these suggestions a precedence
let _ = self.suggest_missing_parentheses(err, expr)
|| self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr)
|| self.suggest_compatible_variants(err, expr, expected, expr_ty)
|| self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
|| self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_no_capture_closure(err, expected, expr_ty)
|| self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
|| self.suggest_into(err, expr, expr_ty, expected);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
@ -286,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
) {
) -> bool {
if let ty::Adt(expected_adt, substs) = expected.kind() {
if let hir::ExprKind::Field(base, ident) = expr.kind {
let base_ty = self.typeck_results.borrow().expr_ty(base);
@ -299,7 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"",
Applicability::MaybeIncorrect,
);
return
return true;
}
}
@ -338,7 +340,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
vec!["None", "Some(())"]
} else {
return;
return false;
};
if let Some(indent) =
self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
@ -358,7 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Applicability::MaybeIncorrect,
);
}
return;
return true;
}
}
}
@ -445,6 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestions_for(&**variant, *ctor_kind, *field_name),
Applicability::MaybeIncorrect,
);
return true;
}
_ => {
// More than one matching variant.
@ -460,9 +463,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
Applicability::MaybeIncorrect,
);
return true;
}
}
}
false
}
fn suggest_non_zero_new_unwrap(
@ -471,19 +477,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
expr_ty: Ty<'tcx>,
) {
) -> bool {
let tcx = self.tcx;
let (adt, unwrap) = match expected.kind() {
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
// Unwrap option
let ty::Adt(adt, _) = substs.type_at(0).kind() else { return };
let ty::Adt(adt, _) = substs.type_at(0).kind() else { return false; };
(adt, "")
}
// In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
ty::Adt(adt, _) => (adt, ".unwrap()"),
_ => return,
_ => return false,
};
let map = [
@ -502,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some((s, _)) = map
.iter()
.find(|&&(s, t)| self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t))
else { return };
else { return false; };
let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
@ -514,6 +520,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
],
Applicability::MaybeIncorrect,
);
true
}
pub fn get_conversion_methods(

View file

@ -3,7 +3,7 @@ use crate::astconv::AstConv;
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
use hir::def_id::DefId;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind};
@ -327,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
found: Ty<'tcx>,
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) {
) -> bool {
let expr = expr.peel_blocks();
if let Some((sp, msg, suggestion, applicability, verbose)) =
self.check_ref(expr, found, expected)
@ -337,14 +337,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion(sp, &msg, suggestion, applicability);
}
return true;
} else if self.suggest_else_fn_with_closure(err, expr, found, expected)
{
return true;
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
&& let ty::FnDef(def_id, ..) = &found.kind()
&& let Some(sp) = self.tcx.hir().span_if_local(*def_id)
{
err.span_label(sp, format!("{found} defined here"));
} else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
return true;
} else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
return true;
} else {
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
if !methods.is_empty() {
let mut suggestions = methods.iter()
@ -395,6 +400,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestions,
Applicability::MaybeIncorrect,
);
return true;
}
} else if let ty::Adt(found_adt, found_substs) = found.kind()
&& self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
@ -419,9 +425,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)),
Applicability::MaybeIncorrect,
);
return true;
}
}
}
false
}
/// When encountering the expected boxed value allocated in the stack, suggest allocating it
@ -432,13 +441,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) {
) -> bool {
if self.tcx.hir().is_inside_const_context(expr.hir_id) {
// Do not suggest `Box::new` in const context.
return;
return false;
}
if !expected.is_box() || found.is_box() {
return;
return false;
}
let boxed_found = self.tcx.mk_box(found);
if self.can_coerce(boxed_found, expected) {
@ -456,6 +465,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
https://doc.rust-lang.org/rust-by-example/std/box.html, and \
https://doc.rust-lang.org/std/boxed/index.html",
);
true
} else {
false
}
}
@ -466,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err: &mut Diagnostic,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) {
) -> bool {
if let (ty::FnPtr(_), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
// Report upto four upvars being captured to reduce the amount error messages
@ -490,8 +502,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
multi_span,
"closures can only be coerced to `fn` types if they do not capture any variables"
);
return true;
}
}
false
}
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
@ -893,11 +907,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
) {
) -> bool {
let sp = self.tcx.sess.source_map().start_point(expr.span);
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
true
} else {
false
}
}
@ -910,7 +927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
mut expr: &hir::Expr<'_>,
mut expr_ty: Ty<'tcx>,
mut expected_ty: Ty<'tcx>,
) {
) -> bool {
loop {
match (&expr.kind, expr_ty.kind(), expected_ty.kind()) {
(
@ -924,9 +941,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
(hir::ExprKind::Block(blk, _), _, _) => {
self.suggest_block_to_brackets(diag, *blk, expr_ty, expected_ty);
break;
break true;
}
_ => break,
_ => break false,
}
}
}
@ -937,11 +954,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) {
let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; };
let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; };
) -> bool {
let ty::Adt(adt_def, substs) = expr_ty.kind() else { return false; };
let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return false; };
if adt_def != expected_adt_def {
return;
return false;
}
let mut suggest_copied_or_cloned = || {
@ -960,6 +977,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".copied()",
Applicability::MachineApplicable,
);
return true;
} else if let Some(clone_did) = self.tcx.lang_items().clone_trait()
&& rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions(
self,
@ -977,8 +995,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
".cloned()",
Applicability::MachineApplicable,
);
return true;
}
}
false
};
if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result)
@ -986,12 +1006,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Check that the error types are equal
&& self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok()
{
suggest_copied_or_cloned();
return suggest_copied_or_cloned();
} else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option)
&& adt_def.did() == option_did
{
suggest_copied_or_cloned();
return suggest_copied_or_cloned();
}
false
}
pub(crate) fn suggest_into(
&self,
diag: &mut Diagnostic,
expr: &hir::Expr<'_>,
expr_ty: Ty<'tcx>,
expected_ty: Ty<'tcx>,
) -> bool {
let expr = expr.peel_blocks();
// We have better suggestions for scalar interconversions...
if expr_ty.is_scalar() && expected_ty.is_scalar() {
return false;
}
// Don't suggest turning a block into another type (e.g. `{}.into()`)
if matches!(expr.kind, hir::ExprKind::Block(..)) {
return false;
}
// We'll later suggest `.as_ref` when noting the type error,
// so skip if we will suggest that instead.
if self.should_suggest_as_ref(expected_ty, expr_ty).is_some() {
return false;
}
if let Some(into_def_id) = self.tcx.get_diagnostic_item(sym::Into)
&& self.predicate_must_hold_modulo_regions(&traits::Obligation::new(
self.misc(expr.span),
self.param_env,
ty::Binder::dummy(ty::TraitRef {
def_id: into_def_id,
substs: self.tcx.mk_substs_trait(expr_ty, &[expected_ty.into()]),
})
.to_poly_trait_predicate()
.to_predicate(self.tcx),
))
{
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
vec![(expr.span.shrink_to_hi(), ".into()".to_owned())]
} else {
vec![(expr.span.shrink_to_lo(), "(".to_owned()), (expr.span.shrink_to_hi(), ").into()".to_owned())]
};
diag.multipart_suggestion(
format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"),
sugg,
Applicability::MaybeIncorrect
);
return true;
}
false
}
/// Suggest wrapping the block in square brackets instead of curly braces

View file

@ -2158,8 +2158,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut Diagnostic,
) {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
&& let Some(msg) = self.should_suggest_as_ref(exp_found.expected, exp_found.found)
{
diag.span_suggestion(
span,
msg,
// HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
format!("{}.as_ref()", snippet.trim_start_matches('&')),
Applicability::MachineApplicable,
);
}
}
pub fn should_suggest_as_ref(&self, expected: Ty<'tcx>, found: Ty<'tcx>) -> Option<&str> {
if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) =
(exp_found.expected.kind(), exp_found.found.kind())
(expected.kind(), found.kind())
{
if let ty::Adt(found_def, found_substs) = *found_ty.kind() {
if exp_def == &found_def {
@ -2197,21 +2211,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => show_suggestion = false,
}
}
if let (Ok(snippet), true) =
(self.tcx.sess.source_map().span_to_snippet(span), show_suggestion)
{
diag.span_suggestion(
span,
*msg,
// HACK: fix issue# 100605, suggesting convert from &Option<T> to Option<&T>, remove the extra `&`
format!("{}.as_ref()", snippet.trim_start_matches('&')),
Applicability::MachineApplicable,
);
if show_suggestion {
return Some(*msg);
}
}
}
}
}
None
}
pub fn report_and_explain_type_error(

View file

@ -435,6 +435,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
generics_def_id,
def_id: _,
generic_args,
have_turbofish,
} => {
let generics = self.tcx.generics_of(generics_def_id);
let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
@ -482,11 +483,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.unwrap()
.into_buffer();
infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
span: insert_span,
arg_count: generic_args.len(),
args,
});
if !have_turbofish {
infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
span: insert_span,
arg_count: generic_args.len(),
args,
});
}
}
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
let printer = fmt_printer(self, Namespace::ValueNS);
@ -616,6 +619,7 @@ enum InferSourceKind<'tcx> {
generics_def_id: DefId,
def_id: DefId,
generic_args: &'tcx [GenericArg<'tcx>],
have_turbofish: bool,
},
FullyQualifiedMethodCall {
receiver: &'tcx Expr<'tcx>,
@ -676,6 +680,7 @@ struct InsertableGenericArgs<'tcx> {
substs: SubstsRef<'tcx>,
generics_def_id: DefId,
def_id: DefId,
have_turbofish: bool,
}
/// A visitor which searches for the "best" spot to use in the inference error.
@ -916,6 +921,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id: def_id,
def_id,
have_turbofish: false,
}
};
return Box::new(insertable.into_iter());
@ -933,6 +939,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs: SubstsRef<'tcx>,
) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
let tcx = self.infcx.tcx;
let have_turbofish = path.segments.iter().any(|segment| {
segment.args.map_or(false, |args| args.args.iter().any(|arg| arg.is_ty_or_const()))
});
// The last segment of a path often has `Res::Err` and the
// correct `Res` is the one of the whole path.
//
@ -942,7 +951,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
let generics_def_id = tcx.res_generics_def_id(path.res)?;
let generics = tcx.generics_of(generics_def_id);
if generics.has_impl_trait() {
None?
None?;
}
let insert_span =
path.segments.last().unwrap().ident.span.shrink_to_hi().with_hi(path.span.hi());
@ -951,6 +960,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id,
def_id: path.res.def_id(),
have_turbofish,
}
};
@ -970,6 +980,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
substs,
generics_def_id,
def_id: res.def_id(),
have_turbofish,
})
})
.chain(last_segment_using_path_data)
@ -998,7 +1009,13 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
}
let span = tcx.hir().span(segment.hir_id);
let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
InsertableGenericArgs {
insert_span,
substs,
generics_def_id: def_id,
def_id,
have_turbofish: false,
}
};
let parent_def_id = generics.parent.unwrap();
@ -1121,7 +1138,13 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
for args in self.expr_inferred_subst_iter(expr) {
debug!(?args);
let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args;
let InsertableGenericArgs {
insert_span,
substs,
generics_def_id,
def_id,
have_turbofish,
} = args;
let generics = tcx.generics_of(generics_def_id);
if let Some(argument_index) = generics
.own_substs(substs)
@ -1144,6 +1167,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
generics_def_id,
def_id,
generic_args,
have_turbofish,
},
});
}

View file

@ -1392,7 +1392,7 @@ pub struct PointeeInfo {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InitKind {
Zero,
Uninit,
UninitMitigated0x01Fill,
}
/// Trait that needs to be implemented by the higher-level type representation
@ -1498,72 +1498,4 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
}
}
/// Determines if this type permits "raw" initialization by just transmuting some
/// memory into an instance of `T`.
///
/// `init_kind` indicates if the memory is zero-initialized or left uninitialized.
///
/// This code is intentionally conservative, and will not detect
/// * zero init of an enum whose 0 variant does not allow zero initialization
/// * making uninitialized types who have a full valid range (ints, floats, raw pointers)
/// * Any form of invalid value being made inside an array (unless the value is uninhabited)
///
/// A strict form of these checks that uses const evaluation exists in
/// `rustc_const_eval::might_permit_raw_init`, and a tracking issue for making these checks
/// stricter is <https://github.com/rust-lang/rust/issues/66151>.
///
/// FIXME: Once all the conservatism is removed from here, and the checks are ran by default,
/// we can use the const evaluation checks always instead.
pub fn might_permit_raw_init<C>(self, cx: &C, init_kind: InitKind) -> bool
where
Self: Copy,
Ty: TyAbiInterface<'a, C>,
C: HasDataLayout,
{
let scalar_allows_raw_init = move |s: Scalar| -> bool {
match init_kind {
InitKind::Zero => {
// The range must contain 0.
s.valid_range(cx).contains(0)
}
InitKind::Uninit => {
// The range must include all values.
s.is_always_valid(cx)
}
}
};
// Check the ABI.
let valid = match self.abi {
Abi::Uninhabited => false, // definitely UB
Abi::Scalar(s) => scalar_allows_raw_init(s),
Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
Abi::Aggregate { .. } => true, // Fields are checked below.
};
if !valid {
// This is definitely not okay.
return false;
}
// If we have not found an error yet, we need to recursively descend into fields.
match &self.fields {
FieldsShape::Primitive | FieldsShape::Union { .. } => {}
FieldsShape::Array { .. } => {
// FIXME(#66151): For now, we are conservative and do not check arrays by default.
}
FieldsShape::Arbitrary { offsets, .. } => {
for idx in 0..offsets.len() {
if !self.field(cx, idx).might_permit_raw_init(cx, init_kind) {
// We found a field that is unhappy with this kind of initialization.
return false;
}
}
}
}
// FIXME(#66151): For now, we are conservative and do not check `self.variants`.
true
}
}

View file

@ -1826,6 +1826,7 @@ in storage.js plus the media query with (min-width: 701px)
as an icon, it's okay to specify its sizes in pixels. */
font-size: 32px;
border: none;
color: var(--main-color);
}
.sidebar-elems {

View file

@ -42,23 +42,24 @@ scroll-to: ".block.keyword li:nth-child(1)"
compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543})
// Now checking the background color of the sidebar.
show-text: true
local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"}
reload:
// Open the sidebar menu.
click: ".sidebar-menu-toggle"
assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)"})
assert-css: (".sidebar", {"background-color": "rgb(80, 80, 80)", "color": "rgb(221, 221, 221)"})
local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "ayu"}
reload:
// Open the sidebar menu.
click: ".sidebar-menu-toggle"
assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)"})
assert-css: (".sidebar", {"background-color": "rgb(20, 25, 31)", "color": "rgb(197, 197, 197)"})
local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "light"}
reload:
// Open the sidebar menu.
click: ".sidebar-menu-toggle"
assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)"})
assert-css: (".sidebar", {"background-color": "rgb(245, 245, 245)", "color": "rgb(0, 0, 0)"})

View file

@ -11,12 +11,15 @@ fn main() {
use std::mem::MaybeUninit;
const _BAD1: () = unsafe {
MaybeUninit::<!>::uninit().assume_init();
intrinsics::assert_inhabited::<!>(); //~ERROR: any use of this value will cause an error
//~^WARN: previously accepted
};
const _BAD2: () = {
intrinsics::assert_uninit_valid::<bool>();
intrinsics::assert_uninit_valid::<!>(); //~ERROR: any use of this value will cause an error
//~^WARN: previously accepted
};
const _BAD3: () = {
intrinsics::assert_zero_valid::<&'static i32>();
intrinsics::assert_zero_valid::<&'static i32>(); //~ERROR: any use of this value will cause an error
//~^WARN: previously accepted
};
}

View file

@ -3,26 +3,26 @@ error: any use of this value will cause an error
|
LL | const _BAD1: () = unsafe {
| ---------------
LL | MaybeUninit::<!>::uninit().assume_init();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
LL | intrinsics::assert_inhabited::<!>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: `#[deny(const_err)]` on by default
error: any use of this value will cause an error
--> $DIR/assert-type-intrinsics.rs:17:9
--> $DIR/assert-type-intrinsics.rs:18:9
|
LL | const _BAD2: () = {
| ---------------
LL | intrinsics::assert_uninit_valid::<bool>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
LL | intrinsics::assert_uninit_valid::<!>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
--> $DIR/assert-type-intrinsics.rs:20:9
--> $DIR/assert-type-intrinsics.rs:22:9
|
LL | const _BAD3: () = {
| ---------------
@ -40,8 +40,8 @@ error: any use of this value will cause an error
|
LL | const _BAD1: () = unsafe {
| ---------------
LL | MaybeUninit::<!>::uninit().assume_init();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
LL | intrinsics::assert_inhabited::<!>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
@ -49,12 +49,12 @@ LL | MaybeUninit::<!>::uninit().assume_init();
Future breakage diagnostic:
error: any use of this value will cause an error
--> $DIR/assert-type-intrinsics.rs:17:9
--> $DIR/assert-type-intrinsics.rs:18:9
|
LL | const _BAD2: () = {
| ---------------
LL | intrinsics::assert_uninit_valid::<bool>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
LL | intrinsics::assert_uninit_valid::<!>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
@ -62,7 +62,7 @@ LL | intrinsics::assert_uninit_valid::<bool>();
Future breakage diagnostic:
error: any use of this value will cause an error
--> $DIR/assert-type-intrinsics.rs:20:9
--> $DIR/assert-type-intrinsics.rs:22:9
|
LL | const _BAD3: () = {
| ---------------

View file

@ -3,11 +3,6 @@ error[E0282]: type annotations needed
|
LL | <Struct as Ambiguous<_>>::method();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `Self` declared on the trait `Ambiguous`
|
help: consider specifying the generic argument
|
LL | <Struct as Ambiguous::<_>>::method();
| ~~~~~
error[E0283]: type annotations needed
--> $DIR/concrete-impl.rs:13:5
@ -22,10 +17,6 @@ LL | impl Ambiguous<One> for Struct {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl Ambiguous<Two> for Struct {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider specifying the generic argument
|
LL | <Struct as Ambiguous::<_>>::method();
| ~~~~~
error: aborting due to 2 previous errors

View file

@ -0,0 +1,11 @@
enum OhNo<T, U> {
A(T),
B(U),
C,
}
fn uwu() {
OhNo::C::<u32, _>; //~ ERROR type annotations needed
}
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0282]: type annotations needed
--> $DIR/do-not-suggest-generic-arguments-for-turbofish.rs:8:5
|
LL | OhNo::C::<u32, _>;
| ^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `U` declared on the enum `OhNo`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.

View file

@ -34,6 +34,12 @@ enum OneVariant_NonZero {
DeadVariant(Bar),
}
#[allow(dead_code, non_camel_case_types)]
enum OneVariant_Ref {
Variant(&'static i32),
DeadVariant(Bar),
}
// An `Aggregate` abi enum where 0 is not a valid discriminant.
#[allow(dead_code)]
#[repr(i32)]
@ -63,6 +69,7 @@ enum ZeroIsValid {
One(NonNull<()>) = 1,
}
#[track_caller]
fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
let err = panic::catch_unwind(op).err();
assert_eq!(
@ -71,6 +78,15 @@ fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
);
}
#[track_caller]
fn test_panic_msg_only_if_strict<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
let err = panic::catch_unwind(op).err();
assert_eq!(
err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
if cfg!(strict) { Some(&msg) } else { None },
);
}
fn main() {
unsafe {
// Uninhabited types
@ -139,57 +155,68 @@ fn main() {
"attempted to instantiate uninhabited type `[Bar; 2]`"
);
// Types that do not like zero-initialziation
// Types that don't allow either.
test_panic_msg(
|| mem::uninitialized::<fn()>(),
"attempted to leave type `fn()` uninitialized, which is invalid"
|| mem::zeroed::<&i32>(),
"attempted to zero-initialize type `&i32`, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<fn()>(),
"attempted to zero-initialize type `fn()`, which is invalid"
|| mem::uninitialized::<&i32>(),
"attempted to leave type `&i32` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<*const dyn Send>(),
"attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid"
|| mem::zeroed::<Box<[i32; 0]>>(),
"attempted to zero-initialize type `alloc::boxed::Box<[i32; 0]>`, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<Box<[i32; 0]>>(),
"attempted to leave type `alloc::boxed::Box<[i32; 0]>` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<Box<u8>>(),
"attempted to zero-initialize type `alloc::boxed::Box<u8>`, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<Box<u8>>(),
"attempted to leave type `alloc::boxed::Box<u8>` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<&[i32]>(),
"attempted to zero-initialize type `&[i32]`, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<&[i32]>(),
"attempted to leave type `&[i32]` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<&(u8, [u8])>(),
"attempted to zero-initialize type `&(u8, [u8])`, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<&(u8, [u8])>(),
"attempted to leave type `&(u8, [u8])` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<&dyn Send>(),
"attempted to zero-initialize type `&dyn core::marker::Send`, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<&dyn Send>(),
"attempted to leave type `&dyn core::marker::Send` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<*const dyn Send>(),
"attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
"attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, \
which is invalid"
);
test_panic_msg(
|| mem::zeroed::<(NonNull<u32>, u32, u32)>(),
"attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \
which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<OneVariant_NonZero>(),
"attempted to leave type `OneVariant_NonZero` uninitialized, \
which is invalid"
);
test_panic_msg(
|| mem::zeroed::<OneVariant_NonZero>(),
"attempted to zero-initialize type `OneVariant_NonZero`, \
which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<LR_NonZero>(),
"attempted to leave type `LR_NonZero` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
"attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \
which is invalid"
|| mem::uninitialized::<*const dyn Send>(),
"attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid"
);
test_panic_msg(
@ -197,34 +224,147 @@ fn main() {
"attempted to leave type `NoNullVariant` uninitialized, \
which is invalid"
);
test_panic_msg(
|| mem::zeroed::<NoNullVariant>(),
"attempted to zero-initialize type `NoNullVariant`, \
which is invalid"
);
// Types that can be zero, but not uninit.
test_panic_msg(
|| mem::uninitialized::<bool>(),
"attempted to leave type `bool` uninitialized, which is invalid"
|| mem::zeroed::<OneVariant_Ref>(),
"attempted to zero-initialize type `OneVariant_Ref`, \
which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<OneVariant_Ref>(),
"attempted to leave type `OneVariant_Ref` uninitialized, which is invalid"
);
// Types where both are invalid, but we allow uninit since the 0x01-filling is not LLVM UB.
test_panic_msg(
|| mem::zeroed::<fn()>(),
"attempted to zero-initialize type `fn()`, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<fn()>(),
"attempted to leave type `fn()` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<&()>(),
"attempted to zero-initialize type `&()`, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<&()>(),
"attempted to leave type `&()` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<&[u8]>(),
"attempted to zero-initialize type `&[u8]`, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<&[u8]>(),
"attempted to leave type `&[u8]` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<&str>(),
"attempted to zero-initialize type `&str`, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<&str>(),
"attempted to leave type `&str` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<(NonNull<u32>, u32, u32)>(),
"attempted to zero-initialize type `(core::ptr::non_null::NonNull<u32>, u32, u32)`, \
which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<(NonNull<u32>, u32, u32)>(),
"attempted to leave type `(core::ptr::non_null::NonNull<u32>, u32, u32)` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<OneVariant_NonZero>(),
"attempted to zero-initialize type `OneVariant_NonZero`, \
which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<OneVariant_NonZero>(),
"attempted to leave type `OneVariant_NonZero` uninitialized, which is invalid"
);
// Types where both are invalid but we allow the zeroed form since it is not LLVM UB.
test_panic_msg_only_if_strict(
|| mem::zeroed::<LR_NonZero>(),
"attempted to zero-initialize type `LR_NonZero`, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<LR_NonZero>(),
"attempted to leave type `LR_NonZero` uninitialized, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
"attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<ManuallyDrop<LR_NonZero>>(),
"attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>` uninitialized, \
which is invalid"
);
// Some strict-only things
test_panic_msg_only_if_strict(
|| mem::uninitialized::<i32>(),
"attempted to leave type `i32` uninitialized, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<*const ()>(),
"attempted to leave type `*const ()` uninitialized, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::uninitialized::<[i32; 1]>(),
"attempted to leave type `[i32; 1]` uninitialized, which is invalid"
);
test_panic_msg_only_if_strict(
|| mem::zeroed::<[NonNull<()>; 1]>(),
"attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
);
// Types that can be zero, but not uninit (though some are mitigated).
let _val = mem::zeroed::<LR>();
test_panic_msg(
|| mem::uninitialized::<LR>(),
"attempted to leave type `LR` uninitialized, which is invalid"
);
let _val = mem::zeroed::<ManuallyDrop<LR>>();
test_panic_msg(
|| mem::uninitialized::<ManuallyDrop<LR>>(),
"attempted to leave type `core::mem::manually_drop::ManuallyDrop<LR>` uninitialized, which is invalid"
);
// Some things that should work.
let _val = mem::zeroed::<bool>();
let _val = mem::zeroed::<LR>();
let _val = mem::zeroed::<ManuallyDrop<LR>>();
test_panic_msg_only_if_strict(
|| mem::uninitialized::<bool>(),
"attempted to leave type `bool` uninitialized, which is invalid"
);
let _val = mem::zeroed::<OneVariant>();
test_panic_msg_only_if_strict(
|| mem::uninitialized::<OneVariant>(),
"attempted to leave type `OneVariant` uninitialized, which is invalid"
);
// Some things that are actually allowed.
let _val = mem::zeroed::<Option<&'static i32>>();
let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
let _val = mem::zeroed::<[!; 0]>();
@ -233,59 +373,5 @@ fn main() {
let _val = mem::uninitialized::<[!; 0]>();
let _val = mem::uninitialized::<()>();
let _val = mem::uninitialized::<ZeroSized>();
if cfg!(strict) {
test_panic_msg(
|| mem::uninitialized::<i32>(),
"attempted to leave type `i32` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<*const ()>(),
"attempted to leave type `*const ()` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::uninitialized::<[i32; 1]>(),
"attempted to leave type `[i32; 1]` uninitialized, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<NonNull<()>>(),
"attempted to zero-initialize type `core::ptr::non_null::NonNull<()>`, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<[NonNull<()>; 1]>(),
"attempted to zero-initialize type `[core::ptr::non_null::NonNull<()>; 1]`, which is invalid"
);
// FIXME(#66151) we conservatively do not error here yet (by default).
test_panic_msg(
|| mem::zeroed::<LR_NonZero>(),
"attempted to zero-initialize type `LR_NonZero`, which is invalid"
);
test_panic_msg(
|| mem::zeroed::<ManuallyDrop<LR_NonZero>>(),
"attempted to zero-initialize type `core::mem::manually_drop::ManuallyDrop<LR_NonZero>`, \
which is invalid"
);
} else {
// These are UB because they have not been officially blessed, but we await the resolution
// of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing
// anything about that.
let _val = mem::uninitialized::<i32>();
let _val = mem::uninitialized::<*const ()>();
// These are UB, but best to test them to ensure we don't become unintentionally
// stricter.
// It's currently unchecked to create invalid enums and values inside arrays.
let _val = mem::zeroed::<LR_NonZero>();
let _val = mem::zeroed::<[LR_NonZero; 1]>();
let _val = mem::zeroed::<[NonNull<()>; 1]>();
let _val = mem::uninitialized::<[NonNull<()>; 1]>();
}
}
}

View file

@ -3,11 +3,6 @@ error[E0282]: type annotations needed
|
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
| ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap`
|
help: consider specifying the generic argument
|
LL | unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
| ~~~~~~~~~~
error: aborting due to previous error

View file

@ -9,11 +9,6 @@ error[E0282]: type annotations needed
|
LL | [0u8; std::mem::size_of::<_>()];
| ^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `size_of`
|
help: consider specifying the generic argument
|
LL | [0u8; std::mem::size_of::<_>()];
| ~~~~~
error: aborting due to 2 previous errors

View file

@ -88,6 +88,9 @@ fn main() {
let _val: NonNull<i32> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: NonNull<i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
let _val: (NonZeroU32, i32) = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: (NonZeroU32, i32) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
let _val: *const dyn Send = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: *const dyn Send = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
@ -133,7 +136,7 @@ fn main() {
let _val: Result<i32, i32> = mem::zeroed();
let _val: Result<i32, i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
// Some things that happen to work due to rustc implementation details,
// Some things that happen to be UB-free due to rustc implementation details,
// but are not guaranteed to keep working.
let _val: OneFruit = mem::zeroed();
let _val: OneFruit = mem::uninitialized();

View file

@ -315,8 +315,30 @@ LL | let _val: NonNull<i32> = mem::uninitialized();
|
= note: `std::ptr::NonNull<i32>` must be non-null
error: the type `(NonZeroU32, i32)` does not permit zero-initialization
--> $DIR/invalid_value.rs:91:39
|
LL | let _val: (NonZeroU32, i32) = mem::zeroed();
| ^^^^^^^^^^^^^
| |
| this code causes undefined behavior when executed
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `std::num::NonZeroU32` must be non-null
error: the type `(NonZeroU32, i32)` does not permit being left uninitialized
--> $DIR/invalid_value.rs:92:39
|
LL | let _val: (NonZeroU32, i32) = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
| |
| this code causes undefined behavior when executed
| help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
|
= note: `std::num::NonZeroU32` must be non-null
error: the type `*const dyn Send` does not permit zero-initialization
--> $DIR/invalid_value.rs:91:37
--> $DIR/invalid_value.rs:94:37
|
LL | let _val: *const dyn Send = mem::zeroed();
| ^^^^^^^^^^^^^
@ -327,7 +349,7 @@ LL | let _val: *const dyn Send = mem::zeroed();
= note: the vtable of a wide raw pointer must be non-null
error: the type `*const dyn Send` does not permit being left uninitialized
--> $DIR/invalid_value.rs:92:37
--> $DIR/invalid_value.rs:95:37
|
LL | let _val: *const dyn Send = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -338,7 +360,7 @@ LL | let _val: *const dyn Send = mem::uninitialized();
= note: the vtable of a wide raw pointer must be non-null
error: the type `[fn(); 2]` does not permit zero-initialization
--> $DIR/invalid_value.rs:94:31
--> $DIR/invalid_value.rs:97:31
|
LL | let _val: [fn(); 2] = mem::zeroed();
| ^^^^^^^^^^^^^
@ -349,7 +371,7 @@ LL | let _val: [fn(); 2] = mem::zeroed();
= note: function pointers must be non-null
error: the type `[fn(); 2]` does not permit being left uninitialized
--> $DIR/invalid_value.rs:95:31
--> $DIR/invalid_value.rs:98:31
|
LL | let _val: [fn(); 2] = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -360,7 +382,7 @@ LL | let _val: [fn(); 2] = mem::uninitialized();
= note: function pointers must be non-null
error: the type `TwoUninhabited` does not permit zero-initialization
--> $DIR/invalid_value.rs:97:36
--> $DIR/invalid_value.rs:100:36
|
LL | let _val: TwoUninhabited = mem::zeroed();
| ^^^^^^^^^^^^^
@ -375,7 +397,7 @@ LL | enum TwoUninhabited {
| ^^^^^^^^^^^^^^^^^^^
error: the type `TwoUninhabited` does not permit being left uninitialized
--> $DIR/invalid_value.rs:98:36
--> $DIR/invalid_value.rs:101:36
|
LL | let _val: TwoUninhabited = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -390,7 +412,7 @@ LL | enum TwoUninhabited {
| ^^^^^^^^^^^^^^^^^^^
error: the type `OneFruitNonZero` does not permit zero-initialization
--> $DIR/invalid_value.rs:100:37
--> $DIR/invalid_value.rs:103:37
|
LL | let _val: OneFruitNonZero = mem::zeroed();
| ^^^^^^^^^^^^^
@ -405,7 +427,7 @@ LL | Banana(NonZeroU32),
| ^^^^^^^^^^
error: the type `OneFruitNonZero` does not permit being left uninitialized
--> $DIR/invalid_value.rs:101:37
--> $DIR/invalid_value.rs:104:37
|
LL | let _val: OneFruitNonZero = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -420,7 +442,7 @@ LL | Banana(NonZeroU32),
| ^^^^^^^^^^
error: the type `bool` does not permit being left uninitialized
--> $DIR/invalid_value.rs:105:26
--> $DIR/invalid_value.rs:108:26
|
LL | let _val: bool = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -431,7 +453,7 @@ LL | let _val: bool = mem::uninitialized();
= note: booleans must be either `true` or `false`
error: the type `Wrap<char>` does not permit being left uninitialized
--> $DIR/invalid_value.rs:108:32
--> $DIR/invalid_value.rs:111:32
|
LL | let _val: Wrap<char> = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -446,7 +468,7 @@ LL | struct Wrap<T> { wrapped: T }
| ^^^^^^^^^^
error: the type `NonBig` does not permit being left uninitialized
--> $DIR/invalid_value.rs:111:28
--> $DIR/invalid_value.rs:114:28
|
LL | let _val: NonBig = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -457,7 +479,7 @@ LL | let _val: NonBig = mem::uninitialized();
= note: `NonBig` must be initialized inside its custom valid range
error: the type `Fruit` does not permit being left uninitialized
--> $DIR/invalid_value.rs:114:27
--> $DIR/invalid_value.rs:117:27
|
LL | let _val: Fruit = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -472,7 +494,7 @@ LL | enum Fruit {
| ^^^^^^^^^^
error: the type `[bool; 2]` does not permit being left uninitialized
--> $DIR/invalid_value.rs:117:31
--> $DIR/invalid_value.rs:120:31
|
LL | let _val: [bool; 2] = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -483,7 +505,7 @@ LL | let _val: [bool; 2] = mem::uninitialized();
= note: booleans must be either `true` or `false`
error: the type `i32` does not permit being left uninitialized
--> $DIR/invalid_value.rs:120:25
--> $DIR/invalid_value.rs:123:25
|
LL | let _val: i32 = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -494,7 +516,7 @@ LL | let _val: i32 = mem::uninitialized();
= note: integers must not be uninitialized
error: the type `f32` does not permit being left uninitialized
--> $DIR/invalid_value.rs:123:25
--> $DIR/invalid_value.rs:126:25
|
LL | let _val: f32 = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -505,7 +527,7 @@ LL | let _val: f32 = mem::uninitialized();
= note: floats must not be uninitialized
error: the type `*const ()` does not permit being left uninitialized
--> $DIR/invalid_value.rs:126:31
--> $DIR/invalid_value.rs:129:31
|
LL | let _val: *const () = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -516,7 +538,7 @@ LL | let _val: *const () = mem::uninitialized();
= note: raw pointers must not be uninitialized
error: the type `*const [()]` does not permit being left uninitialized
--> $DIR/invalid_value.rs:129:33
--> $DIR/invalid_value.rs:132:33
|
LL | let _val: *const [()] = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -527,7 +549,7 @@ LL | let _val: *const [()] = mem::uninitialized();
= note: raw pointers must not be uninitialized
error: the type `Result<i32, i32>` does not permit being left uninitialized
--> $DIR/invalid_value.rs:134:38
--> $DIR/invalid_value.rs:137:38
|
LL | let _val: Result<i32, i32> = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
@ -542,7 +564,7 @@ LL | pub enum Result<T, E> {
| ^^^^^^^^^^^^^^^^^^^^^
error: the type `&i32` does not permit zero-initialization
--> $DIR/invalid_value.rs:142:34
--> $DIR/invalid_value.rs:145:34
|
LL | let _val: &'static i32 = mem::transmute(0usize);
| ^^^^^^^^^^^^^^^^^^^^^^
@ -553,7 +575,7 @@ LL | let _val: &'static i32 = mem::transmute(0usize);
= note: references must be non-null
error: the type `&[i32]` does not permit zero-initialization
--> $DIR/invalid_value.rs:143:36
--> $DIR/invalid_value.rs:146:36
|
LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -564,7 +586,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize));
= note: references must be non-null
error: the type `NonZeroU32` does not permit zero-initialization
--> $DIR/invalid_value.rs:144:32
--> $DIR/invalid_value.rs:147:32
|
LL | let _val: NonZeroU32 = mem::transmute(0);
| ^^^^^^^^^^^^^^^^^
@ -575,7 +597,7 @@ LL | let _val: NonZeroU32 = mem::transmute(0);
= note: `std::num::NonZeroU32` must be non-null
error: the type `NonNull<i32>` does not permit zero-initialization
--> $DIR/invalid_value.rs:147:34
--> $DIR/invalid_value.rs:150:34
|
LL | let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -586,7 +608,7 @@ LL | let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
= note: `std::ptr::NonNull<i32>` must be non-null
error: the type `NonNull<i32>` does not permit being left uninitialized
--> $DIR/invalid_value.rs:148:34
--> $DIR/invalid_value.rs:151:34
|
LL | let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -597,7 +619,7 @@ LL | let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
= note: `std::ptr::NonNull<i32>` must be non-null
error: the type `bool` does not permit being left uninitialized
--> $DIR/invalid_value.rs:149:26
--> $DIR/invalid_value.rs:152:26
|
LL | let _val: bool = MaybeUninit::uninit().assume_init();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -607,5 +629,5 @@ LL | let _val: bool = MaybeUninit::uninit().assume_init();
|
= note: booleans must be either `true` or `false`
error: aborting due to 48 previous errors
error: aborting due to 50 previous errors

View file

@ -36,11 +36,6 @@ LL | / &&
LL | | if let Some(y) = a { true } else { false }
| |______________________________________________^ expected `bool`, found `&&bool`
|
help: consider removing the `&&`
|
LL - &&
LL + if let Some(y) = a { true } else { false }
|
help: parentheses are required to parse this as an expression
|
LL | (if let Some(x) = a { true } else { false })

View file

@ -170,11 +170,6 @@ LL | fn revenge_from_mars() -> bool {
LL | { true } && { true }
| ^^^^^^^^^^^ expected `bool`, found `&&bool`
|
help: consider removing the `&&`
|
LL - { true } && { true }
LL + { true } { true }
|
help: parentheses are required to parse this as an expression
|
LL | ({ true }) && { true }
@ -201,10 +196,6 @@ LL | { true } || { true }
|
= note: expected type `bool`
found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:16]`
help: use parentheses to call this closure
|
LL | { true } (|| { true })()
| + +++
help: parentheses are required to parse this as an expression
|
LL | ({ true }) || { true }

View file

@ -9,7 +9,6 @@ fn foo(x: Ty) -> Ty {
Ty::List(elem) => foo(elem),
//~^ ERROR mismatched types
//~| HELP consider unboxing the value
//~| HELP try wrapping
}
}

View file

@ -17,10 +17,6 @@ help: consider unboxing the value
|
LL | Ty::List(elem) => foo(*elem),
| +
help: try wrapping the expression in `Ty::List`
|
LL | Ty::List(elem) => foo(Ty::List(elem)),
| +++++++++ +
error: aborting due to previous error

View file

@ -0,0 +1,26 @@
use std::path::{Path, PathBuf};
use std::sync::atomic::AtomicU32;
use std::sync::Arc;
fn main() {
let x: A = B;
//~^ ERROR mismatched types
//~| HELP call `Into::into` on this expression to convert `B` into `A`
let y: Arc<Path> = PathBuf::new();
//~^ ERROR mismatched types
//~| HELP call `Into::into` on this expression to convert `PathBuf` into `Arc<Path>`
let z: AtomicU32 = 1;
//~^ ERROR mismatched types
//~| HELP call `Into::into` on this expression to convert `{integer}` into `AtomicU32`
}
struct A;
struct B;
impl From<B> for A {
fn from(_: B) -> Self {
A
}
}

View file

@ -0,0 +1,44 @@
error[E0308]: mismatched types
--> $DIR/into-convert.rs:6:16
|
LL | let x: A = B;
| - ^ expected struct `A`, found struct `B`
| |
| expected due to this
|
help: call `Into::into` on this expression to convert `B` into `A`
|
LL | let x: A = B.into();
| +++++++
error[E0308]: mismatched types
--> $DIR/into-convert.rs:10:24
|
LL | let y: Arc<Path> = PathBuf::new();
| --------- ^^^^^^^^^^^^^^ expected struct `Arc`, found struct `PathBuf`
| |
| expected due to this
|
= note: expected struct `Arc<Path>`
found struct `PathBuf`
help: call `Into::into` on this expression to convert `PathBuf` into `Arc<Path>`
|
LL | let y: Arc<Path> = PathBuf::new().into();
| +++++++
error[E0308]: mismatched types
--> $DIR/into-convert.rs:14:24
|
LL | let z: AtomicU32 = 1;
| --------- ^ expected struct `AtomicU32`, found integer
| |
| expected due to this
|
help: call `Into::into` on this expression to convert `{integer}` into `AtomicU32`
|
LL | let z: AtomicU32 = 1.into();
| +++++++
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.