Auto merge of #120242 - matthiaskrgr:rollup-a93yj3i, r=matthiaskrgr
Rollup of 10 pull requests Successful merges: - #117910 (Refactor uses of `objc_msgSend` to no longer have clashing definitions) - #118639 (Undeprecate lint `unstable_features` and make use of it in the compiler) - #119801 (Fix deallocation with wrong allocator in (A)Rc::from_box_in) - #120058 (bootstrap: improvements for compiler builds) - #120059 (Make generic const type mismatches not hide trait impls from the trait solver) - #120097 (Report unreachable subpatterns consistently) - #120137 (Validate AggregateKind types in MIR) - #120164 (`maybe_lint_impl_trait`: separate `is_downgradable` from `is_object_safe`) - #120181 (Allow any `const` expression blocks in `thread_local!`) - #120218 (rustfmt: Check that a token can begin a nonterminal kind before parsing it as a macro arg) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d5fd099729
@ -796,7 +796,67 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
};
|
||||
}
|
||||
match rvalue {
|
||||
Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
|
||||
Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {}
|
||||
Rvalue::Aggregate(kind, fields) => match **kind {
|
||||
AggregateKind::Tuple => {}
|
||||
AggregateKind::Array(dest) => {
|
||||
for src in fields {
|
||||
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
|
||||
self.fail(location, "array field has the wrong type");
|
||||
}
|
||||
}
|
||||
}
|
||||
AggregateKind::Adt(def_id, idx, args, _, Some(field)) => {
|
||||
let adt_def = self.tcx.adt_def(def_id);
|
||||
assert!(adt_def.is_union());
|
||||
assert_eq!(idx, FIRST_VARIANT);
|
||||
let dest = adt_def.non_enum_variant().fields[field].ty(self.tcx, args);
|
||||
if fields.len() != 1 {
|
||||
self.fail(location, "unions should have one initialized field");
|
||||
}
|
||||
if !self.mir_assign_valid_types(fields.raw[0].ty(self.body, self.tcx), dest) {
|
||||
self.fail(location, "union field has the wrong type");
|
||||
}
|
||||
}
|
||||
AggregateKind::Adt(def_id, idx, args, _, None) => {
|
||||
let adt_def = self.tcx.adt_def(def_id);
|
||||
assert!(!adt_def.is_union());
|
||||
let variant = &adt_def.variants()[idx];
|
||||
if variant.fields.len() != fields.len() {
|
||||
self.fail(location, "adt has the wrong number of initialized fields");
|
||||
}
|
||||
for (src, dest) in std::iter::zip(fields, &variant.fields) {
|
||||
if !self.mir_assign_valid_types(
|
||||
src.ty(self.body, self.tcx),
|
||||
dest.ty(self.tcx, args),
|
||||
) {
|
||||
self.fail(location, "adt field has the wrong type");
|
||||
}
|
||||
}
|
||||
}
|
||||
AggregateKind::Closure(_, args) => {
|
||||
let upvars = args.as_closure().upvar_tys();
|
||||
if upvars.len() != fields.len() {
|
||||
self.fail(location, "closure has the wrong number of initialized fields");
|
||||
}
|
||||
for (src, dest) in std::iter::zip(fields, upvars) {
|
||||
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
|
||||
self.fail(location, "closure field has the wrong type");
|
||||
}
|
||||
}
|
||||
}
|
||||
AggregateKind::Coroutine(_, args) => {
|
||||
let upvars = args.as_coroutine().upvar_tys();
|
||||
if upvars.len() != fields.len() {
|
||||
self.fail(location, "coroutine has the wrong number of initialized fields");
|
||||
}
|
||||
for (src, dest) in std::iter::zip(fields, upvars) {
|
||||
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx), dest) {
|
||||
self.fail(location, "coroutine field has the wrong type");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Rvalue::Ref(_, BorrowKind::Fake, _) => {
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
|
||||
self.fail(
|
||||
|
@ -94,15 +94,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
return false;
|
||||
};
|
||||
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
|
||||
let mut is_downgradable = true;
|
||||
let is_object_safe = match self_ty.kind {
|
||||
hir::TyKind::TraitObject(objects, ..) => {
|
||||
objects.iter().all(|o| match o.trait_ref.path.res {
|
||||
Res::Def(DefKind::Trait, id) if Some(id) == owner => {
|
||||
// When we're dealing with a recursive trait, we don't want to downgrade
|
||||
// the error, so we consider them to be object safe always. (#119652)
|
||||
true
|
||||
Res::Def(DefKind::Trait, id) => {
|
||||
if Some(id) == owner {
|
||||
// For recursive traits, don't downgrade the error. (#119652)
|
||||
is_downgradable = false;
|
||||
}
|
||||
tcx.check_is_object_safe(id)
|
||||
}
|
||||
Res::Def(DefKind::Trait, id) => tcx.check_is_object_safe(id),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
@ -130,7 +132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if diag.is_error() {
|
||||
} else if diag.is_error() && is_downgradable {
|
||||
// We'll emit the object safety error already, with a structured suggestion.
|
||||
diag.downgrade_to_delayed_bug();
|
||||
}
|
||||
@ -156,7 +158,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
}
|
||||
if !is_object_safe {
|
||||
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
|
||||
if diag.is_error() {
|
||||
if diag.is_error() && is_downgradable {
|
||||
// We'll emit the object safety error already, with a structured suggestion.
|
||||
diag.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
@ -165,9 +165,9 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
//
|
||||
// This probe is probably not strictly necessary but it seems better to be safe and not accidentally find
|
||||
// ourselves with a check to find bugs being required for code to compile because it made inference progress.
|
||||
let compatible_types = self.probe(|_| {
|
||||
self.probe(|_| {
|
||||
if a.ty() == b.ty() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't have access to trait solving machinery in `rustc_infer` so the logic for determining if the
|
||||
@ -177,32 +177,18 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
relation.param_env().and((a.ty(), b.ty())),
|
||||
&mut OriginalQueryValues::default(),
|
||||
);
|
||||
self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
|
||||
self.tcx.check_tys_might_be_eq(canonical).unwrap_or_else(|_| {
|
||||
// The error will only be reported later. If we emit an ErrorGuaranteed
|
||||
// here, then we will never get to the code that actually emits the error.
|
||||
self.tcx.dcx().delayed_bug(format!(
|
||||
"cannot relate consts of different types (a={a:?}, b={b:?})",
|
||||
))
|
||||
})
|
||||
));
|
||||
// We treat these constants as if they were of the same type, so that any
|
||||
// such constants being used in impls make these impls match barring other mismatches.
|
||||
// This helps with diagnostics down the road.
|
||||
});
|
||||
});
|
||||
|
||||
// If the consts have differing types, just bail with a const error with
|
||||
// the expected const's type. Specifically, we don't want const infer vars
|
||||
// to do any type shapeshifting before and after resolution.
|
||||
if let Err(guar) = compatible_types {
|
||||
// HACK: equating both sides with `[const error]` eagerly prevents us
|
||||
// from leaving unconstrained inference vars during things like impl
|
||||
// matching in the solver.
|
||||
let a_error = ty::Const::new_error(self.tcx, guar, a.ty());
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
|
||||
return self.unify_const_variable(vid, a_error, relation.param_env());
|
||||
}
|
||||
let b_error = ty::Const::new_error(self.tcx, guar, b.ty());
|
||||
if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
|
||||
return self.unify_const_variable(vid, b_error, relation.param_env());
|
||||
}
|
||||
|
||||
return Ok(if relation.a_is_expected() { a_error } else { b_error });
|
||||
}
|
||||
|
||||
match (a.kind(), b.kind()) {
|
||||
(
|
||||
ty::ConstKind::Infer(InferConst::Var(a_vid)),
|
||||
|
@ -20,8 +20,9 @@
|
||||
//! [`rustc_parse::lexer`]: ../rustc_parse/lexer/index.html
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
// We want to be able to build this crate with a stable compiler, so no
|
||||
// `#![feature]` attributes should be added.
|
||||
// We want to be able to build this crate with a stable compiler,
|
||||
// so no `#![feature]` attributes should be added.
|
||||
#![deny(unstable_features)]
|
||||
|
||||
mod cursor;
|
||||
pub mod unescape;
|
||||
|
@ -148,7 +148,7 @@ lint_builtin_unsafe_impl = implementation of an `unsafe` trait
|
||||
|
||||
lint_builtin_unsafe_trait = declaration of an `unsafe` trait
|
||||
|
||||
lint_builtin_unstable_features = unstable feature
|
||||
lint_builtin_unstable_features = use of an unstable feature
|
||||
|
||||
lint_builtin_unused_doc_comment = unused doc comment
|
||||
.label = rustdoc does not generate documentation for {$kind}
|
||||
|
@ -1233,10 +1233,30 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unstable_features` is deprecated and should no longer be used.
|
||||
/// The `unstable_features` lint detects uses of `#![feature]`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(unstable_features)]
|
||||
/// #![feature(test)]
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// In larger nightly-based projects which
|
||||
///
|
||||
/// * consist of a multitude of crates where a subset of crates has to compile on
|
||||
/// stable either unconditionally or depending on a `cfg` flag to for example
|
||||
/// allow stable users to depend on them,
|
||||
/// * don't use nightly for experimental features but for, e.g., unstable options only,
|
||||
///
|
||||
/// this lint may come in handy to enforce policies of these kinds.
|
||||
UNSTABLE_FEATURES,
|
||||
Allow,
|
||||
"enabling unstable features (deprecated. do not use)"
|
||||
"enabling unstable features"
|
||||
}
|
||||
|
||||
declare_lint_pass!(
|
||||
@ -1246,11 +1266,11 @@ declare_lint_pass!(
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
|
||||
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
||||
if attr.has_name(sym::feature) {
|
||||
if let Some(items) = attr.meta_item_list() {
|
||||
for item in items {
|
||||
cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
|
||||
}
|
||||
if attr.has_name(sym::feature)
|
||||
&& let Some(items) = attr.meta_item_list()
|
||||
{
|
||||
for item in items {
|
||||
cx.emit_spanned_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
use rustc_pattern_analysis::errors::Uncovered;
|
||||
use rustc_pattern_analysis::rustc::{
|
||||
Constructor, DeconstructedPat, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
|
||||
Constructor, DeconstructedPat, MatchArm, RustcMatchCheckCtxt as MatchCheckCtxt, Usefulness,
|
||||
UsefulnessReport, WitnessPat,
|
||||
};
|
||||
use rustc_pattern_analysis::{analyze_match, MatchArm};
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
@ -390,6 +389,34 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn analyze_patterns(
|
||||
&mut self,
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
arms: &[MatchArm<'p, 'tcx>],
|
||||
scrut_ty: Ty<'tcx>,
|
||||
) -> Result<UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
|
||||
let report =
|
||||
rustc_pattern_analysis::analyze_match(&cx, &arms, scrut_ty).map_err(|err| {
|
||||
self.error = Err(err);
|
||||
err
|
||||
})?;
|
||||
|
||||
// Warn unreachable subpatterns.
|
||||
for (arm, is_useful) in report.arm_usefulness.iter() {
|
||||
if let Usefulness::Useful(redundant_subpats) = is_useful
|
||||
&& !redundant_subpats.is_empty()
|
||||
{
|
||||
let mut redundant_subpats = redundant_subpats.clone();
|
||||
// Emit lints in the order in which they occur in the file.
|
||||
redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
|
||||
for pat in redundant_subpats {
|
||||
report_unreachable_pattern(cx, arm.arm_data, pat.data().unwrap().span, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(report)
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn check_let(&mut self, pat: &'p Pat<'tcx>, scrutinee: Option<ExprId>, span: Span) {
|
||||
assert!(self.let_source != LetSource::None);
|
||||
@ -435,14 +462,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let scrut_ty = scrut.ty;
|
||||
let report = match analyze_match(&cx, &tarms, scrut_ty) {
|
||||
Ok(report) => report,
|
||||
Err(err) => {
|
||||
self.error = Err(err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let Ok(report) = self.analyze_patterns(&cx, &tarms, scrut.ty) else { return };
|
||||
|
||||
match source {
|
||||
// Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
|
||||
@ -474,7 +494,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
);
|
||||
} else {
|
||||
self.error = Err(report_non_exhaustive_match(
|
||||
&cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
|
||||
&cx, self.thir, scrut.ty, scrut.span, witnesses, arms, expr_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -556,7 +576,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
let cx = self.new_cx(refutability, None, scrut, pat.span);
|
||||
let pat = self.lower_pattern(&cx, pat)?;
|
||||
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
|
||||
let report = analyze_match(&cx, &arms, pat.ty().inner())?;
|
||||
let report = self.analyze_patterns(&cx, &arms, pat.ty().inner())?;
|
||||
Ok((cx, report))
|
||||
}
|
||||
|
||||
@ -567,7 +587,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
|
||||
) -> Result<RefutableFlag, ErrorGuaranteed> {
|
||||
let (cx, report) = self.analyze_binding(pat, Refutable, scrut)?;
|
||||
// Report if the pattern is unreachable, which can only occur when the type is uninhabited.
|
||||
// This also reports unreachable sub-patterns.
|
||||
report_arm_reachability(&cx, &report);
|
||||
// If the list of witnesses is empty, the match is exhaustive, i.e. the `if let` pattern is
|
||||
// irrefutable.
|
||||
@ -850,39 +869,30 @@ fn report_irrefutable_let_patterns(
|
||||
}
|
||||
}
|
||||
|
||||
/// Report unreachable arms, if any.
|
||||
fn report_unreachable_pattern<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
hir_id: HirId,
|
||||
span: Span,
|
||||
catchall: Option<Span>,
|
||||
) {
|
||||
cx.tcx.emit_spanned_lint(
|
||||
UNREACHABLE_PATTERNS,
|
||||
hir_id,
|
||||
span,
|
||||
UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
|
||||
);
|
||||
}
|
||||
|
||||
/// Report unreachable arms, if any.
|
||||
fn report_arm_reachability<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
report: &UsefulnessReport<'p, 'tcx>,
|
||||
) {
|
||||
let report_unreachable_pattern = |span, hir_id, catchall: Option<Span>| {
|
||||
cx.tcx.emit_spanned_lint(
|
||||
UNREACHABLE_PATTERNS,
|
||||
hir_id,
|
||||
span,
|
||||
UnreachablePattern {
|
||||
span: if catchall.is_some() { Some(span) } else { None },
|
||||
catchall,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
let mut catchall = None;
|
||||
for (arm, is_useful) in report.arm_usefulness.iter() {
|
||||
match is_useful {
|
||||
Usefulness::Redundant => {
|
||||
report_unreachable_pattern(arm.pat.data().unwrap().span, arm.arm_data, catchall)
|
||||
}
|
||||
Usefulness::Useful(redundant_subpats) if redundant_subpats.is_empty() => {}
|
||||
// The arm is reachable, but contains redundant subpatterns (from or-patterns).
|
||||
Usefulness::Useful(redundant_subpats) => {
|
||||
let mut redundant_subpats = redundant_subpats.clone();
|
||||
// Emit lints in the order in which they occur in the file.
|
||||
redundant_subpats.sort_unstable_by_key(|pat| pat.data().unwrap().span);
|
||||
for pat in redundant_subpats {
|
||||
report_unreachable_pattern(pat.data().unwrap().span, arm.arm_data, None);
|
||||
}
|
||||
}
|
||||
if matches!(is_useful, Usefulness::Redundant) {
|
||||
report_unreachable_pattern(cx, arm.arm_data, arm.pat.data().unwrap().span, catchall)
|
||||
}
|
||||
if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
|
||||
catchall = Some(arm.pat.data().unwrap().span);
|
||||
|
@ -11,8 +11,9 @@
|
||||
)]
|
||||
#![deny(rustc::untranslatable_diagnostic)]
|
||||
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||
// WARNING: We want to be able to build this crate with a stable compiler,
|
||||
// so no `#![feature]` attributes should be added!
|
||||
// We want to be able to build this crate with a stable compiler,
|
||||
// so no `#![feature]` attributes should be added.
|
||||
#![deny(unstable_features)]
|
||||
|
||||
use rustc_lexer::unescape;
|
||||
pub use Alignment::*;
|
||||
|
@ -1924,7 +1924,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
|
||||
|
||||
// Free the allocation without dropping its contents
|
||||
let (bptr, alloc) = Box::into_raw_with_allocator(src);
|
||||
let src = Box::from_raw(bptr as *mut mem::ManuallyDrop<T>);
|
||||
let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop<T>, alloc.by_ref());
|
||||
drop(src);
|
||||
|
||||
Self::from_ptr_in(ptr, alloc)
|
||||
|
@ -1869,7 +1869,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
|
||||
|
||||
// Free the allocation without dropping its contents
|
||||
let (bptr, alloc) = Box::into_raw_with_allocator(src);
|
||||
let src = Box::from_raw(bptr as *mut mem::ManuallyDrop<T>);
|
||||
let src = Box::from_raw_in(bptr as *mut mem::ManuallyDrop<T>, alloc.by_ref());
|
||||
drop(src);
|
||||
|
||||
Self::from_ptr_in(ptr, alloc)
|
||||
|
@ -201,9 +201,9 @@ mod imp {
|
||||
|
||||
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
|
||||
// and use underscores in their names - they're most probably
|
||||
// are considered private and therefore should be avoided
|
||||
// Here is another way to get arguments using Objective C
|
||||
// runtime
|
||||
// are considered private and therefore should be avoided.
|
||||
// Here is another way to get arguments using the Objective-C
|
||||
// runtime.
|
||||
//
|
||||
// In general it looks like:
|
||||
// res = Vec::new()
|
||||
@ -213,53 +213,60 @@ mod imp {
|
||||
// res
|
||||
#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))]
|
||||
pub fn args() -> Args {
|
||||
use crate::ffi::OsString;
|
||||
use crate::ffi::{c_char, c_void, OsString};
|
||||
use crate::mem;
|
||||
use crate::str;
|
||||
|
||||
type Sel = *const c_void;
|
||||
type NsId = *const c_void;
|
||||
type NSUInteger = usize;
|
||||
|
||||
extern "C" {
|
||||
fn sel_registerName(name: *const libc::c_uchar) -> Sel;
|
||||
fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
|
||||
fn sel_registerName(name: *const c_char) -> Sel;
|
||||
fn objc_getClass(class_name: *const c_char) -> NsId;
|
||||
|
||||
// This must be transmuted to an appropriate function pointer type before being called.
|
||||
fn objc_msgSend();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
extern "C" {
|
||||
fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
|
||||
#[allow(clashing_extern_declarations)]
|
||||
#[link_name = "objc_msgSend"]
|
||||
fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
extern "C" {
|
||||
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
|
||||
#[allow(clashing_extern_declarations)]
|
||||
#[link_name = "objc_msgSend"]
|
||||
fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
|
||||
}
|
||||
|
||||
type Sel = *const libc::c_void;
|
||||
type NsId = *const libc::c_void;
|
||||
const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend;
|
||||
const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void =
|
||||
unsafe { mem::transmute(MSG_SEND_PTR) };
|
||||
const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn(
|
||||
NsId,
|
||||
Sel,
|
||||
) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) };
|
||||
const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn(
|
||||
NsId,
|
||||
Sel,
|
||||
NSUInteger,
|
||||
)
|
||||
-> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) };
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
||||
unsafe {
|
||||
let process_info_sel =
|
||||
sel_registerName(c"processInfo".as_ptr() as *const libc::c_uchar);
|
||||
let arguments_sel = sel_registerName(c"arguments".as_ptr() as *const libc::c_uchar);
|
||||
let utf8_sel = sel_registerName(c"UTF8String".as_ptr() as *const libc::c_uchar);
|
||||
let count_sel = sel_registerName(c"count".as_ptr() as *const libc::c_uchar);
|
||||
let object_at_sel =
|
||||
sel_registerName(c"objectAtIndex:".as_ptr() as *const libc::c_uchar);
|
||||
let process_info_sel = sel_registerName(c"processInfo".as_ptr());
|
||||
let arguments_sel = sel_registerName(c"arguments".as_ptr());
|
||||
let count_sel = sel_registerName(c"count".as_ptr());
|
||||
let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr());
|
||||
let utf8string_sel = sel_registerName(c"UTF8String".as_ptr());
|
||||
|
||||
let klass = objc_getClass(c"NSProcessInfo".as_ptr() as *const libc::c_uchar);
|
||||
let info = objc_msgSend(klass, process_info_sel);
|
||||
let args = objc_msgSend(info, arguments_sel);
|
||||
let klass = objc_getClass(c"NSProcessInfo".as_ptr());
|
||||
// `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
|
||||
let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel);
|
||||
|
||||
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
|
||||
// `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
|
||||
let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel);
|
||||
|
||||
let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel);
|
||||
for i in 0..cnt {
|
||||
let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
|
||||
let utf_c_str: *const libc::c_char = mem::transmute(objc_msgSend(tmp, utf8_sel));
|
||||
// `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
|
||||
let ns_string =
|
||||
MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i);
|
||||
// The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
|
||||
let utf_c_str: *const c_char =
|
||||
MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast();
|
||||
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
|
||||
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
|
||||
}
|
||||
|
@ -186,12 +186,12 @@ macro_rules! thread_local {
|
||||
// empty (base case for the recursion)
|
||||
() => {};
|
||||
|
||||
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }; $($rest:tt)*) => (
|
||||
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => (
|
||||
$crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
|
||||
$crate::thread_local!($($rest)*);
|
||||
);
|
||||
|
||||
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const { $init:expr }) => (
|
||||
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => (
|
||||
$crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
|
||||
);
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
@ -14,3 +15,24 @@ fn sleep() {
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
assert_eq!(*finished.lock().unwrap(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thread_local_containing_const_statements() {
|
||||
// This exercises the `const $init:block` cases of the thread_local macro.
|
||||
// Despite overlapping with expression syntax, the `const { ... }` is not
|
||||
// parsed as `$init:expr`.
|
||||
thread_local! {
|
||||
static CELL: Cell<u32> = const {
|
||||
let value = 1;
|
||||
Cell::new(value)
|
||||
};
|
||||
|
||||
static REFCELL: RefCell<u32> = const {
|
||||
let value = 1;
|
||||
RefCell::new(value)
|
||||
};
|
||||
}
|
||||
|
||||
assert_eq!(CELL.get(), 1);
|
||||
assert_eq!(REFCELL.take(), 1);
|
||||
}
|
||||
|
@ -803,7 +803,14 @@ impl Rustc {
|
||||
}
|
||||
|
||||
impl Step for Rustc {
|
||||
type Output = ();
|
||||
// We return the stage of the "actual" compiler (not the uplifted one).
|
||||
//
|
||||
// By "actual" we refer to the uplifting logic where we may not compile the requested stage;
|
||||
// instead, we uplift it from the previous stages. Which can lead to bootstrap failures in
|
||||
// specific situations where we request stage X from other steps. However we may end up
|
||||
// uplifting it from stage Y, causing the other stage to fail when attempting to link with
|
||||
// stage X which was never actually built.
|
||||
type Output = u32;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const DEFAULT: bool = false;
|
||||
|
||||
@ -834,7 +841,7 @@ impl Step for Rustc {
|
||||
/// This will build the compiler for a particular stage of the build using
|
||||
/// the `compiler` targeting the `target` architecture. The artifacts
|
||||
/// created will also be linked into the sysroot directory.
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
fn run(self, builder: &Builder<'_>) -> u32 {
|
||||
let compiler = self.compiler;
|
||||
let target = self.target;
|
||||
|
||||
@ -848,7 +855,7 @@ impl Step for Rustc {
|
||||
compiler,
|
||||
builder.config.ci_rustc_dev_contents(),
|
||||
);
|
||||
return;
|
||||
return compiler.stage;
|
||||
}
|
||||
|
||||
builder.ensure(Std::new(compiler, target));
|
||||
@ -857,7 +864,8 @@ impl Step for Rustc {
|
||||
builder.info("WARNING: Using a potentially old librustc. This may not behave well.");
|
||||
builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
|
||||
builder.ensure(RustcLink::from_rustc(self, compiler));
|
||||
return;
|
||||
|
||||
return compiler.stage;
|
||||
}
|
||||
|
||||
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
|
||||
@ -880,7 +888,7 @@ impl Step for Rustc {
|
||||
};
|
||||
builder.info(&msg);
|
||||
builder.ensure(RustcLink::from_rustc(self, compiler_to_use));
|
||||
return;
|
||||
return compiler_to_use.stage;
|
||||
}
|
||||
|
||||
// Ensure that build scripts and proc macros have a std / libproc_macro to link against.
|
||||
@ -984,6 +992,8 @@ impl Step for Rustc {
|
||||
self,
|
||||
builder.compiler(compiler.stage, builder.config.build),
|
||||
));
|
||||
|
||||
compiler.stage
|
||||
}
|
||||
}
|
||||
|
||||
@ -1642,21 +1652,6 @@ impl Step for Assemble {
|
||||
return target_compiler;
|
||||
}
|
||||
|
||||
// Get the compiler that we'll use to bootstrap ourselves.
|
||||
//
|
||||
// Note that this is where the recursive nature of the bootstrap
|
||||
// happens, as this will request the previous stage's compiler on
|
||||
// downwards to stage 0.
|
||||
//
|
||||
// Also note that we're building a compiler for the host platform. We
|
||||
// only assume that we can run `build` artifacts, which means that to
|
||||
// produce some other architecture compiler we need to start from
|
||||
// `build` to get there.
|
||||
//
|
||||
// FIXME: It may be faster if we build just a stage 1 compiler and then
|
||||
// use that to bootstrap this compiler forward.
|
||||
let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
|
||||
|
||||
// If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.
|
||||
if builder.download_rustc() {
|
||||
let sysroot =
|
||||
@ -1671,19 +1666,30 @@ impl Step for Assemble {
|
||||
return target_compiler;
|
||||
}
|
||||
|
||||
// Get the compiler that we'll use to bootstrap ourselves.
|
||||
//
|
||||
// Note that this is where the recursive nature of the bootstrap
|
||||
// happens, as this will request the previous stage's compiler on
|
||||
// downwards to stage 0.
|
||||
//
|
||||
// Also note that we're building a compiler for the host platform. We
|
||||
// only assume that we can run `build` artifacts, which means that to
|
||||
// produce some other architecture compiler we need to start from
|
||||
// `build` to get there.
|
||||
//
|
||||
// FIXME: It may be faster if we build just a stage 1 compiler and then
|
||||
// use that to bootstrap this compiler forward.
|
||||
let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
|
||||
|
||||
// Build the libraries for this compiler to link to (i.e., the libraries
|
||||
// it uses at runtime). NOTE: Crates the target compiler compiles don't
|
||||
// link to these. (FIXME: Is that correct? It seems to be correct most
|
||||
// of the time but I think we do link to these for stage2/bin compilers
|
||||
// when not performing a full bootstrap).
|
||||
builder.ensure(Rustc::new(build_compiler, target_compiler.host));
|
||||
|
||||
// FIXME: For now patch over problems noted in #90244 by early returning here, even though
|
||||
// we've not properly assembled the target sysroot. A full fix is pending further investigation,
|
||||
// for now full bootstrap usage is rare enough that this is OK.
|
||||
if target_compiler.stage >= 3 && !builder.config.full_bootstrap {
|
||||
return target_compiler;
|
||||
}
|
||||
let actual_stage = builder.ensure(Rustc::new(build_compiler, target_compiler.host));
|
||||
// Current build_compiler.stage might be uplifted instead of being built; so update it
|
||||
// to not fail while linking the artifacts.
|
||||
build_compiler.stage = actual_stage;
|
||||
|
||||
for &backend in builder.config.rust_codegen_backends.iter() {
|
||||
if backend == "llvm" {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc_ast::token::{Delimiter, TokenKind};
|
||||
use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{ast, ptr};
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
||||
use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::{self, kw};
|
||||
@ -15,7 +15,7 @@ pub(crate) mod cfg_if;
|
||||
pub(crate) mod lazy_static;
|
||||
|
||||
fn build_stream_parser<'a>(sess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> {
|
||||
stream_to_parser(sess, tokens, MACRO_ARGUMENTS)
|
||||
stream_to_parser(sess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden)
|
||||
}
|
||||
|
||||
fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> {
|
||||
@ -24,21 +24,23 @@ fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser
|
||||
|
||||
fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
|
||||
macro_rules! parse_macro_arg {
|
||||
($macro_arg:ident, $parser:expr, $f:expr) => {
|
||||
($macro_arg:ident, $nt_kind:expr, $try_parse:expr, $then:expr) => {
|
||||
let mut cloned_parser = (*parser).clone();
|
||||
match $parser(&mut cloned_parser) {
|
||||
Ok(x) => {
|
||||
if parser.sess.dcx.has_errors().is_some() {
|
||||
parser.sess.dcx.reset_err_count();
|
||||
} else {
|
||||
// Parsing succeeded.
|
||||
*parser = cloned_parser;
|
||||
return Some(MacroArg::$macro_arg($f(x)?));
|
||||
if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) {
|
||||
match $try_parse(&mut cloned_parser) {
|
||||
Ok(x) => {
|
||||
if parser.sess.dcx.has_errors().is_some() {
|
||||
parser.sess.dcx.reset_err_count();
|
||||
} else {
|
||||
// Parsing succeeded.
|
||||
*parser = cloned_parser;
|
||||
return Some(MacroArg::$macro_arg($then(x)?));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
e.cancel();
|
||||
parser.sess.dcx.reset_err_count();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
e.cancel();
|
||||
parser.sess.dcx.reset_err_count();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -46,23 +48,27 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
|
||||
|
||||
parse_macro_arg!(
|
||||
Expr,
|
||||
|parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(),
|
||||
NonterminalKind::Expr,
|
||||
|parser: &mut Parser<'b>| parser.parse_expr(),
|
||||
|x: ptr::P<ast::Expr>| Some(x)
|
||||
);
|
||||
parse_macro_arg!(
|
||||
Ty,
|
||||
|parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(),
|
||||
NonterminalKind::Ty,
|
||||
|parser: &mut Parser<'b>| parser.parse_ty(),
|
||||
|x: ptr::P<ast::Ty>| Some(x)
|
||||
);
|
||||
parse_macro_arg!(
|
||||
Pat,
|
||||
|parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None, None),
|
||||
NonterminalKind::PatParam { inferred: false },
|
||||
|parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None),
|
||||
|x: ptr::P<ast::Pat>| Some(x)
|
||||
);
|
||||
// `parse_item` returns `Option<ptr::P<ast::Item>>`.
|
||||
parse_macro_arg!(
|
||||
Item,
|
||||
|parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No),
|
||||
NonterminalKind::Item,
|
||||
|parser: &mut Parser<'b>| parser.parse_item(ForceCollect::No),
|
||||
|x: Option<ptr::P<ast::Item>>| x
|
||||
);
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
m!(const N: usize = 0;);
|
@ -0,0 +1,3 @@
|
||||
m!(
|
||||
const N: usize = 0;
|
||||
);
|
@ -11,3 +11,4 @@ impl<const N: u64> Q for [u8; N] {
|
||||
}
|
||||
|
||||
pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
|
||||
//~^ ERROR: the constant `13` is not of type `u64`
|
||||
|
@ -1,9 +1,23 @@
|
||||
error: the constant `13` is not of type `u64`
|
||||
--> $DIR/bad-subst-const-kind.rs:13:24
|
||||
|
|
||||
LL | pub fn test() -> [u8; <[u8; 13] as Q>::ASSOC] { todo!() }
|
||||
| ^^^^^^^^ expected `u64`, found `usize`
|
||||
|
|
||||
note: required for `[u8; 13]` to implement `Q`
|
||||
--> $DIR/bad-subst-const-kind.rs:8:20
|
||||
|
|
||||
LL | impl<const N: u64> Q for [u8; N] {
|
||||
| ------------ ^ ^^^^^^^
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/bad-subst-const-kind.rs:8:31
|
||||
|
|
||||
LL | impl<const N: u64> Q for [u8; N] {
|
||||
| ^ expected `usize`, found `u64`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
@ -7,7 +7,10 @@ trait Q {
|
||||
|
||||
impl<const N: u64> Q for [u8; N] {}
|
||||
//~^ ERROR not all trait items implemented
|
||||
//~| ERROR mismatched types
|
||||
|
||||
pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
|
||||
//~^ ERROR the constant `13` is not of type `u64`
|
||||
//~| ERROR mismatched types
|
||||
|
||||
pub fn main() {}
|
||||
|
@ -7,6 +7,35 @@ LL | const ASSOC: usize;
|
||||
LL | impl<const N: u64> Q for [u8; N] {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: the constant `13` is not of type `u64`
|
||||
--> $DIR/type_mismatch.rs:12:26
|
||||
|
|
||||
LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
|
||||
| ^^^^^^^^ expected `u64`, found `usize`
|
||||
|
|
||||
note: required for `[u8; 13]` to implement `Q`
|
||||
--> $DIR/type_mismatch.rs:8:20
|
||||
|
|
||||
LL | impl<const N: u64> Q for [u8; N] {}
|
||||
| ------------ ^ ^^^^^^^
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
|
||||
For more information about this error, try `rustc --explain E0046`.
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type_mismatch.rs:12:20
|
||||
|
|
||||
LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {}
|
||||
| ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `[u8; <[u8; 13] as Q>::ASSOC]`, found `()`
|
||||
| |
|
||||
| implicitly returns `()` as its body has no tail or `return` expression
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type_mismatch.rs:8:31
|
||||
|
|
||||
LL | impl<const N: u64> Q for [u8; N] {}
|
||||
| ^ expected `usize`, found `u64`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0046, E0308.
|
||||
For more information about an error, try `rustc --explain E0046`.
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: unstable feature
|
||||
error: use of an unstable feature
|
||||
--> $DIR/feature-gate-feature-gate.rs:2:12
|
||||
|
|
||||
LL | #![feature(intrinsics)]
|
||||
|
@ -160,3 +160,23 @@ fn main() {
|
||||
| (y, x) => {} //~ ERROR unreachable
|
||||
}
|
||||
}
|
||||
|
||||
fn unreachable_in_param((_ | (_, _)): (bool, bool)) {}
|
||||
//~^ ERROR unreachable
|
||||
|
||||
fn unreachable_in_binding() {
|
||||
let bool_pair = (true, true);
|
||||
let bool_option = Some(true);
|
||||
|
||||
let (_ | (_, _)) = bool_pair;
|
||||
//~^ ERROR unreachable
|
||||
for (_ | (_, _)) in [bool_pair] {}
|
||||
//~^ ERROR unreachable
|
||||
|
||||
let (Some(_) | Some(true)) = bool_option else { return };
|
||||
//~^ ERROR unreachable
|
||||
if let Some(_) | Some(true) = bool_option {}
|
||||
//~^ ERROR unreachable
|
||||
while let Some(_) | Some(true) = bool_option {}
|
||||
//~^ ERROR unreachable
|
||||
}
|
||||
|
@ -184,5 +184,41 @@ error: unreachable pattern
|
||||
LL | | (y, x) => {}
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 29 previous errors
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:164:30
|
||||
|
|
||||
LL | fn unreachable_in_param((_ | (_, _)): (bool, bool)) {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:171:14
|
||||
|
|
||||
LL | let (_ | (_, _)) = bool_pair;
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:173:14
|
||||
|
|
||||
LL | for (_ | (_, _)) in [bool_pair] {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:176:20
|
||||
|
|
||||
LL | let (Some(_) | Some(true)) = bool_option else { return };
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:178:22
|
||||
|
|
||||
LL | if let Some(_) | Some(true) = bool_option {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/exhaustiveness-unreachable-pattern.rs:180:25
|
||||
|
|
||||
LL | while let Some(_) | Some(true) = bool_option {}
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 35 previous errors
|
||||
|
||||
|
@ -0,0 +1,44 @@
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:17:9
|
||||
|
|
||||
LL | Err(!),
|
||||
| ^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unreachable.rs:7:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:20:19
|
||||
|
|
||||
LL | let (Ok(_x) | Err(!)) = res_void;
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:22:12
|
||||
|
|
||||
LL | if let Err(!) = res_void {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:24:24
|
||||
|
|
||||
LL | if let (Ok(true) | Err(!)) = res_void {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:26:23
|
||||
|
|
||||
LL | for (Ok(mut _x) | Err(!)) in [res_void] {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/unreachable.rs:30:18
|
||||
|
|
||||
LL | fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
31
tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
Normal file
31
tests/ui/rfcs/rfc-0000-never_patterns/unreachable.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// revisions: normal exh_pats
|
||||
//[normal] check-pass
|
||||
#![feature(never_patterns)]
|
||||
#![allow(incomplete_features)]
|
||||
#![cfg_attr(exh_pats, feature(exhaustive_patterns))]
|
||||
#![allow(dead_code, unreachable_code)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Void {}
|
||||
|
||||
fn main() {
|
||||
let res_void: Result<bool, Void> = Ok(true);
|
||||
|
||||
match res_void {
|
||||
Ok(_x) => {}
|
||||
Err(!),
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
}
|
||||
let (Ok(_x) | Err(!)) = res_void;
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
if let Err(!) = res_void {}
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
if let (Ok(true) | Err(!)) = res_void {}
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
for (Ok(mut _x) | Err(!)) in [res_void] {}
|
||||
//[exh_pats]~^ ERROR unreachable
|
||||
}
|
||||
|
||||
fn foo((Ok(_x) | Err(!)): Result<bool, Void>) {}
|
||||
//[exh_pats]~^ ERROR unreachable
|
@ -8,5 +8,6 @@ struct S<const L: usize>;
|
||||
impl<const N: i32> Copy for S<N> {}
|
||||
//~^ ERROR the constant `N` is not of type `usize`
|
||||
impl<const M: usize> Copy for S<M> {}
|
||||
//~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>`
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,14 +1,29 @@
|
||||
error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:10:1
|
||||
|
|
||||
LL | impl<const N: i32> Copy for S<N> {}
|
||||
| -------------------------------- first implementation here
|
||||
LL |
|
||||
LL | impl<const M: usize> Copy for S<M> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
|
||||
|
||||
error: the constant `N` is not of type `usize`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
|
||||
|
|
||||
LL | impl<const N: i32> Copy for S<N> {}
|
||||
| ^^^^ expected `usize`, found `i32`
|
||||
|
|
||||
note: required by a bound in `S`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:6:10
|
||||
note: required for `S<N>` to implement `Clone`
|
||||
--> $DIR/bad-const-wf-doesnt-specialize.rs:5:10
|
||||
|
|
||||
LL | #[derive(Clone)]
|
||||
| ^^^^^
|
||||
LL | struct S<const L: usize>;
|
||||
| ^^^^^^^^^^^^^^ required by this bound in `S`
|
||||
| ----- unsatisfied trait bound introduced in this `derive` macro
|
||||
note: required by a bound in `Copy`
|
||||
--> $SRC_DIR/core/src/marker.rs:LL:COL
|
||||
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0119`.
|
||||
|
@ -8,16 +8,18 @@ trait A: Sized {
|
||||
//~| ERROR the trait `A` cannot be made into an object
|
||||
}
|
||||
trait B {
|
||||
fn f(a: B) -> B;
|
||||
fn f(b: B) -> B;
|
||||
//~^ ERROR trait objects must include the `dyn` keyword
|
||||
//~| ERROR trait objects must include the `dyn` keyword
|
||||
//~| ERROR associated item referring to unboxed trait object for its own trait
|
||||
//~| ERROR the trait `B` cannot be made into an object
|
||||
}
|
||||
trait C {
|
||||
fn f(&self, a: C) -> C;
|
||||
fn f(&self, c: C) -> C;
|
||||
//~^ ERROR trait objects must include the `dyn` keyword
|
||||
//~| ERROR trait objects must include the `dyn` keyword
|
||||
//~| ERROR associated item referring to unboxed trait object for its own trait
|
||||
//~| ERROR the trait `C` cannot be made into an object
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -30,18 +30,18 @@ error: associated item referring to unboxed trait object for its own trait
|
||||
|
|
||||
LL | trait B {
|
||||
| - in this trait
|
||||
LL | fn f(a: B) -> B;
|
||||
LL | fn f(b: B) -> B;
|
||||
| ^ ^
|
||||
|
|
||||
help: you might have meant to use `Self` to refer to the implementing type
|
||||
|
|
||||
LL | fn f(a: Self) -> Self;
|
||||
LL | fn f(b: Self) -> Self;
|
||||
| ~~~~ ~~~~
|
||||
|
||||
error[E0038]: the trait `B` cannot be made into an object
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
|
||||
|
|
||||
LL | fn f(a: B) -> B;
|
||||
LL | fn f(b: B) -> B;
|
||||
| ^ `B` cannot be made into an object
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
@ -49,23 +49,53 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all
|
||||
|
|
||||
LL | trait B {
|
||||
| - this trait cannot be made into an object...
|
||||
LL | fn f(a: B) -> B;
|
||||
LL | fn f(b: B) -> B;
|
||||
| ^ ...because associated function `f` has no `self` parameter
|
||||
help: consider turning `f` into a method by giving it a `&self` argument
|
||||
|
|
||||
LL | fn f(&self, a: B) -> B;
|
||||
LL | fn f(&self, b: B) -> B;
|
||||
| ++++++
|
||||
help: alternatively, consider constraining `f` so it does not apply to trait objects
|
||||
|
|
||||
LL | fn f(a: B) -> B where Self: Sized;
|
||||
LL | fn f(b: B) -> B where Self: Sized;
|
||||
| +++++++++++++++++
|
||||
|
||||
error: associated item referring to unboxed trait object for its own trait
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
|
||||
|
|
||||
LL | trait C {
|
||||
| - in this trait
|
||||
LL | fn f(&self, c: C) -> C;
|
||||
| ^ ^
|
||||
|
|
||||
help: you might have meant to use `Self` to refer to the implementing type
|
||||
|
|
||||
LL | fn f(&self, c: Self) -> Self;
|
||||
| ~~~~ ~~~~
|
||||
|
||||
error[E0038]: the trait `C` cannot be made into an object
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
|
||||
|
|
||||
LL | fn f(&self, c: C) -> C;
|
||||
| ----- ^ `C` cannot be made into an object
|
||||
| |
|
||||
| help: consider changing method `f`'s `self` parameter to be `&self` (notice the capitalization): `&Self`
|
||||
|
|
||||
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:10
|
||||
|
|
||||
LL | trait C {
|
||||
| - this trait cannot be made into an object...
|
||||
LL | fn f(&self, c: C) -> C;
|
||||
| ^^^^^ ...because method `f`'s `self` parameter cannot be dispatched on
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:13
|
||||
|
|
||||
LL | fn f(a: A) -> A;
|
||||
| ^
|
||||
|
|
||||
= note: `A` it is not object safe, so it can't be `dyn`
|
||||
help: use a new generic type parameter, constrained by `A`
|
||||
|
|
||||
LL | fn f<T: A>(a: T) -> A;
|
||||
@ -74,10 +104,6 @@ help: you can also use an opaque type, but users won't be able to specify the ty
|
||||
|
|
||||
LL | fn f(a: impl A) -> A;
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `A`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn f(a: &dyn A) -> A;
|
||||
| ++++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:4:19
|
||||
@ -85,84 +111,66 @@ error[E0782]: trait objects must include the `dyn` keyword
|
||||
LL | fn f(a: A) -> A;
|
||||
| ^
|
||||
|
|
||||
help: use `impl A` to return an opaque type, as long as you return a single underlying type
|
||||
help: `A` is not object safe, use `impl A` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn f(a: A) -> impl A;
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn f(a: A) -> Box<dyn A>;
|
||||
| +++++++ +
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:13
|
||||
|
|
||||
LL | fn f(a: B) -> B;
|
||||
LL | fn f(b: B) -> B;
|
||||
| ^
|
||||
|
|
||||
= note: `B` it is not object safe, so it can't be `dyn`
|
||||
help: use a new generic type parameter, constrained by `B`
|
||||
|
|
||||
LL | fn f<T: B>(a: T) -> B;
|
||||
LL | fn f<T: B>(b: T) -> B;
|
||||
| ++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn f(a: impl B) -> B;
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `B`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn f(a: &dyn B) -> B;
|
||||
LL | fn f(b: impl B) -> B;
|
||||
| ++++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:11:19
|
||||
|
|
||||
LL | fn f(a: B) -> B;
|
||||
LL | fn f(b: B) -> B;
|
||||
| ^
|
||||
|
|
||||
help: use `impl B` to return an opaque type, as long as you return a single underlying type
|
||||
help: `B` is not object safe, use `impl B` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn f(a: B) -> impl B;
|
||||
LL | fn f(b: B) -> impl B;
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn f(a: B) -> Box<dyn B>;
|
||||
| +++++++ +
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:20
|
||||
|
|
||||
LL | fn f(&self, a: C) -> C;
|
||||
LL | fn f(&self, c: C) -> C;
|
||||
| ^
|
||||
|
|
||||
= note: `C` it is not object safe, so it can't be `dyn`
|
||||
help: use a new generic type parameter, constrained by `C`
|
||||
|
|
||||
LL | fn f<T: C>(&self, a: T) -> C;
|
||||
LL | fn f<T: C>(&self, c: T) -> C;
|
||||
| ++++++ ~
|
||||
help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
|
||||
|
|
||||
LL | fn f(&self, a: impl C) -> C;
|
||||
| ++++
|
||||
help: alternatively, use a trait object to accept any type that implements `C`, accessing its methods at runtime using dynamic dispatch
|
||||
|
|
||||
LL | fn f(&self, a: &dyn C) -> C;
|
||||
LL | fn f(&self, c: impl C) -> C;
|
||||
| ++++
|
||||
|
||||
error[E0782]: trait objects must include the `dyn` keyword
|
||||
--> $DIR/object-unsafe-trait-should-use-self-2021-without-dyn.rs:18:26
|
||||
|
|
||||
LL | fn f(&self, a: C) -> C;
|
||||
LL | fn f(&self, c: C) -> C;
|
||||
| ^
|
||||
|
|
||||
help: use `impl C` to return an opaque type, as long as you return a single underlying type
|
||||
help: `C` is not object safe, use `impl C` to return an opaque type, as long as you return a single underlying type
|
||||
|
|
||||
LL | fn f(&self, a: C) -> impl C;
|
||||
LL | fn f(&self, c: C) -> impl C;
|
||||
| ++++
|
||||
help: alternatively, you can return an owned trait object
|
||||
|
|
||||
LL | fn f(&self, a: C) -> Box<dyn C>;
|
||||
| +++++++ +
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0038, E0782.
|
||||
For more information about an error, try `rustc --explain E0038`.
|
||||
|
@ -1,4 +1,5 @@
|
||||
// run-pass
|
||||
#![allow(unreachable_patterns)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(dead_code)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user