diff options
449 files changed, 8530 insertions, 3500 deletions
diff --git a/Cargo.lock b/Cargo.lock index 4421e526d10..ff21d5f8c08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4525,6 +4525,7 @@ dependencies = [ "rustc_middle", "rustc_span", "rustc_target", + "scoped-tls", "stable_mir", "tracing", ] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4f1b13870fd..b82f878ea87 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -188,7 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.id, None, e.span, - hir::AsyncCoroutineKind::Block, + hir::CoroutineSource::Block, |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), @@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure_node_id: NodeId, ret_ty: Option<hir::FnRetTy<'hir>>, span: Span, - async_gen_kind: hir::AsyncCoroutineKind, + async_gen_kind: hir::CoroutineSource, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::ExprKind<'hir> { let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span))); @@ -1005,7 +1005,7 @@ impl<'hir> LoweringContext<'_, 'hir> { inner_closure_id, async_ret_ty, body.span, - hir::AsyncCoroutineKind::Closure, + hir::CoroutineSource::Closure, |this| this.with_new_scopes(|this| this.lower_expr_mut(body)), ); let hir_id = this.lower_node_id(inner_closure_id); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3c165f87dbf..ca851bd4d35 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1206,7 +1206,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure_id, None, body.span, - hir::AsyncCoroutineKind::Fn, + hir::CoroutineSource::Fn, |this| { // Create a block from the user's function body: let user_body = this.lower_block_expr(body); diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl index e6cbbaf3704..7281282fec3 100644 --- a/compiler/rustc_attr/messages.ftl +++ b/compiler/rustc_attr/messages.ftl @@ -58,6 +58,9 @@ attr_invalid_repr_hint_no_paren = attr_invalid_repr_hint_no_value = invalid representation hint: `{$name}` does not take a value +attr_invalid_since = + 'since' must be a Rust version number, such as "1.31.0" + attr_missing_feature = missing 'feature' diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 60eacde1c72..bd85483885e 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -3,6 +3,7 @@ use rustc_ast::{self as ast, attr}; use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; +use rustc_errors::ErrorGuaranteed; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; use rustc_session::config::ExpectedValues; @@ -12,6 +13,7 @@ use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Session; use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; +use std::fmt::{self, Display}; use std::num::NonZeroU32; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -22,9 +24,10 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; /// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591). pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; +pub const CURRENT_RUSTC_VERSION: &str = env!("CFG_RELEASE"); + pub fn rust_version_symbol() -> Symbol { - let version = option_env!("CFG_RELEASE").unwrap_or("<current>"); - Symbol::intern(&version) + Symbol::intern(CURRENT_RUSTC_VERSION) } pub fn is_builtin_attr(attr: &Attribute) -> bool { @@ -143,13 +146,24 @@ pub enum StabilityLevel { /// `#[stable]` Stable { /// Rust release which stabilized this feature. - since: Symbol, + since: Since, /// Is this item allowed to be referred to on stable, despite being contained in unstable /// modules? allowed_through_unstable_modules: bool, }, } +/// Rust release in which a feature is stabilized. +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] +#[derive(HashStable_Generic)] +pub enum Since { + Version(Version), + /// Stabilized in the upcoming version, whatever number that is. + Current, + /// Failed to parse a stabilization version. + Err, +} + impl StabilityLevel { pub fn is_unstable(&self) -> bool { matches!(self, StabilityLevel::Unstable { .. }) @@ -361,25 +375,34 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit } } - if let Some(s) = since - && s.as_str() == VERSION_PLACEHOLDER - { - since = Some(rust_version_symbol()); - } + let feature = match feature { + Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), + Some(_bad_feature) => { + Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span })) + } + None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })), + }; + + let since = if let Some(since) = since { + if since.as_str() == VERSION_PLACEHOLDER { + Since::Current + } else if let Some(version) = parse_version(since.as_str(), false) { + Since::Version(version) + } else { + sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); + Since::Err + } + } else { + sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); + Since::Err + }; - match (feature, since) { - (Some(feature), Some(since)) => { + match feature { + Ok(feature) => { let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false }; Some((feature, level)) } - (None, _) => { - sess.emit_err(session_diagnostics::MissingFeature { span: attr.span }); - None - } - _ => { - sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); - None - } + Err(ErrorGuaranteed { .. }) => None, } } @@ -451,12 +474,19 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil } } - match (feature, reason, issue) { - (Some(feature), reason, Some(_)) => { - if !rustc_lexer::is_ident(feature.as_str()) { - sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }); - return None; - } + let feature = match feature { + Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), + Some(_bad_feature) => { + Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span })) + } + None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })), + }; + + let issue = + issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span })); + + match (feature, issue) { + (Ok(feature), Ok(_)) => { let level = StabilityLevel::Unstable { reason: UnstableReason::from_opt_reason(reason), issue: issue_num, @@ -465,14 +495,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil }; Some((feature, level)) } - (None, _, _) => { - sess.emit_err(session_diagnostics::MissingFeature { span: attr.span }); - return None; - } - _ => { - sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }); - return None; - } + (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None, } } @@ -548,11 +571,12 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F } } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -struct Version { - major: u16, - minor: u16, - patch: u16, +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(HashStable_Generic)] +pub struct Version { + pub major: u16, + pub minor: u16, + pub patch: u16, } fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> { @@ -568,6 +592,12 @@ fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> { Some(Version { major, minor, patch }) } +impl Display for Version { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch) + } +} + /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. pub fn eval_condition( @@ -601,7 +631,7 @@ pub fn eval_condition( sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span }); return false; }; - let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap(); + let rustc_version = parse_version(CURRENT_RUSTC_VERSION, true).unwrap(); // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details if sess.assume_incomplete_release { diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 86f27254db2..ca9bbd28b95 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -371,6 +371,13 @@ pub(crate) struct ExpectsFeatures { } #[derive(Diagnostic)] +#[diag(attr_invalid_since)] +pub(crate) struct InvalidSince { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(attr_soft_no_args)] pub(crate) struct SoftNoArgs { #[primary_span] diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b5ad02dc688..928c25d1061 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -8,7 +8,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; -use rustc_hir::{AsyncCoroutineKind, CoroutineKind, LangItem}; +use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; @@ -2506,8 +2506,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let kind = match use_span.coroutine_kind() { Some(coroutine_kind) => match coroutine_kind { CoroutineKind::Async(async_kind) => match async_kind { - AsyncCoroutineKind::Block => "async block", - AsyncCoroutineKind::Closure => "async closure", + CoroutineSource::Block => "async block", + CoroutineSource::Closure => "async closure", _ => bug!("async block/closure expected, but async function found."), }, CoroutineKind::Coroutine => "coroutine", diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index de9ece3faba..e630ac7c4fa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -682,9 +682,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { }; let mir_description = match hir.body(body).coroutine_kind { Some(hir::CoroutineKind::Async(gen)) => match gen { - hir::AsyncCoroutineKind::Block => " of async block", - hir::AsyncCoroutineKind::Closure => " of async closure", - hir::AsyncCoroutineKind::Fn => { + hir::CoroutineSource::Block => " of async block", + hir::CoroutineSource::Closure => " of async closure", + hir::CoroutineSource::Fn => { let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id); let output = &parent_item diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 5d6f5cc8967..ec0131c5349 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -81,6 +81,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { + if matches!(ty_context, TyContext::ReturnTy(_)) { + // We will renumber the return ty when called again with `TyContext::LocalDecl` + return; + } *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context)); debug!(?ty); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 7252658d460..aa1ce1b929d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -37,8 +37,9 @@ //! following snippet //! //! ```rust -//! # #![allow(dead_code)] -//! struct A { x : i32 } +//! struct A { +//! x: i32, +//! } //! //! struct B(i32); //! @@ -74,6 +75,7 @@ //! trait PartialEq { //! fn eq(&self, other: &Self) -> bool; //! } +//! //! impl PartialEq for i32 { //! fn eq(&self, other: &i32) -> bool { //! *self == *other @@ -90,22 +92,22 @@ //! //! ```text //! Struct(vec![FieldInfo { -//! span: <span of x> -//! name: Some(<ident of x>), -//! self_: <expr for &self.x>, -//! other: vec![<expr for &other.x] -//! }]) +//! span: <span of x>, +//! name: Some(<ident of x>), +//! self_: <expr for &self.x>, +//! other: vec![<expr for &other.x>], +//! }]) //! ``` //! //! For the `B` impl, called with `B(a)` and `B(b)`, //! //! ```text //! Struct(vec![FieldInfo { -//! span: <span of `i32`>, -//! name: None, -//! self_: <expr for &a> -//! other: vec![<expr for &b>] -//! }]) +//! span: <span of i32>, +//! name: None, +//! self_: <expr for &a>, +//! other: vec![<expr for &b>], +//! }]) //! ``` //! //! ## Enums @@ -114,33 +116,42 @@ //! == C0(b)`, the SubstructureFields is //! //! ```text -//! EnumMatching(0, <ast::Variant for C0>, -//! vec![FieldInfo { -//! span: <span of i32> -//! name: None, -//! self_: <expr for &a>, -//! other: vec![<expr for &b>] -//! }]) +//! EnumMatching( +//! 0, +//! <ast::Variant for C0>, +//! vec![FieldInfo { +//! span: <span of i32>, +//! name: None, +//! self_: <expr for &a>, +//! other: vec![<expr for &b>], +//! }], +//! ) //! ``` //! //! For `C1 {x}` and `C1 {x}`, //! //! ```text -//! EnumMatching(1, <ast::Variant for C1>, -//! vec![FieldInfo { -//! span: <span of x> -//! name: Some(<ident of x>), -//! self_: <expr for &self.x>, -//! other: vec![<expr for &other.x>] -//! }]) +//! EnumMatching( +//! 1, +//! <ast::Variant for C1>, +//! vec![FieldInfo { +//! span: <span of x>, +//! name: Some(<ident of x>), +//! self_: <expr for &self.x>, +//! other: vec![<expr for &other.x>], +//! }], +//! ) //! ``` //! //! For the tags, //! //! ```text //! EnumTag( -//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>) +//! &[<ident of self tag>, <ident of other tag>], +//! <expr to combine with>, +//! ) //! ``` +//! //! Note that this setup doesn't allow for the brute-force "match every variant //! against every other variant" approach, which is bad because it produces a //! quadratic amount of code (see #15375). @@ -154,9 +165,13 @@ //! //! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>])) //! -//! StaticEnum(<ast::EnumDef of C>, -//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])), -//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))]) +//! StaticEnum( +//! <ast::EnumDef of C>, +//! vec![ +//! (<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])), +//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)])), +//! ], +//! ) //! ``` pub use StaticFields::*; @@ -522,7 +537,10 @@ impl<'a> TraitDef<'a> { /// Given that we are deriving a trait `DerivedTrait` for a type like: /// /// ```ignore (only-for-syntax-highlight) - /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait { + /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> + /// where + /// C: WhereTrait, + /// { /// a: A, /// b: B::Item, /// b1: <B as DeclaredTrait>::Item, @@ -535,12 +553,13 @@ impl<'a> TraitDef<'a> { /// create an impl like: /// /// ```ignore (only-for-syntax-highlight) - /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where - /// C: WhereTrait, + /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> + /// where + /// C: WhereTrait, /// A: DerivedTrait + B1 + ... + BN, /// B: DerivedTrait + B1 + ... + BN, /// C: DerivedTrait + B1 + ... + BN, - /// B::Item: DerivedTrait + B1 + ... + BN, + /// B::Item: DerivedTrait + B1 + ... + BN, /// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN, /// ... /// { @@ -676,65 +695,59 @@ impl<'a> TraitDef<'a> { } })); - { - // Extra scope required here so ty_params goes out of scope before params is moved - - let mut ty_params = params - .iter() - .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - .peekable(); - - if ty_params.peek().is_some() { - let ty_param_names: Vec<Symbol> = - ty_params.map(|ty_param| ty_param.ident.name).collect(); - - for field_ty in field_tys { - let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); - - for field_ty_param in field_ty_params { - // if we have already handled this type, skip it - if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind - && let [sole_segment] = &*p.segments - && ty_param_names.contains(&sole_segment.ident.name) - { - continue; - } - let mut bounds: Vec<_> = self - .additional_bounds - .iter() - .map(|p| { - cx.trait_bound( - p.to_path(cx, self.span, type_ident, generics), - self.is_const, - ) - }) - .collect(); - - // Require the current trait. - if !self.skip_path_as_bound { - bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); - } + let ty_param_names: Vec<Symbol> = params + .iter() + .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) + .map(|ty_param| ty_param.ident.name) + .collect(); - // Add a `Copy` bound if required. - if is_packed && self.needs_copy_as_bound_if_packed { - let p = deriving::path_std!(marker::Copy); - bounds.push(cx.trait_bound( + if !ty_param_names.is_empty() { + for field_ty in field_tys { + let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); + + for field_ty_param in field_ty_params { + // if we have already handled this type, skip it + if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind + && let [sole_segment] = &*p.segments + && ty_param_names.contains(&sole_segment.ident.name) + { + continue; + } + let mut bounds: Vec<_> = self + .additional_bounds + .iter() + .map(|p| { + cx.trait_bound( p.to_path(cx, self.span, type_ident, generics), self.is_const, - )); - } + ) + }) + .collect(); - if !bounds.is_empty() { - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_generic_params: field_ty_param.bound_generic_params, - bounded_ty: field_ty_param.ty, - bounds, - }; + // Require the current trait. + if !self.skip_path_as_bound { + bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); + } - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); - } + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + bounds.push(cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + )); + } + + if !bounds.is_empty() { + let predicate = ast::WhereBoundPredicate { + span: self.span, + bound_generic_params: field_ty_param.bound_generic_params, + bounded_ty: field_ty_param.ty, + bounds, + }; + + let predicate = ast::WherePredicate::BoundPredicate(predicate); + where_clause.predicates.push(predicate); } } } @@ -1026,6 +1039,7 @@ impl<'a> MethodDef<'a> { } /// The normal case uses field access. + /// /// ``` /// #[derive(PartialEq)] /// # struct Dummy; @@ -1038,10 +1052,12 @@ impl<'a> MethodDef<'a> { /// } /// } /// ``` + /// /// But if the struct is `repr(packed)`, we can't use something like /// `&self.x` because that might cause an unaligned ref. So for any trait /// method that takes a reference, we use a local block to force a copy. /// This requires that the field impl `Copy`. + /// /// ```rust,ignore (example) /// # struct A { x: u8, y: u8 } /// impl PartialEq for A { @@ -1053,7 +1069,7 @@ impl<'a> MethodDef<'a> { /// impl Hash for A { /// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () { /// ::core::hash::Hash::hash(&{ self.x }, state); - /// ::core::hash::Hash::hash(&{ self.y }, state) + /// ::core::hash::Hash::hash(&{ self.y }, state); /// } /// } /// ``` @@ -1107,7 +1123,9 @@ impl<'a> MethodDef<'a> { /// A2(i32) /// } /// ``` + /// /// is equivalent to: + /// /// ``` /// #![feature(core_intrinsics)] /// enum A { @@ -1119,15 +1137,15 @@ impl<'a> MethodDef<'a> { /// fn eq(&self, other: &A) -> bool { /// let __self_tag = ::core::intrinsics::discriminant_value(self); /// let __arg1_tag = ::core::intrinsics::discriminant_value(other); - /// __self_tag == __arg1_tag && - /// match (self, other) { - /// (A::A2(__self_0), A::A2(__arg1_0)) => - /// *__self_0 == *__arg1_0, + /// __self_tag == __arg1_tag + /// && match (self, other) { + /// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0, /// _ => true, /// } /// } /// } /// ``` + /// /// Creates a tag check combined with a match for a tuple of all /// `selflike_args`, with an arm for each variant with fields, possibly an /// arm for each fieldless variant (if `unify_fieldless_variants` is not @@ -1349,7 +1367,7 @@ impl<'a> MethodDef<'a> { // (Variant1, Variant1, ...) => Body1 // (Variant2, Variant2, ...) => Body2, // ... - // _ => ::core::intrinsics::unreachable() + // _ => ::core::intrinsics::unreachable(), // } let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| { let match_arg = if selflike_args.len() == 1 { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f16fe372a92..c0f6e7cb7b0 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1889,37 +1889,14 @@ fn add_linked_symbol_object( return; }; - // NOTE(nbdd0121): MSVC will hang if the input object file contains no sections, - // so add an empty section. if file.format() == object::BinaryFormat::Coff { + // NOTE(nbdd0121): MSVC will hang if the input object file contains no sections, + // so add an empty section. file.add_section(Vec::new(), ".text".into(), object::SectionKind::Text); // We handle the name decoration of COFF targets in `symbol_export.rs`, so disable the // default mangler in `object` crate. file.set_mangling(object::write::Mangling::None); - - // Add feature flags to the object file. On MSVC this is optional but LLD will complain if - // not present. - let mut feature = 0; - - if file.architecture() == object::Architecture::I386 { - // Indicate that all SEH handlers are registered in .sxdata section. - // We don't have generate any code, so we don't need .sxdata section but LLD still - // expects us to set this bit (see #96498). - // Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format - feature |= 1; - } - - file.add_symbol(object::write::Symbol { - name: "@feat.00".into(), - value: feature, - size: 0, - kind: object::SymbolKind::Data, - scope: object::SymbolScope::Compilation, - weak: false, - section: object::write::SymbolSection::Absolute, - flags: object::SymbolFlags::None, - }); } for (sym, kind) in symbols.iter() { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index c6f4bd35e29..cb60ed729c1 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -228,6 +228,35 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static if sess.target.is_like_osx { file.set_macho_build_version(macho_object_build_version_for_target(&sess.target)) } + if binary_format == BinaryFormat::Coff { + // Disable the default mangler to avoid mangling the special "@feat.00" symbol name. + let original_mangling = file.mangling(); + file.set_mangling(object::write::Mangling::None); + + let mut feature = 0; + + if file.architecture() == object::Architecture::I386 { + // When linking with /SAFESEH on x86, lld requires that all linker inputs be marked as + // safe exception handling compatible. Metadata files masquerade as regular COFF + // objects and are treated as linker inputs, despite containing no actual code. Thus, + // they still need to be marked as safe exception handling compatible. See #96498. + // Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format + feature |= 1; + } + + file.add_symbol(object::write::Symbol { + name: "@feat.00".into(), + value: feature, + size: 0, + kind: object::SymbolKind::Data, + scope: object::SymbolScope::Compilation, + weak: false, + section: object::write::SymbolSection::Absolute, + flags: object::SymbolFlags::None, + }); + + file.set_mangling(original_mangling); + } let e_flags = match architecture { Architecture::Mips => { let arch = match sess.target.options.cpu.as_ref() { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index e401f6bbcbf..5900c764073 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; -use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Mutability}; +use rustc_hir::{CoroutineKind, CoroutineSource, Mutability}; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; @@ -560,9 +560,9 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: & fn coroutine_kind_label(coroutine_kind: Option<CoroutineKind>) -> &'static str { match coroutine_kind { - Some(CoroutineKind::Async(AsyncCoroutineKind::Block)) => "async_block", - Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) => "async_closure", - Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) => "async_fn", + Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block", + Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure", + Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn", Some(CoroutineKind::Coroutine) => "coroutine", None => "closure", } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index baf6b19d3f9..13a3f432b03 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -342,6 +342,19 @@ const CSKY_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("hard-float-abi", Some(sym::csky_target_feature)), // tidy-alphabetical-end ]; + +const LOONGARCH_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ + // tidy-alphabetical-start + ("d", Some(sym::loongarch_target_feature)), + ("f", Some(sym::loongarch_target_feature)), + ("lasx", Some(sym::loongarch_target_feature)), + ("lbt", Some(sym::loongarch_target_feature)), + ("lsx", Some(sym::loongarch_target_feature)), + ("lvz", Some(sym::loongarch_target_feature)), + ("ual", Some(sym::loongarch_target_feature)), + // tidy-alphabetical-end +]; + /// When rustdoc is running, provide a list of all known features so that all their respective /// primitives may be documented. /// @@ -358,6 +371,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol .chain(WASM_ALLOWED_FEATURES.iter()) .chain(BPF_ALLOWED_FEATURES.iter()) .chain(CSKY_ALLOWED_FEATURES) + .chain(LOONGARCH_ALLOWED_FEATURES) .cloned() } @@ -373,6 +387,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES, "bpf" => BPF_ALLOWED_FEATURES, "csky" => CSKY_ALLOWED_FEATURES, + "loongarch64" => LOONGARCH_ALLOWED_FEATURES, _ => &[], } } @@ -445,6 +460,7 @@ pub fn from_target_feature( Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature, Some(sym::csky_target_feature) => rust_features.csky_target_feature, + Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 1202b0030ca..ec0af79459c 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1010,7 +1010,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Just make this an efficient immediate. // Note that not calling `layout_of` here does have one real consequence: // if the type is too big, we'll only notice this when the local is actually initialized, - // which is a bit too late -- we should ideally notice this alreayd here, when the memory + // which is a bit too late -- we should ideally notice this already here, when the memory // is conceptually allocated. But given how rare that error is and that this is a hot function, // we accept this downside for now. Operand::Immediate(Immediate::Uninit) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 616fab8fe7d..40183baccf8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -360,7 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { pub struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 { + if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 { Status::Unstable(sym::const_async_blocks) } else { Status::Forbidden @@ -372,8 +372,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind()); - if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 { + let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind()); + if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 { ccx.tcx.sess.create_feature_err( errors::UnallowedOpInConstContext { span, msg }, sym::const_async_blocks, diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index d3bd3244a52..39462112dc2 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -1,5 +1,6 @@ driver_impl_ice = the compiler unexpectedly panicked. this is a bug. driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} +driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden driver_impl_ice_flags = compiler flags: {$flags} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 7e4a7d93210..331843ab051 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -60,7 +60,7 @@ use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::OnceLock; +use std::sync::{Arc, OnceLock}; use std::time::{Instant, SystemTime}; use time::OffsetDateTime; @@ -223,11 +223,18 @@ pub struct RunCompiler<'a, 'b> { file_loader: Option<Box<dyn FileLoader + Send + Sync>>, make_codegen_backend: Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>, + using_internal_features: Arc<std::sync::atomic::AtomicBool>, } impl<'a, 'b> RunCompiler<'a, 'b> { pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self { - Self { at_args, callbacks, file_loader: None, make_codegen_backend: None } + Self { + at_args, + callbacks, + file_loader: None, + make_codegen_backend: None, + using_internal_features: Arc::default(), + } } /// Set a custom codegen backend. @@ -259,9 +266,23 @@ impl<'a, 'b> RunCompiler<'a, 'b> { self } + /// Set the session-global flag that checks whether internal features have been used, + /// suppressing the message about submitting an issue in ICEs when enabled. + #[must_use] + pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self { + self.using_internal_features = using_internal_features; + self + } + /// Parse args and run the compiler. pub fn run(self) -> interface::Result<()> { - run_compiler(self.at_args, self.callbacks, self.file_loader, self.make_codegen_backend) + run_compiler( + self.at_args, + self.callbacks, + self.file_loader, + self.make_codegen_backend, + self.using_internal_features, + ) } } @@ -272,6 +293,7 @@ fn run_compiler( make_codegen_backend: Option< Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, >, + using_internal_features: Arc<std::sync::atomic::AtomicBool>, ) -> interface::Result<()> { let mut early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default()); @@ -316,6 +338,7 @@ fn run_compiler( override_queries: None, make_codegen_backend, registry: diagnostics_registry(), + using_internal_features, expanded_args: args, }; @@ -1333,8 +1356,12 @@ fn ice_path() -> &'static Option<PathBuf> { /// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to /// extra_info. /// +/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to +/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering +/// internal features. +/// /// A custom rustc driver can skip calling this to set up a custom ICE hook. -pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) { +pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) -> Arc<AtomicBool> { // If the user has not explicitly overridden "RUST_BACKTRACE", then produce // full backtraces. When a compiler ICE happens, we want to gather // as much information as possible to present in the issue opened @@ -1345,6 +1372,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) std::env::set_var("RUST_BACKTRACE", "full"); } + let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default()); + let using_internal_features_hook = using_internal_features.clone(); panic::update_hook(Box::new( move |default_hook: &(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static), info: &PanicInfo<'_>| { @@ -1394,9 +1423,11 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) } // Print the ICE message - report_ice(info, bug_report_url, extra_info); + report_ice(info, bug_report_url, extra_info, &using_internal_features_hook); }, )); + + using_internal_features } /// Prints the ICE message, including query stack, but without backtrace. @@ -1405,7 +1436,12 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) /// /// When `install_ice_hook` is called, this function will be called as the panic /// hook. -fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) { +fn report_ice( + info: &panic::PanicInfo<'_>, + bug_report_url: &str, + extra_info: fn(&Handler), + using_internal_features: &AtomicBool, +) { let fallback_bundle = rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( @@ -1422,7 +1458,11 @@ fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn( handler.emit_err(session_diagnostics::Ice); } - handler.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { + handler.emit_note(session_diagnostics::IceBugReportInternalFeature); + } else { + handler.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + } let version = util::version_str!().unwrap_or("unknown_version"); let triple = config::host_triple(); @@ -1506,7 +1546,7 @@ pub fn main() -> ! { init_rustc_env_logger(&handler); signal_handler::install(); let mut callbacks = TimePassesCallbacks::default(); - install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); + let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); let exit_code = catch_with_exit_code(|| { let args = env::args_os() .enumerate() @@ -1516,7 +1556,9 @@ pub fn main() -> ! { }) }) .collect::<Vec<_>>(); - RunCompiler::new(&args, &mut callbacks).run() + RunCompiler::new(&args, &mut callbacks) + .set_using_internal_features(using_internal_features) + .run() }); if let Some(format) = callbacks.time_passes { diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 442989f8de8..2b31fdd77cc 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -43,6 +43,10 @@ pub(crate) struct IceBugReport<'a> { } #[derive(Diagnostic)] +#[diag(driver_impl_ice_bug_report_internal_feature)] +pub(crate) struct IceBugReportInternalFeature; + +#[derive(Diagnostic)] #[diag(driver_impl_ice_version)] pub(crate) struct IceVersion<'a> { pub version: &'a str, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b73c7593381..bef48765937 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -35,7 +35,7 @@ pub struct StripUnconfigured<'a> { pub lint_node_id: NodeId, } -pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { +pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features { fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> { if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() @@ -167,6 +167,15 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { // If the declared feature is unstable, record it. if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) { (f.set_enabled)(&mut features); + // When the ICE comes from core, alloc or std (approximation of the standard library), there's a chance + // that the person hitting the ICE may be using -Zbuild-std or similar with an untested target. + // The bug is probably in the standard library and not the compiler in that case, but that doesn't + // really matter - we want a bug report. + if features.internal(name) + && ![sym::core, sym::alloc, sym::std].contains(&crate_name) + { + sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); + } features.set_declared_lang_feature(name, mi.span(), None); continue; } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8185a8a3e43..695de54eefa 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -288,6 +288,7 @@ declare_features! ( (unstable, csky_target_feature, "1.73.0", Some(44839), None), (unstable, ermsb_target_feature, "1.49.0", Some(44839), None), (unstable, hexagon_target_feature, "1.27.0", Some(44839), None), + (unstable, loongarch_target_feature, "1.73.0", Some(44839), None), (unstable, mips_target_feature, "1.27.0", Some(44839), None), (unstable, powerpc_target_feature, "1.27.0", Some(44839), None), (unstable, riscv_target_feature, "1.45.0", Some(44839), None), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f8d55192a37..259af4f565b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1511,7 +1511,7 @@ impl<'hir> Body<'hir> { #[derive(HashStable_Generic, Encodable, Decodable)] pub enum CoroutineKind { /// An explicit `async` block or the body of an async function. - Async(AsyncCoroutineKind), + Async(CoroutineSource), /// A coroutine literal created via a `yield` inside a closure. Coroutine, @@ -1520,56 +1520,45 @@ pub enum CoroutineKind { impl fmt::Display for CoroutineKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - CoroutineKind::Async(k) => fmt::Display::fmt(k, f), + CoroutineKind::Async(k) => { + if f.alternate() { + f.write_str("`async` ")?; + } else { + f.write_str("async ")? + } + k.fmt(f) + } CoroutineKind::Coroutine => f.write_str("coroutine"), } } } -impl CoroutineKind { - pub fn descr(&self) -> &'static str { - match self { - CoroutineKind::Async(ask) => ask.descr(), - CoroutineKind::Coroutine => "coroutine", - } - } -} - -/// In the case of a coroutine created as part of an async construct, -/// which kind of async construct caused it to be created? +/// In the case of a coroutine created as part of an async/gen construct, +/// which kind of async/gen construct caused it to be created? /// /// This helps error messages but is also used to drive coercions in /// type-checking (see #60424). #[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)] #[derive(HashStable_Generic, Encodable, Decodable)] -pub enum AsyncCoroutineKind { - /// An explicit `async` block written by the user. +pub enum CoroutineSource { + /// An explicit `async`/`gen` block written by the user. Block, - /// An explicit `async` closure written by the user. + /// An explicit `async`/`gen` closure written by the user. Closure, - /// The `async` block generated as the body of an async function. + /// The `async`/`gen` block generated as the body of an async/gen function. Fn, } -impl fmt::Display for AsyncCoroutineKind { +impl fmt::Display for CoroutineSource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - AsyncCoroutineKind::Block => "async block", - AsyncCoroutineKind::Closure => "async closure body", - AsyncCoroutineKind::Fn => "async fn body", - }) - } -} - -impl AsyncCoroutineKind { - pub fn descr(&self) -> &'static str { match self { - AsyncCoroutineKind::Block => "`async` block", - AsyncCoroutineKind::Closure => "`async` closure body", - AsyncCoroutineKind::Fn => "`async fn` body", + CoroutineSource::Block => "block", + CoroutineSource::Closure => "closure body", + CoroutineSource::Fn => "fn body", } + .fmt(f) } } @@ -3781,6 +3770,7 @@ impl<'hir> Node<'hir> { ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => Some(ty), + ItemKind::Impl(impl_item) => Some(&impl_item.self_ty), _ => None, }, Node::TraitItem(it) => match it.kind { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index cdfc67d5740..c8ac95e2994 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -210,6 +210,7 @@ language_item_table! { FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; + Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); CoroutineState, sym::coroutine_state, gen_state, Target::Enum, GenericRequirement::None; Coroutine, sym::coroutine, gen_trait, Target::Trait, GenericRequirement::Minimum(1); diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 6bf6650986a..e8d9918be22 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -72,6 +72,12 @@ hir_analysis_copy_impl_on_type_with_dtor = the trait `Copy` cannot be implemented for this type; the type has a destructor .label = `Copy` not allowed on types with destructors +hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type, not `{$self_ty}` + .label = can't implement cross-crate trait with a default impl for non-struct/enum type + +hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate + .label = can't implement cross-crate trait for type in another crate + hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced .coercions_note = currently, {$number} fields need coercions: {$coercions} @@ -237,6 +243,28 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args +hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types + +hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait + +hir_analysis_only_current_traits_label = impl doesn't use only types from inside the current crate + +hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign + +hir_analysis_only_current_traits_note = define and implement a trait or new type instead + +hir_analysis_only_current_traits_opaque = type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate + +hir_analysis_only_current_traits_outside = only traits defined in the current crate can be implemented for types defined outside of the crate + +hir_analysis_only_current_traits_pointer = `{$pointer}` is not defined in the current crate because raw pointers are always foreign + +hir_analysis_only_current_traits_pointer_sugg = consider introducing a new wrapper type + +hir_analysis_only_current_traits_primitive = only traits defined in the current crate can be implemented for primitive types + +hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate + hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it @@ -326,6 +354,9 @@ hir_analysis_trait_object_declared_with_no_traits = at least one trait is required for an object type .alias_span = this alias does not contain a trait +hir_analysis_traits_with_defualt_impl = traits with a default impl, like `{$traits}`, cannot be implemented for {$problematic_kind} `{$self_ty}` + .note = a trait object implements `{$traits}` if and only if `{$traits}` is one of the trait object's trait bounds + hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number} .label = needs exactly one variant, but has {$number} .many_label = too many variants in `{$path}` @@ -339,6 +370,16 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de .label = needs at most one field with non-trivial size or alignment, but has {$field_count} .labels = this field has non-zero size or requires alignment +hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`) + .label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`) + .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + .case_note = in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last + +hir_analysis_ty_param_some = type parameter `{$param_ty}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param_ty}>`) + .label = type parameter `{$param_ty}` must be used as the type parameter for some local type + .note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local + .only_note = only traits defined in the current crate can be implemented for a type parameter + hir_analysis_type_of = {$type_of} hir_analysis_typeof_reserved_keyword_used = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 360d31b863c..e61ca232de6 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -128,7 +128,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b let param_env = tcx.param_env(item_def_id); for field in &def.non_enum_variant().fields { - let field_ty = tcx.normalize_erasing_regions(param_env, field.ty(tcx, args)); + let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args)) + else { + tcx.sess.delay_span_bug(span, "could not normalize field type"); + continue; + }; if !allowed_union_field(field_ty, tcx, param_env) { let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index faddb0c3829..7eeb7837467 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -2,8 +2,7 @@ //! crate or pertains to a type defined in this crate. use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, DelayDm}; -use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_errors::{DelayDm, ErrorGuaranteed}; use rustc_hir as hir; use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::GenericArgs; @@ -17,6 +16,8 @@ use rustc_span::Span; use rustc_trait_selection::traits; use std::ops::ControlFlow; +use crate::errors; + #[instrument(skip(tcx), level = "debug")] pub(crate) fn orphan_check_impl( tcx: TyCtxt<'_>, @@ -259,49 +260,30 @@ fn do_orphan_check_impl<'tcx>( match local_impl { LocalImpl::Allow => {} LocalImpl::Disallow { problematic_kind } => { - let msg = format!( - "traits with a default impl, like `{trait}`, \ - cannot be implemented for {problematic_kind} `{self_ty}`", - trait = tcx.def_path_str(trait_def_id), - ); - let label = format!( - "a trait object implements `{trait}` if and only if `{trait}` \ - is one of the trait object's trait bounds", - trait = tcx.def_path_str(trait_def_id), - ); - let sp = tcx.def_span(def_id); - let reported = - struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit(); - return Err(reported); + return Err(tcx.sess.emit_err(errors::TraitsWithDefaultImpl { + span: tcx.def_span(def_id), + traits: tcx.def_path_str(trait_def_id), + problematic_kind, + self_ty, + })); } } } else { - if let Some((msg, label)) = match nonlocal_impl { - NonlocalImpl::Allow => None, - NonlocalImpl::DisallowBecauseNonlocal => Some(( - format!( - "cross-crate traits with a default impl, like `{}`, \ - can only be implemented for a struct/enum type \ - defined in the current crate", - tcx.def_path_str(trait_def_id) - ), - "can't implement cross-crate trait for type in another crate", - )), - NonlocalImpl::DisallowOther => Some(( - format!( - "cross-crate traits with a default impl, like `{}`, can \ - only be implemented for a struct/enum type, not `{}`", - tcx.def_path_str(trait_def_id), - self_ty - ), - "can't implement cross-crate trait with a default impl for \ - non-struct/enum type", - )), - } { - let sp = tcx.def_span(def_id); - let reported = - struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit(); - return Err(reported); + match nonlocal_impl { + NonlocalImpl::Allow => {} + NonlocalImpl::DisallowBecauseNonlocal => { + return Err(tcx.sess.emit_err(errors::CrossCrateTraitsDefined { + span: tcx.def_span(def_id), + traits: tcx.def_path_str(trait_def_id), + })); + } + NonlocalImpl::DisallowOther => { + return Err(tcx.sess.emit_err(errors::CrossCrateTraits { + span: tcx.def_span(def_id), + traits: tcx.def_path_str(trait_def_id), + self_ty, + })); + } } } } @@ -322,19 +304,18 @@ fn emit_orphan_check_error<'tcx>( let self_ty = trait_ref.self_ty(); Err(match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { - let msg = match self_ty.kind() { - ty::Adt(..) => "can be implemented for types defined outside of the crate", - _ if self_ty.is_primitive() => "can be implemented for primitive types", - _ => "can be implemented for arbitrary types", - }; - let mut err = struct_span_err!( - tcx.sess, - sp, - E0117, - "only traits defined in the current crate {msg}" - ); - err.span_label(sp, "impl doesn't use only types from inside the current crate"); + let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) = + (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()); + let mut sugg = None; for &(mut ty, is_target_ty) in &tys { + let span = if is_target_ty { + // Point at `D<A>` in `impl<A, B> for C<B> in D<A>` + self_ty_span + } else { + // Point at `C<B>` in `impl<A, B> for C<B> in D<A>` + trait_span + }; + ty = tcx.erase_regions(ty); ty = match ty.kind() { // Remove the type arguments from the output, as they are not relevant. @@ -345,50 +326,103 @@ fn emit_orphan_check_error<'tcx>( ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()), _ => ty, }; - let msg = |ty: &str, postfix: &str| { - format!("{ty} is not defined in the current crate{postfix}") - }; - let this = |name: &str| { - if !trait_ref.def_id.is_local() && !is_target_ty { - msg("this", " because this is a foreign trait") + fn push_to_foreign_or_name<'tcx>( + is_foreign: bool, + foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>, + name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>, + span: Span, + sname: &'tcx str, + ) { + if is_foreign { + foreign.push(errors::OnlyCurrentTraitsForeign { span }) } else { - msg("this", &format!(" because {name} are always foreign")) + name.push(errors::OnlyCurrentTraitsName { span, name: sname }); + } + } + + let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty; + + match &ty.kind() { + ty::Slice(_) => { + push_to_foreign_or_name( + is_foreign, + &mut foreign, + &mut name, + span, + "slices", + ); + } + ty::Array(..) => { + push_to_foreign_or_name( + is_foreign, + &mut foreign, + &mut name, + span, + "arrays", + ); + } + ty::Tuple(..) => { + push_to_foreign_or_name( + is_foreign, + &mut foreign, + &mut name, + span, + "tuples", + ); } - }; - let msg = match &ty.kind() { - ty::Slice(_) => this("slices"), - ty::Array(..) => this("arrays"), - ty::Tuple(..) => this("tuples"), ty::Alias(ty::Opaque, ..) => { - "type alias impl trait is treated as if it were foreign, \ - because its hidden type could be from a foreign crate" - .to_string() + opaque.push(errors::OnlyCurrentTraitsOpaque { span }) } ty::RawPtr(ptr_ty) => { - emit_newtype_suggestion_for_raw_ptr( - full_impl_span, - self_ty, - self_ty_span, - ptr_ty, - &mut err, - ); - - msg(&format!("`{ty}`"), " because raw pointers are always foreign") + if !self_ty.has_param() { + let mut_key = ptr_ty.mutbl.prefix_str(); + sugg = Some(errors::OnlyCurrentTraitsPointerSugg { + wrapper_span: self_ty_span, + struct_span: full_impl_span.shrink_to_lo(), + mut_key, + ptr_ty: ptr_ty.ty, + }); + } + pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty }); } - _ => msg(&format!("`{ty}`"), ""), - }; - - if is_target_ty { - // Point at `D<A>` in `impl<A, B> for C<B> in D<A>` - err.span_label(self_ty_span, msg); - } else { - // Point at `C<B>` in `impl<A, B> for C<B> in D<A>` - err.span_label(trait_span, msg); + _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }), } } - err.note("define and implement a trait or new type instead"); - err.emit() + + let err_struct = match self_ty.kind() { + ty::Adt(..) => errors::OnlyCurrentTraits::Outside { + span: sp, + note: (), + opaque, + foreign, + name, + pointer, + ty: ty_diag, + sugg, + }, + _ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive { + span: sp, + note: (), + opaque, + foreign, + name, + pointer, + ty: ty_diag, + sugg, + }, + _ => errors::OnlyCurrentTraits::Arbitrary { + span: sp, + note: (), + opaque, + foreign, + name, + pointer, + ty: ty_diag, + sugg, + }, + }; + tcx.sess.emit_err(err_struct) } traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { let mut sp = sp; @@ -399,85 +433,18 @@ fn emit_orphan_check_error<'tcx>( } match local_type { - Some(local_type) => struct_span_err!( - tcx.sess, - sp, - E0210, - "type parameter `{}` must be covered by another type \ - when it appears before the first local type (`{}`)", - param_ty, - local_type - ) - .span_label( - sp, - format!( - "type parameter `{param_ty}` must be covered by another type \ - when it appears before the first local type (`{local_type}`)" - ), - ) - .note( - "implementing a foreign trait is only possible if at \ - least one of the types for which it is implemented is local, \ - and no uncovered type parameters appear before that first \ - local type", - ) - .note( - "in this case, 'before' refers to the following order: \ - `impl<..> ForeignTrait<T1, ..., Tn> for T0`, \ - where `T0` is the first and `Tn` is the last", - ) - .emit(), - None => struct_span_err!( - tcx.sess, - sp, - E0210, - "type parameter `{}` must be used as the type parameter for some \ - local type (e.g., `MyStruct<{}>`)", + Some(local_type) => tcx.sess.emit_err(errors::TyParamFirstLocal { + span: sp, + note: (), param_ty, - param_ty - ) - .span_label( - sp, - format!( - "type parameter `{param_ty}` must be used as the type parameter for some \ - local type", - ), - ) - .note( - "implementing a foreign trait is only possible if at \ - least one of the types for which it is implemented is local", - ) - .note( - "only traits defined in the current crate can be \ - implemented for a type parameter", - ) - .emit(), + local_type, + }), + None => tcx.sess.emit_err(errors::TyParamSome { span: sp, note: (), param_ty }), } } }) } -fn emit_newtype_suggestion_for_raw_ptr( - full_impl_span: Span, - self_ty: Ty<'_>, - self_ty_span: Span, - ptr_ty: &ty::TypeAndMut<'_>, - diag: &mut Diagnostic, -) { - if !self_ty.has_param() { - let mut_key = ptr_ty.mutbl.prefix_str(); - let msg_sugg = "consider introducing a new wrapper type".to_owned(); - let sugg = vec![ - ( - full_impl_span.shrink_to_lo(), - format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty), - ), - (self_ty_span, "WrapperType".to_owned()), - ]; - diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect); - } -} - /// Lint impls of auto traits if they are likely to have /// unsound or surprising effects on auto impls. fn lint_auto_trait_impl<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 189564d4e33..6a2db1d0627 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -683,7 +683,6 @@ pub(crate) struct SIMDFFIHighlyExperimental { } #[derive(Diagnostic)] - pub enum ImplNotMarkedDefault { #[diag(hir_analysis_impl_not_marked_default, code = "E0520")] #[note] @@ -1159,3 +1158,174 @@ pub struct ImplForTyRequires { pub trait_name: String, pub ty: String, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")] +#[note] +pub struct TraitsWithDefaultImpl<'a> { + #[primary_span] + pub span: Span, + pub traits: String, + pub problematic_kind: &'a str, + pub self_ty: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_cross_crate_traits, code = "E0321")] +pub struct CrossCrateTraits<'a> { + #[primary_span] + #[label] + pub span: Span, + pub traits: String, + pub self_ty: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")] +pub struct CrossCrateTraitsDefined { + #[primary_span] + #[label] + pub span: Span, + pub traits: String, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_ty_param_first_local, code = "E0210")] +#[note] +pub struct TyParamFirstLocal<'a> { + #[primary_span] + #[label] + pub span: Span, + #[note(hir_analysis_case_note)] + pub note: (), + pub param_ty: Ty<'a>, + pub local_type: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_ty_param_some, code = "E0210")] +#[note] +pub struct TyParamSome<'a> { + #[primary_span] + #[label] + pub span: Span, + #[note(hir_analysis_only_note)] + pub note: (), + pub param_ty: Ty<'a>, +} + +#[derive(Diagnostic)] +pub enum OnlyCurrentTraits<'a> { + #[diag(hir_analysis_only_current_traits_outside, code = "E0117")] + Outside { + #[primary_span] + #[label(hir_analysis_only_current_traits_label)] + span: Span, + #[note(hir_analysis_only_current_traits_note)] + note: (), + #[subdiagnostic] + opaque: Vec<OnlyCurrentTraitsOpaque>, + #[subdiagnostic] + foreign: Vec<OnlyCurrentTraitsForeign>, + #[subdiagnostic] + name: Vec<OnlyCurrentTraitsName<'a>>, + #[subdiagnostic] + pointer: Vec<OnlyCurrentTraitsPointer<'a>>, + #[subdiagnostic] + ty: Vec<OnlyCurrentTraitsTy<'a>>, + #[subdiagnostic] + sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>, + }, + #[diag(hir_analysis_only_current_traits_primitive, code = "E0117")] + Primitive { + #[primary_span] + #[label(hir_analysis_only_current_traits_label)] + span: Span, + #[note(hir_analysis_only_current_traits_note)] + note: (), + #[subdiagnostic] + opaque: Vec<OnlyCurrentTraitsOpaque>, + #[subdiagnostic] + foreign: Vec<OnlyCurrentTraitsForeign>, + #[subdiagnostic] + name: Vec<OnlyCurrentTraitsName<'a>>, + #[subdiagnostic] + pointer: Vec<OnlyCurrentTraitsPointer<'a>>, + #[subdiagnostic] + ty: Vec<OnlyCurrentTraitsTy<'a>>, + #[subdiagnostic] + sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>, + }, + #[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")] + Arbitrary { + #[primary_span] + #[label(hir_analysis_only_current_traits_label)] + span: Span, + #[note(hir_analysis_only_current_traits_note)] + note: (), + #[subdiagnostic] + opaque: Vec<OnlyCurrentTraitsOpaque>, + #[subdiagnostic] + foreign: Vec<OnlyCurrentTraitsForeign>, + #[subdiagnostic] + name: Vec<OnlyCurrentTraitsName<'a>>, + #[subdiagnostic] + pointer: Vec<OnlyCurrentTraitsPointer<'a>>, + #[subdiagnostic] + ty: Vec<OnlyCurrentTraitsTy<'a>>, + #[subdiagnostic] + sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>, + }, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_opaque)] +pub struct OnlyCurrentTraitsOpaque { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_foreign)] +pub struct OnlyCurrentTraitsForeign { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_name)] +pub struct OnlyCurrentTraitsName<'a> { + #[primary_span] + pub span: Span, + pub name: &'a str, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_pointer)] +pub struct OnlyCurrentTraitsPointer<'a> { + #[primary_span] + pub span: Span, + pub pointer: Ty<'a>, +} + +#[derive(Subdiagnostic)] +#[label(hir_analysis_only_current_traits_ty)] +pub struct OnlyCurrentTraitsTy<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + hir_analysis_only_current_traits_pointer_sugg, + applicability = "maybe-incorrect" +)] +pub struct OnlyCurrentTraitsPointerSugg<'a> { + #[suggestion_part(code = "WrapperType")] + pub wrapper_span: Span, + #[suggestion_part(code = "struct WrapperType(*{mut_key}{ptr_ty});\n\n")] + pub struct_span: Span, + pub mut_key: &'a str, + pub ptr_ty: Ty<'a>, +} diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 0622aa2ee80..2b8219c01c7 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -182,13 +182,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { } tcx.sess.track_errors(|| { - tcx.sess.time("impl_wf_inference", || { - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)) - }); - })?; - - tcx.sess.track_errors(|| { tcx.sess.time("coherence_checking", || { + // Check impls constrain their parameters + tcx.hir().for_each_module(|module| tcx.ensure().check_mod_impl_wf(module)); + for &trait_def_id in tcx.all_local_trait_impls(()).keys() { tcx.ensure().coherent_trait(trait_def_id); } @@ -205,15 +202,19 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { })?; } - tcx.sess.time("wf_checking", || { + let errs = tcx.sess.time("wf_checking", || { tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) - })?; + }); // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync. tcx.sess.time("item_types_checking", || { tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) }); + // HACK: `check_mod_type_wf` may spuriously emit errors due to `delay_span_bug`, even if those errors + // only actually get emitted in `check_mod_item_types`. + errs?; + if tcx.features().rustc_attrs { tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?; } diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 2b5f6fd214c..76bd370a641 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if self.missing_lifetimes() { "lifetime" } else { "generic" } } + /// Returns true if the generic type is a trait + /// and is being referred to from one of its trait impls + fn is_in_trait_impl(&self) -> bool { + if self.tcx.is_trait(self.def_id) { + // Here we check if the reference to the generic type + // is from the 'of_trait' field of the enclosing impl + + let parent = self.tcx.hir().get_parent(self.path_segment.hir_id); + let parent_item = self + .tcx + .hir() + .get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id); + + // Get the HIR id of the trait ref + let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else { + return false; + }; + + // Get the HIR id of the 'of_trait' field of the impl + let hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Impl(hir::Impl { + of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }), + .. + }), + .. + }) = parent_item + else { + return false; + }; + + // Check that trait is referred to from the of_trait field of impl + trait_ref_id == id_in_of_trait + } else { + false + } + } + fn num_provided_args(&self) -> usize { if self.missing_lifetimes() { self.num_provided_lifetime_args() @@ -955,20 +993,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { // If there is a single unbound associated type and a single excess generic param // suggest replacing the generic param with the associated type bound if provided_args_matches_unbound_traits && !unbound_types.is_empty() { - let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; - let suggestions = iter::zip(unused_generics, &unbound_types) - .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = "))) - .collect::<Vec<_>>(); + // Don't suggest if we're in a trait impl as + // that would result in invalid syntax (fixes #116464) + if !self.is_in_trait_impl() { + let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; + let suggestions = iter::zip(unused_generics, &unbound_types) + .map(|(potential, name)| { + (potential.span().shrink_to_lo(), format!("{name} = ")) + }) + .collect::<Vec<_>>(); - if !suggestions.is_empty() { - err.multipart_suggestion_verbose( - format!( - "replace the generic bound{s} with the associated type{s}", - s = pluralize!(unbound_types.len()) - ), - suggestions, - Applicability::MaybeIncorrect, - ); + if !suggestions.is_empty() { + err.multipart_suggestion_verbose( + format!( + "replace the generic bound{s} with the associated type{s}", + s = pluralize!(unbound_types.len()) + ), + suggestions, + Applicability::MaybeIncorrect, + ); + } } } else if remove_entire_generics { let span = self diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 5eb68cf6b28..6b6d1574b2b 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -305,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) = (parent_node, callee_node) { let fn_decl_span = if hir.body(body).coroutine_kind - == Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure)) + == Some(hir::CoroutineKind::Async(hir::CoroutineSource::Closure)) { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index a834ea15047..ee23f47c271 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -660,9 +660,21 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else { match self.try_coercion_cast(fcx) { Ok(()) => { - self.trivial_cast_lint(fcx); - debug!(" -> CoercionCast"); - fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id); + if self.expr_ty.is_unsafe_ptr() && self.cast_ty.is_unsafe_ptr() { + // When casting a raw pointer to another raw pointer, we cannot convert the cast into + // a coercion because the pointee types might only differ in regions, which HIR typeck + // cannot distinguish. This would cause us to erroneously discard a cast which will + // lead to a borrowck error like #113257. + // We still did a coercion above to unify inference variables for `ptr as _` casts. + // This does cause us to miss some trivial casts in the trival cast lint. + debug!(" -> PointerCast"); + } else { + self.trivial_cast_lint(fcx); + debug!(" -> CoercionCast"); + fcx.typeck_results + .borrow_mut() + .set_coercion_cast(self.expr.hir_id.local_id); + } } Err(_) => { match self.do_check(fcx) { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cf8a4cafbb6..47bde21ceb2 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -636,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // In the case of the async block that we create for a function body, // we expect the return type of the block to match that of the enclosing // function. - Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn)) => { + Some(hir::CoroutineKind::Async(hir::CoroutineSource::Fn)) => { debug!("closure is async fn body"); let def_id = self.tcx.hir().body_owner_def_id(body.id()); self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else( diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 65ec2f232ae..f379e8477e3 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -58,7 +58,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_into(err, expr, expr_ty, expected) || self.suggest_floating_point_literal(err, expr, expected) || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected) - || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty); + || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty) + || self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty); if !suggested { self.note_source_of_type_mismatch_constraint( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index afa5a3b9379..b5a07f0d3e9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -26,7 +26,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType, + self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType, }; use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy}; use rustc_session::lint; @@ -207,6 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { debug!("fcx {}", self.tag()); + // FIXME: is_identity being on `UserType` and not `Canonical<UserType>` is awkward if !canonical_user_type_annotation.is_identity() { self.typeck_results .borrow_mut() diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 04220397872..ca7dc298de6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -6,11 +6,12 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::Res; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ - AsyncCoroutineKind, CoroutineKind, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, - Stmt, StmtKind, TyKind, WherePredicate, + CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt, + StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::traits::{self, StatementAsExpression}; @@ -535,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Coroutine(def_id, ..) if matches!( self.tcx.coroutine_kind(def_id), - Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) + Some(CoroutineKind::Async(CoroutineSource::Closure)) ) => { errors::SuggestBoxing::AsyncBody @@ -1738,4 +1739,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the field is hygienic it must come from the same syntax context. && self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span) } + + pub(crate) fn suggest_missing_unwrap_expect( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + let ty::Adt(adt, args) = found.kind() else { + return false; + }; + let ret_ty_matches = |diagnostic_item| { + let Some(sig) = self.body_fn_sig() else { + return false; + }; + let ty::Adt(kind, _) = sig.output().kind() else { + return false; + }; + self.tcx.is_diagnostic_item(diagnostic_item, kind.did()) + }; + + // don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`, + // `None.unwrap()` etc. + let is_ctor = matches!( + expr.kind, + hir::ExprKind::Call( + hir::Expr { + kind: hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. }, + )), + .. + }, + .., + ) | hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. }, + )), + ); + + let (article, kind, variant, sugg_operator) = + if self.tcx.is_diagnostic_item(sym::Result, adt.did()) { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return false; + }; + if is_ctor || !self.can_coerce(args.type_at(0), expected) { + return false; + } + + let (msg, sugg) = if sugg_operator { + ( + format!( + "use the `?` operator to extract the `{found}` value, propagating \ + {article} `{kind}::{variant}` value to the caller" + ), + "?", + ) + } else { + ( + format!( + "consider using `{kind}::expect` to unwrap the `{found}` value, \ + panicking if the value is {article} `{kind}::{variant}`" + ), + ".expect(\"REASON\")", + ) + }; + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + msg, + sugg, + Applicability::HasPlaceholders, + ); + return true; + } } diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 41787ee2942..280dcae3451 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -152,7 +152,7 @@ impl<'tcx> InferCtxt<'tcx> { ) .into(), CanonicalVarKind::Effect => { - let vid = self.inner.borrow_mut().effect_unification_table().new_key(None); + let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool) .into() } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index ee13eb0271e..2a9e20b9f8f 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -320,7 +320,7 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self))] fn unify_const_variable( &self, - target_vid: ty::ConstVid<'tcx>, + target_vid: ty::ConstVid, ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { @@ -381,7 +381,7 @@ impl<'tcx> InferCtxt<'tcx> { fn unify_effect_variable( &self, vid_is_expected: bool, - vid: ty::EffectVid<'tcx>, + vid: ty::EffectVid, val: EffectVarValue<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { self.inner diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ba118f8110f..e4be435fded 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1584,14 +1584,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { target: &str, types: &FxIndexMap<TyCategory, FxIndexSet<Span>>, ) { - for (key, values) in types.iter() { + for (kind, values) in types.iter() { let count = values.len(); - let kind = key.descr(); for &sp in values { err.span_label( sp, format!( - "{}{} {}{}", + "{}{} {:#}{}", if count == 1 { "the " } else { "one of the " }, target, kind, @@ -2952,17 +2951,19 @@ pub enum TyCategory { Foreign, } -impl TyCategory { - fn descr(&self) -> &'static str { +impl fmt::Display for TyCategory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Closure => "closure", - Self::Opaque => "opaque type", - Self::OpaqueFuture => "future", - Self::Coroutine(gk) => gk.descr(), - Self::Foreign => "foreign type", + Self::Closure => "closure".fmt(f), + Self::Opaque => "opaque type".fmt(f), + Self::OpaqueFuture => "future".fmt(f), + Self::Coroutine(gk) => gk.fmt(f), + Self::Foreign => "foreign type".fmt(f), } } +} +impl TyCategory { pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> { match *ty.kind() { ty::Closure(def_id, _) => Some((Self::Closure, def_id)), diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 0596ce373cf..35204478c54 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -42,7 +42,7 @@ pub struct TypeFreshener<'a, 'tcx> { ty_freshen_count: u32, const_freshen_count: u32, ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>, - const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>, + const_freshen_map: FxHashMap<ty::InferConst, ty::Const<'tcx>>, } impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { @@ -79,12 +79,12 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { fn freshen_const<F>( &mut self, opt_ct: Option<ty::Const<'tcx>>, - key: ty::InferConst<'tcx>, + key: ty::InferConst, freshener: F, ty: Ty<'tcx>, ) -> ty::Const<'tcx> where - F: FnOnce(u32) -> ty::InferConst<'tcx>, + F: FnOnce(u32) -> ty::InferConst, { if let Some(ct) = opt_ct { return ct.fold_with(self); diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 2f371c4fe31..7e878ac06c7 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -1,3 +1,4 @@ +use rustc_middle::infer::unify_key::ConstVidKey; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; @@ -23,14 +24,14 @@ where } fn const_vars_since_snapshot<'tcx>( - table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>, + table: &mut UnificationTable<'_, 'tcx, ConstVidKey<'tcx>>, snapshot_var_len: usize, -) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) { +) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) { let range = vars_since_snapshot(table, snapshot_var_len); ( - range.start..range.end, - (range.start.index..range.end.index) - .map(|index| table.probe_value(ConstVid::from_index(index)).origin) + range.start.vid..range.end.vid, + (range.start.index()..range.end.index()) + .map(|index| table.probe_value(ConstVid::from_u32(index)).origin) .collect(), ) } @@ -172,7 +173,7 @@ pub struct InferenceFudger<'a, 'tcx> { int_vars: Range<IntVid>, float_vars: Range<FloatVid>, region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>), - const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>), + const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>), } impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { @@ -235,7 +236,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { if self.const_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. - let idx = (vid.index - self.const_vars.0.start.index) as usize; + let idx = (vid.index() - self.const_vars.0.start.index()) as usize; let origin = self.const_vars.1[idx]; self.infcx.next_const_var(ct.ty(), origin) } else { diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs index c1e65ffe0a6..17fe3aa7b44 100644 --- a/compiler/rustc_infer/src/infer/generalize.rs +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -17,7 +17,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> infcx: &InferCtxt<'tcx>, delegate: &mut D, term: T, - for_vid: impl Into<ty::TermVid<'tcx>>, + for_vid: impl Into<ty::TermVid>, ambient_variance: ty::Variance, ) -> RelateResult<'tcx, Generalization<T>> { let (for_universe, root_vid) = match for_vid.into() { @@ -27,7 +27,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> ), ty::TermVid::Const(ct_vid) => ( infcx.probe_const_var(ct_vid).unwrap_err(), - ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)), + ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid), ), }; @@ -127,7 +127,7 @@ struct Generalizer<'me, 'tcx, D> { /// The vid of the type variable that is in the process of being /// instantiated. If we find this within the value we are folding, /// that means we would have created a cyclic value. - root_vid: ty::TermVid<'tcx>, + root_vid: ty::TermVid, /// The universe of the type variable that is in the process of being /// instantiated. If we find anything that this universe cannot name, @@ -376,7 +376,7 @@ where // `vid` are related and we'd be inferring an infinitely // deep const. if ty::TermVid::Const( - self.infcx.inner.borrow_mut().const_unification_table().find(vid), + self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid, ) == self.root_vid { return Err(self.cyclic_term_error()); @@ -394,10 +394,14 @@ where if self.for_universe.can_name(universe) { Ok(c) } else { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.for_universe }, - }); + let new_var_id = variable_table + .new_key(ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { + universe: self.for_universe, + }, + }) + .vid; Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 8ffcf1fce9c..4ee897ffe98 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -6,7 +6,9 @@ pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; pub use combine::ObligationEmittingRelation; +use rustc_data_structures::captures::Captures; use rustc_data_structures::undo_log::UndoLogs; +use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use self::opaque_types::OpaqueTypeStorage; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; @@ -40,7 +42,6 @@ use rustc_span::{Span, DUMMY_SP}; use std::cell::{Cell, RefCell}; use std::fmt; -use std::marker::PhantomData; use self::combine::CombineFields; use self::error_reporting::TypeErrCtxt; @@ -85,7 +86,7 @@ pub struct InferOk<'tcx, T> { pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" -pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result" +pub type FixupResult<T> = Result<T, FixupError>; // "fixup result" pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>, @@ -108,7 +109,7 @@ pub struct InferCtxtInner<'tcx> { type_variable_storage: type_variable::TypeVariableStorage<'tcx>, /// Map from const parameter variable to the kind of const it represents. - const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>, + const_unification_storage: ut::UnificationTableStorage<ConstVidKey<'tcx>>, /// Map from integral variable to the kind of integer it represents. int_unification_storage: ut::UnificationTableStorage<ty::IntVid>, @@ -117,7 +118,7 @@ pub struct InferCtxtInner<'tcx> { float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>, /// Map from effect variable to the effect param it represents. - effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>, + effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>, /// Tracks the set of region variables and the constraints between them. /// @@ -224,11 +225,11 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::ConstVid<'tcx>> { + fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ConstVidKey<'tcx>> { self.const_unification_storage.with_log(&mut self.undo_log) } - fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> { + fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> { self.effect_unification_storage.with_log(&mut self.undo_log) } @@ -341,7 +342,9 @@ pub struct InferCtxt<'tcx> { next_trait_solver: bool, } -impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> { +impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { + type Interner = TyCtxt<'tcx>; + fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> { use InferTy::*; match ty { @@ -357,7 +360,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> { } } - fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> { + fn universe_of_ct(&self, ct: ty::InferConst) -> Option<ty::UniverseIndex> { use ty::InferConst::*; match ct { // Same issue as with `universe_of_ty` @@ -546,11 +549,11 @@ pub enum NllRegionVariableOrigin { // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`. #[derive(Copy, Clone, Debug)] -pub enum FixupError<'tcx> { +pub enum FixupError { UnresolvedIntTy(IntVid), UnresolvedFloatTy(FloatVid), UnresolvedTy(TyVid), - UnresolvedConst(ConstVid<'tcx>), + UnresolvedConst(ConstVid), } /// See the `region_obligations` field for more information. @@ -561,7 +564,7 @@ pub struct RegionObligation<'tcx> { pub origin: SubregionOrigin<'tcx>, } -impl<'tcx> fmt::Display for FixupError<'tcx> { +impl fmt::Display for FixupError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use self::FixupError::*; @@ -792,7 +795,7 @@ impl<'tcx> InferCtxt<'tcx> { let mut table = inner.effect_unification_table(); (0..table.len()) - .map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData }) + .map(|i| ty::EffectVid::from_usize(i)) .filter(|&vid| table.probe_value(vid).is_none()) .map(|v| { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool) @@ -1070,15 +1073,20 @@ impl<'tcx> InferCtxt<'tcx> { .inner .borrow_mut() .const_unification_table() - .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); + .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }) + .vid; ty::Const::new_var(self.tcx, vid, ty) } - pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { - self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue { - origin, - val: ConstVariableValue::Unknown { universe: self.universe() }, - }) + pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid { + self.inner + .borrow_mut() + .const_unification_table() + .new_key(ConstVarValue { + origin, + val: ConstVariableValue::Unknown { universe: self.universe() }, + }) + .vid } fn next_int_var_id(&self) -> IntVid { @@ -1192,11 +1200,15 @@ impl<'tcx> InferCtxt<'tcx> { ), span, }; - let const_var_id = - self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue { + let const_var_id = self + .inner + .borrow_mut() + .const_unification_table() + .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe: self.universe() }, - }); + }) + .vid; ty::Const::new_var( self.tcx, const_var_id, @@ -1211,7 +1223,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None); + let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid; let ty = self .tcx .type_of(param.def_id) @@ -1331,12 +1343,12 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().root_var(var) } - pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> { - self.inner.borrow_mut().const_unification_table().find(var) + pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { + self.inner.borrow_mut().const_unification_table().find(var).vid } - pub fn root_effect_var(&self, var: ty::EffectVid<'tcx>) -> ty::EffectVid<'tcx> { - self.inner.borrow_mut().effect_unification_table().find(var) + pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid { + self.inner.borrow_mut().effect_unification_table().find(var).vid } /// Resolves an int var to a rigid int type, if it was constrained to one, @@ -1400,17 +1412,14 @@ impl<'tcx> InferCtxt<'tcx> { value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value() } - pub fn probe_const_var( - &self, - vid: ty::ConstVid<'tcx>, - ) -> Result<ty::Const<'tcx>, ty::UniverseIndex> { + pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> { match self.inner.borrow_mut().const_unification_table().probe_value(vid).val { ConstVariableValue::Known { value } => Ok(value), ConstVariableValue::Unknown { universe } => Err(universe), } } - pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> { + pub fn probe_effect_var(&self, vid: EffectVid) -> Option<EffectVarValue<'tcx>> { self.inner.borrow_mut().effect_unification_table().probe_value(vid) } @@ -1421,7 +1430,7 @@ impl<'tcx> InferCtxt<'tcx> { /// /// This method is idempotent, but it not typically not invoked /// except during the writeback phase. - pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> { + pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<T> { match resolve::fully_resolve(self, value) { Ok(value) => { if value.has_non_region_infer() { @@ -1645,11 +1654,11 @@ impl<'tcx> InferCtxt<'tcx> { #[inline] pub fn is_ty_infer_var_definitely_unchanged<'a>( &'a self, - ) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) { + ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'tcx> + 'a) { // This hoists the borrow/release out of the loop body. let inner = self.inner.try_borrow(); - return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) { + return move |infer_var: TyOrConstInferVar| match (infer_var, &inner) { (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { use self::type_variable::TypeVariableValue; @@ -1672,7 +1681,7 @@ impl<'tcx> InferCtxt<'tcx> { /// inference variables), and it handles both `Ty` and `ty::Const` without /// having to resort to storing full `GenericArg`s in `stalled_on`. #[inline(always)] - pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool { + pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool { match infer_var { TyOrConstInferVar::Ty(v) => { use self::type_variable::TypeVariableValue; @@ -1779,7 +1788,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently /// used only for `traits::fulfill`'s list of `stalled_on` inference variables. #[derive(Copy, Clone, Debug)] -pub enum TyOrConstInferVar<'tcx> { +pub enum TyOrConstInferVar { /// Equivalent to `ty::Infer(ty::TyVar(_))`. Ty(TyVid), /// Equivalent to `ty::Infer(ty::IntVar(_))`. @@ -1788,12 +1797,12 @@ pub enum TyOrConstInferVar<'tcx> { TyFloat(FloatVid), /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`. - Const(ConstVid<'tcx>), + Const(ConstVid), /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`. - Effect(EffectVid<'tcx>), + Effect(EffectVid), } -impl<'tcx> TyOrConstInferVar<'tcx> { +impl<'tcx> TyOrConstInferVar { /// Tries to extract an inference variable from a type or a constant, returns `None` /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 3c41e8b3783..18a9cb6b44b 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -192,7 +192,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tc /// Full type resolution replaces all type and region variables with /// their concrete results. If any variable cannot be replaced (never unified, etc) /// then an `Err` result is returned. -pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T> +pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<T> where T: TypeFoldable<TyCtxt<'tcx>>, { @@ -206,7 +206,7 @@ struct FullTypeResolver<'a, 'tcx> { } impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { - type Error = FixupError<'tcx>; + type Error = FixupError; fn interner(&self) -> TyCtxt<'tcx> { self.infcx.tcx diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 79144b3e643..5655730518e 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify as ut; -use rustc_middle::infer::unify_key::RegionVidKey; +use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey}; use crate::{ @@ -21,10 +21,10 @@ pub struct Snapshot<'tcx> { pub(crate) enum UndoLog<'tcx> { OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>), TypeVariables(type_variable::UndoLog<'tcx>), - ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), + ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), - EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>), + EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), ProjectionCache(traits::UndoLog<'tcx>), @@ -56,9 +56,9 @@ impl_from! { IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), - EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>), + EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>), - ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), + ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>), RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), ProjectionCache(traits::UndoLog<'tcx>), diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index d2ce77ad535..87badcbdf15 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -24,6 +24,7 @@ use rustc_span::source_map::{FileLoader, FileName}; use rustc_span::symbol::sym; use std::path::PathBuf; use std::result; +use std::sync::Arc; pub type Result<T> = result::Result<T, ErrorGuaranteed>; @@ -410,6 +411,12 @@ pub struct Config { /// Registry of diagnostics codes. pub registry: Registry, + /// The inner atomic value is set to true when a feature marked as `internal` is + /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with + /// internal features are wontfix, and they are usually the cause of the ICEs. + /// None signifies that this is not tracked. + pub using_internal_features: Arc<std::sync::atomic::AtomicBool>, + /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows /// This is mainly useful for other tools that reads that debuginfo to figure out @@ -453,6 +460,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.make_codegen_backend, registry.clone(), config.ice_file, + config.using_internal_features, config.expanded_args, ); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 7a7e9024bd8..884afae23d8 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -775,12 +775,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { rustc_hir_analysis::check_crate(tcx)?; sess.time("MIR_borrow_checking", || { - tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); + tcx.hir().par_body_owners(|def_id| { + // Run THIR unsafety check because it's responsible for stealing + // and deallocating THIR when enabled. + tcx.ensure().thir_check_unsafety(def_id); + tcx.ensure().mir_borrowck(def_id) + }); }); sess.time("MIR_effect_checking", || { for def_id in tcx.hir().body_owners() { - tcx.ensure().thir_check_unsafety(def_id); if !tcx.sess.opts.unstable_opts.thir_unsafeck { rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id); } @@ -852,6 +856,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { // This check has to be run after all lints are done processing. We don't // define a lint filter, as all lint checks should have finished at this point. sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None)); + + // This query is only invoked normally if a diagnostic is emitted that needs any + // diagnostic item. If the crate compiles without checking any diagnostic items, + // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally. + let _ = tcx.all_diagnostic_items(()); }); if sess.opts.unstable_opts.print_vtable_sizes { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index fe253febfc7..4fb295da640 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -181,9 +181,11 @@ impl<'tcx> Queries<'tcx> { feed.crate_name(crate_name); let feed = tcx.feed_unit_query(); - feed.features_query( - tcx.arena.alloc(rustc_expand::config::features(sess, &pre_configured_attrs)), - ); + feed.features_query(tcx.arena.alloc(rustc_expand::config::features( + sess, + &pre_configured_attrs, + crate_name, + ))); feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); }); Ok(qcx) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index ec4fd78994e..750d49a1c2d 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -35,6 +35,7 @@ use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtecto use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; +use std::sync::Arc; type CfgSpecs = FxHashSet<(String, Option<String>)>; @@ -69,6 +70,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se None, "", None, + Arc::default(), Default::default(), ); (sess, cfg) @@ -789,7 +791,6 @@ fn test_unstable_options_tracking_hash() { tracked!(inline_mir, Some(true)); tracked!(inline_mir_hint_threshold, Some(123)); tracked!(inline_mir_threshold, Some(123)); - tracked!(instrument_coverage, Some(InstrumentCoverage::All)); tracked!(instrument_mcount, true); tracked!(instrument_xray, Some(InstrumentXRay::default())); tracked!(link_directives, false); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 0634e44c562..d2455a036cc 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -26,7 +26,7 @@ use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::mem; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::OnceLock; +use std::sync::{Arc, OnceLock}; use std::thread; /// Function pointer type that constructs a new CodegenBackend. @@ -71,6 +71,7 @@ pub fn create_session( >, descriptions: Registry, ice_file: Option<PathBuf>, + using_internal_features: Arc<AtomicBool>, expanded_args: Vec<String>, ) -> (Session, Box<dyn CodegenBackend>) { let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { @@ -114,6 +115,7 @@ pub fn create_session( target_override, rustc_version_str().unwrap_or("unknown"), ice_file, + using_internal_features, expanded_args, ); diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index c8f3c2a20a6..0b5426c3bb1 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -21,35 +21,17 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::infer::MemberConstraint; -use crate::mir::ConstraintCategory; -use crate::ty::GenericArg; -use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; use rustc_macros::HashStable; +use rustc_type_ir::Canonical as IrCanonical; use smallvec::SmallVec; -use std::fmt::Display; use std::ops::Index; -/// A "canonicalized" type `V` is one where all free inference -/// variables have been rewritten to "canonical vars". These are -/// numbered starting from 0 in order of first appearance. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] -pub struct Canonical<'tcx, V> { - pub value: V, - pub max_universe: ty::UniverseIndex, - pub variables: CanonicalVarInfos<'tcx>, -} +use crate::infer::MemberConstraint; +use crate::mir::ConstraintCategory; +use crate::ty::GenericArg; +use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; -impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", - self.value, self.max_universe, self.variables - ) - } -} +pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>; pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>; @@ -379,56 +361,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { - pub fn is_proven(&self) -> bool { - self.value.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, V> Canonical<'tcx, V> { - /// Allows you to map the `value` of a canonical while keeping the - /// same set of bound variables. - /// - /// **WARNING:** This function is very easy to mis-use, hence the - /// name! In particular, the new value `W` must use all **the - /// same type/region variables** in **precisely the same order** - /// as the original! (The ordering is defined by the - /// `TypeFoldable` implementation of the type in question.) - /// - /// An example of a **correct** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'_, T> = ...; - /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, )); - /// ``` - /// - /// An example of an **incorrect** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'tcx, T> = ...; - /// let ty: Ty<'tcx> = ...; - /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty)); - /// ``` - pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } - } - - /// Allows you to map the `value` of a canonical while keeping the same set of - /// bound variables. - /// - /// **WARNING:** This function is very easy to mis-use, hence the name! See - /// the comment of [Canonical::unchecked_map] for more details. - pub fn unchecked_rebind<W>(self, value: W) -> Canonical<'tcx, W> { - let Canonical { max_universe, variables, value: _ } = self; - Canonical { max_universe, variables, value } - } -} - pub type QueryOutlivesConstraint<'tcx> = (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>); diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 7ca9647590a..041a63776d1 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -141,18 +141,30 @@ pub struct ConstVarValue<'tcx> { pub val: ConstVariableValue<'tcx>, } -impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct ConstVidKey<'tcx> { + pub vid: ty::ConstVid, + pub phantom: PhantomData<ty::Const<'tcx>>, +} + +impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> { + fn from(vid: ty::ConstVid) -> Self { + ConstVidKey { vid, phantom: PhantomData } + } +} + +impl<'tcx> UnifyKey for ConstVidKey<'tcx> { type Value = ConstVarValue<'tcx>; #[inline] fn index(&self) -> u32 { - self.index + self.vid.as_u32() } #[inline] fn from_index(i: u32) -> Self { - ty::ConstVid { index: i, phantom: PhantomData } + ConstVidKey::from(ty::ConstVid::from_u32(i)) } fn tag() -> &'static str { - "ConstVid" + "ConstVidKey" } } @@ -224,17 +236,29 @@ impl<'tcx> UnifyValue for EffectVarValue<'tcx> { } } -impl<'tcx> UnifyKey for ty::EffectVid<'tcx> { +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct EffectVidKey<'tcx> { + pub vid: ty::EffectVid, + pub phantom: PhantomData<EffectVarValue<'tcx>>, +} + +impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> { + fn from(vid: ty::EffectVid) -> Self { + EffectVidKey { vid, phantom: PhantomData } + } +} + +impl<'tcx> UnifyKey for EffectVidKey<'tcx> { type Value = Option<EffectVarValue<'tcx>>; #[inline] fn index(&self) -> u32 { - self.index + self.vid.as_u32() } #[inline] fn from_index(i: u32) -> Self { - ty::EffectVid { index: i, phantom: PhantomData } + EffectVidKey::from(ty::EffectVid::from_u32(i)) } fn tag() -> &'static str { - "EffectVid" + "EffectVidKey" } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 23d77a1ebe4..0c2241f8729 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -341,7 +341,7 @@ rustc_queries! { query opaque_types_defined_by( key: LocalDefId - ) -> &'tcx [LocalDefId] { + ) -> &'tcx ty::List<LocalDefId> { desc { |tcx| "computing the opaque types defined by `{}`", tcx.def_path_str(key.to_def_id()) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 20e3349073d..f1747356139 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -636,7 +636,8 @@ impl<'tcx> Pat<'tcx> { Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } - | Deref { subpattern } => subpattern.walk_(it), + | Deref { subpattern } + | InlineConstant { subpattern, .. } => subpattern.walk_(it), Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) } @@ -764,6 +765,22 @@ pub enum PatKind<'tcx> { value: mir::Const<'tcx>, }, + /// Inline constant found while lowering a pattern. + InlineConstant { + /// [LocalDefId] of the constant, we need this so that we have a + /// reference that can be used by unsafety checking to visit nested + /// unevaluated constants. + def: LocalDefId, + /// If the inline constant is used in a range pattern, this subpattern + /// represents the range (if both ends are inline constants, there will + /// be multiple InlineConstant wrappers). + /// + /// Otherwise, the actual pattern that the constant lowered to. As with + /// other constants, inline constants are matched structurally where + /// possible. + subpattern: Box<Pat<'tcx>>, + }, + Range(Box<PatRange<'tcx>>), /// Matches against a slice, checking the length and extracting elements. @@ -924,6 +941,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> { write!(f, "{subpattern}") } PatKind::Constant { value } => write!(f, "{value}"), + PatKind::InlineConstant { def: _, ref subpattern } => { + write!(f, "{} (from inline const)", subpattern) + } PatKind::Range(box PatRange { lo, hi, end }) => { write!(f, "{lo}")?; write!(f, "{end}")?; diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index afb58438519..d03d92c3a4b 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -233,16 +233,17 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' } } Constant { value: _ } => {} + InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern), Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { for subpattern in prefix.iter() { - visitor.visit_pat(&subpattern); + visitor.visit_pat(subpattern); } if let Some(pat) = slice { - visitor.visit_pat(&pat); + visitor.visit_pat(pat); } for subpattern in suffix.iter() { - visitor.visit_pat(&subpattern); + visitor.visit_pat(subpattern); } } Or { pats } => { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index e4069e11df2..d52a717b6b0 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -230,9 +230,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> assert!(pos >= SHORTHAND_OFFSET); let shorthand = pos - SHORTHAND_OFFSET; - decoder.with_position(shorthand, ty::PredicateKind::decode) + decoder.with_position(shorthand, <ty::PredicateKind<'tcx> as Decodable<D>>::decode) } else { - ty::PredicateKind::decode(decoder) + <ty::PredicateKind<'tcx> as Decodable<D>>::decode(decoder) }, bound_vars, ) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 2518f0cf2e9..cfacccd2679 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -57,7 +57,7 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> { Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty) } @@ -67,7 +67,7 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> { Const::new(tcx, ty::ConstKind::Infer(infer), ty) } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 749b54ca0be..4af841fcf9a 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -80,19 +80,19 @@ static_assert_size!(super::ConstKind<'_>, 32); /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] -pub enum InferConst<'tcx> { +pub enum InferConst { /// Infer the value of the const. - Var(ty::ConstVid<'tcx>), + Var(ty::ConstVid), /// Infer the value of the effect. /// /// For why this is separate from the `Var` variant above, see the /// documentation on `EffectVid`. - EffectVar(ty::EffectVid<'tcx>), + EffectVar(ty::EffectVid), /// A fresh const variable. See `infer::freshen` for more details. Fresh(u32), } -impl<CTX> HashStable<CTX> for InferConst<'_> { +impl<CTX> HashStable<CTX> for InferConst { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { match self { InferConst::Var(_) | InferConst::EffectVar(_) => { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 561699d3170..a669ff8d961 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -6,7 +6,7 @@ pub mod tls; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; -use crate::infer::canonical::CanonicalVarInfo; +use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::struct_lint_level; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -84,10 +84,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArg = ty::GenericArg<'tcx>; + type Term = ty::Term<'tcx>; + type Binder<T> = Binder<'tcx, T>; - type Predicate = Predicate<'tcx>; - type PredicateKind = ty::PredicateKind<'tcx>; type TypeAndMut = TypeAndMut<'tcx>; + type CanonicalVars = CanonicalVarInfos<'tcx>; + type Ty = Ty<'tcx>; type Tys = &'tcx List<Ty<'tcx>>; type AliasTy = ty::AliasTy<'tcx>; @@ -95,18 +97,21 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type BoundTy = ty::BoundTy; type PlaceholderTy = ty::PlaceholderType; type InferTy = InferTy; + type ErrorGuaranteed = ErrorGuaranteed; type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>; type PolyFnSig = PolyFnSig<'tcx>; type AllocId = crate::mir::interpret::AllocId; + type Const = ty::Const<'tcx>; - type InferConst = ty::InferConst<'tcx>; + type InferConst = ty::InferConst; type AliasConst = ty::UnevaluatedConst<'tcx>; type PlaceholderConst = ty::PlaceholderConst<'tcx>; type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; type ValueConst = ty::ValTree<'tcx>; type ExprConst = ty::Expr<'tcx>; + type Region = Region<'tcx>; type EarlyBoundRegion = ty::EarlyBoundRegion; type BoundRegion = ty::BoundRegion; @@ -114,6 +119,15 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type InferRegion = ty::RegionVid; type PlaceholderRegion = ty::PlaceholderRegion; + type Predicate = Predicate<'tcx>; + type TraitPredicate = ty::TraitPredicate<'tcx>; + type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>; + type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>; + type ProjectionPredicate = ty::ProjectionPredicate<'tcx>; + type SubtypePredicate = ty::SubtypePredicate<'tcx>; + type CoercePredicate = ty::CoercePredicate<'tcx>; + type ClosureKind = ty::ClosureKind; + fn ty_and_mut_to_parts( TypeAndMut { ty, mutbl }: TypeAndMut<'tcx>, ) -> (Self::Ty, ty::Mutability) { @@ -148,6 +162,7 @@ pub struct CtxtInterners<'tcx> { external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List<FieldIdx>>, + local_def_ids: InternedSet<'tcx, List<LocalDefId>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -173,6 +188,7 @@ impl<'tcx> CtxtInterners<'tcx> { external_constraints: Default::default(), predefined_opaques_in_body: Default::default(), fields: Default::default(), + local_def_ids: Default::default(), } } @@ -1559,6 +1575,7 @@ slice_interners!( place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), fields: pub mk_fields(FieldIdx), + local_def_ids: intern_local_def_ids(LocalDefId), ); impl<'tcx> TyCtxt<'tcx> { @@ -1788,6 +1805,13 @@ impl<'tcx> TyCtxt<'tcx> { self.intern_clauses(clauses) } + pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> { + // FIXME consider asking the input slice to be sorted to avoid + // re-interning permutations, in which case that would be asserted + // here. + self.intern_local_def_ids(clauses) + } + pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 184a70ed4cb..738bb5e8b19 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -241,7 +241,9 @@ impl<'tcx> Ty<'tcx> { } ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), - ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(), + ty::Coroutine(def_id, ..) => { + format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into() + } ty::CoroutineWitness(..) => "coroutine witness".into(), ty::Infer(ty::TyVar(_)) => "inferred type".into(), ty::Infer(ty::IntVar(_)) => "integer".into(), @@ -299,7 +301,9 @@ impl<'tcx> Ty<'tcx> { ty::FnPtr(_) => "fn pointer".into(), ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), - ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(), + ty::Coroutine(def_id, ..) => { + format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into() + } ty::CoroutineWitness(..) => "coroutine witness".into(), ty::Tuple(..) => "tuple".into(), ty::Placeholder(..) => "higher-ranked type".into(), diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 7a32cfb1085..4f9c9d85763 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -1,7 +1,7 @@ use crate::arena::Arena; use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_serialize::{Encodable, Encoder}; -use rustc_type_ir::{InferCtxtLike, OptWithInfcx}; +use rustc_type_ir::{InferCtxtLike, WithInfcx}; use std::alloc::Layout; use std::cmp::Ordering; use std::fmt; @@ -121,8 +121,8 @@ impl<T: fmt::Debug> fmt::Debug for List<T> { } } impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { fmt::Debug::fmt(&this.map(|this| this.as_slice()), f) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9b0ceb23e3e..739d4fa886e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -54,7 +54,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; -pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; +pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; pub use vtable::*; use std::fmt::Debug; @@ -97,17 +97,17 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::BoundRegionKind::*; pub use self::sty::{ AliasTy, Article, Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, - BoundVariableKind, CanonicalPolyFnSig, ClosureArgs, ClosureArgsParts, ConstKind, ConstVid, - CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate, + BoundVariableKind, CanonicalPolyFnSig, ClauseKind, ClosureArgs, ClosureArgsParts, ConstKind, + ConstVid, CoroutineArgs, CoroutineArgsParts, EarlyBoundRegion, EffectVid, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PolyExistentialPredicate, PolyExistentialProjection, - PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, Region, RegionKind, RegionVid, - TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, + PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, PredicateKind, Region, + RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ - CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults, - UserType, UserTypeAnnotationIndex, + CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity, + TypeckResults, UserType, UserTypeAnnotationIndex, }; pub mod _match; @@ -233,6 +233,7 @@ impl MainDefinition { #[derive(Clone, Debug, TypeFoldable, TypeVisitable)] pub struct ImplHeader<'tcx> { pub impl_def_id: DefId, + pub impl_args: ty::GenericArgsRef<'tcx>, pub self_ty: Ty<'tcx>, pub trait_ref: Option<TraitRef<'tcx>>, pub predicates: Vec<Predicate<'tcx>>, @@ -626,98 +627,6 @@ impl<'tcx> Clause<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -/// A clause is something that can appear in where bounds or be inferred -/// by implied bounds. -pub enum ClauseKind<'tcx> { - /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be - /// the `Self` type of the trait reference and `A`, `B`, and `C` - /// would be the type parameters. - Trait(TraitPredicate<'tcx>), - - /// `where 'a: 'b` - RegionOutlives(RegionOutlivesPredicate<'tcx>), - - /// `where T: 'a` - TypeOutlives(TypeOutlivesPredicate<'tcx>), - - /// `where <T as TraitRef>::Name == X`, approximately. - /// See the `ProjectionPredicate` struct for details. - Projection(ProjectionPredicate<'tcx>), - - /// Ensures that a const generic argument to a parameter `const N: u8` - /// is of type `u8`. - ConstArgHasType(Const<'tcx>, Ty<'tcx>), - - /// No syntax: `T` well-formed. - WellFormed(GenericArg<'tcx>), - - /// Constant initializer must evaluate successfully. - ConstEvaluatable(ty::Const<'tcx>), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub enum PredicateKind<'tcx> { - /// Prove a clause - Clause(ClauseKind<'tcx>), - - /// Trait must be object-safe. - ObjectSafe(DefId), - - /// No direct syntax. May be thought of as `where T: FnFoo<...>` - /// for some generic args `...` and `T` being a closure type. - /// Satisfied (or refuted) once we know the closure's kind. - ClosureKind(DefId, GenericArgsRef<'tcx>, ClosureKind), - - /// `T1 <: T2` - /// - /// This obligation is created most often when we have two - /// unresolved type variables and hence don't have enough - /// information to process the subtyping obligation yet. - Subtype(SubtypePredicate<'tcx>), - - /// `T1` coerced to `T2` - /// - /// Like a subtyping obligation, this is created most often - /// when we have two unresolved type variables and hence - /// don't have enough information to process the coercion - /// obligation yet. At the moment, we actually process coercions - /// very much like subtyping and don't handle the full coercion - /// logic. - Coerce(CoercePredicate<'tcx>), - - /// Constants must be equal. The first component is the const that is expected. - ConstEquate(Const<'tcx>, Const<'tcx>), - - /// A marker predicate that is always ambiguous. - /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. - Ambiguous, - - /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. - /// This predicate requires two terms to be equal to eachother. - /// - /// Only used for new solver - AliasRelate(Term<'tcx>, Term<'tcx>, AliasRelationDirection), -} - -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, Debug)] -pub enum AliasRelationDirection { - Equate, - Subtype, -} - -impl std::fmt::Display for AliasRelationDirection { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - AliasRelationDirection::Equate => write!(f, "=="), - AliasRelationDirection::Subtype => write!(f, "<:"), - } - } -} - /// The crate outlives map is computed during typeck and contains the /// outlives of every item in the local crate. You should not use it /// directly, because to do so will make your pass dependent on the @@ -1084,19 +993,19 @@ impl ParamTerm { } #[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum TermVid<'tcx> { +pub enum TermVid { Ty(ty::TyVid), - Const(ty::ConstVid<'tcx>), + Const(ty::ConstVid), } -impl From<ty::TyVid> for TermVid<'_> { +impl From<ty::TyVid> for TermVid { fn from(value: ty::TyVid) -> Self { TermVid::Ty(value) } } -impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> { - fn from(value: ty::ConstVid<'tcx>) -> Self { +impl From<ty::ConstVid> for TermVid { + fn from(value: ty::ConstVid) -> Self { TermVid::Const(value) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 316370977a4..433ac33f1b8 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1194,7 +1194,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { None } - fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<Symbol> { + fn const_infer_name(&self, _: ty::ConstVid) -> Option<Symbol> { None } @@ -1742,7 +1742,7 @@ pub struct FmtPrinterData<'a, 'tcx> { pub region_highlight_mode: RegionHighlightMode<'tcx>, pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>, - pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<Symbol> + 'a>>, + pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid) -> Option<Symbol> + 'a>>, } impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> { @@ -2082,7 +2082,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { self.printed_type_count = 0; } - fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<Symbol> { + fn const_infer_name(&self, id: ty::ConstVid) -> Option<Symbol> { self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id)) } @@ -2650,6 +2650,13 @@ macro_rules! forward_display_to_print { macro_rules! define_print_and_forward_display { (($self:ident, $cx:ident): $($ty:ty $print:block)+) => { + define_print!(($self, $cx): $($ty $print)*); + forward_display_to_print!($($ty),+); + }; +} + +macro_rules! define_print { + (($self:ident, $cx:ident): $($ty:ty $print:block)+) => { $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty { fn print(&$self, $cx: &mut P) -> Result<(), PrintError> { #[allow(unused_mut)] @@ -2660,8 +2667,6 @@ macro_rules! define_print_and_forward_display { Ok(()) } })+ - - forward_display_to_print!($($ty),+); }; } @@ -2759,6 +2764,51 @@ forward_display_to_print! { ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> } +define_print! { + (self, cx): + + ty::ClauseKind<'tcx> { + match *self { + ty::ClauseKind::Trait(ref data) => { + p!(print(data)) + } + ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)), + ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)), + ty::ClauseKind::Projection(predicate) => p!(print(predicate)), + ty::ClauseKind::ConstArgHasType(ct, ty) => { + p!("the constant `", print(ct), "` has type `", print(ty), "`") + }, + ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"), + ty::ClauseKind::ConstEvaluatable(ct) => { + p!("the constant `", print(ct), "` can be evaluated") + } + } + } + + ty::PredicateKind<'tcx> { + match *self { + ty::PredicateKind::Clause(data) => { + p!(print(data)) + } + ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), + ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), + ty::PredicateKind::ObjectSafe(trait_def_id) => { + p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") + } + ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!( + "the closure `", + print_value_path(closure_def_id, &[]), + write("` implements the trait `{}`", kind) + ), + ty::PredicateKind::ConstEquate(c1, c2) => { + p!("the constant `", print(c1), "` equals `", print(c2), "`") + } + ty::PredicateKind::Ambiguous => p!("ambiguous"), + ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), + } + } +} + define_print_and_forward_display! { (self, cx): @@ -2887,55 +2937,13 @@ define_print_and_forward_display! { } ty::Predicate<'tcx> { - let binder = self.kind(); - p!(print(binder)) + p!(print(self.kind())) } ty::Clause<'tcx> { p!(print(self.kind())) } - ty::ClauseKind<'tcx> { - match *self { - ty::ClauseKind::Trait(ref data) => { - p!(print(data)) - } - ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)), - ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)), - ty::ClauseKind::Projection(predicate) => p!(print(predicate)), - ty::ClauseKind::ConstArgHasType(ct, ty) => { - p!("the constant `", print(ct), "` has type `", print(ty), "`") - }, - ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"), - ty::ClauseKind::ConstEvaluatable(ct) => { - p!("the constant `", print(ct), "` can be evaluated") - } - } - } - - ty::PredicateKind<'tcx> { - match *self { - ty::PredicateKind::Clause(data) => { - p!(print(data)) - } - ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), - ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), - ty::PredicateKind::ObjectSafe(trait_def_id) => { - p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") - } - ty::PredicateKind::ClosureKind(closure_def_id, _closure_args, kind) => p!( - "the closure `", - print_value_path(closure_def_id, &[]), - write("` implements the trait `{}`", kind) - ), - ty::PredicateKind::ConstEquate(c1, c2) => { - p!("the constant `", print(c1), "` equals `", print(c2), "`") - } - ty::PredicateKind::Ambiguous => p!("ambiguous"), - ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), - } - } - GenericArg<'tcx> { match self.unpack() { GenericArgKind::Lifetime(lt) => p!(print(lt)), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index bf2e61b23b2..6af68bc5dba 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -10,7 +10,7 @@ use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_hir::def::Namespace; use rustc_target::abi::TyAndLayout; -use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; +use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx}; use std::fmt::{self, Debug}; use std::ops::ControlFlow; @@ -87,12 +87,12 @@ impl fmt::Debug for ty::FreeRegion { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { let sig = this.data; @@ -128,18 +128,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "?{}c", self.index) - } -} - -impl fmt::Debug for ty::EffectVid<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "?{}e", self.index) - } -} - impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { with_no_trimmed_paths!(fmt::Display::fmt(self, f)) @@ -147,8 +135,8 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { } impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { this.data.fmt(f) @@ -197,51 +185,14 @@ impl<'tcx> fmt::Debug for ty::Clause<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), - ty::ClauseKind::Trait(ref a) => a.fmt(f), - ty::ClauseKind::RegionOutlives(ref pair) => pair.fmt(f), - ty::ClauseKind::TypeOutlives(ref pair) => pair.fmt(f), - ty::ClauseKind::Projection(ref pair) => pair.fmt(f), - ty::ClauseKind::WellFormed(ref data) => write!(f, "WellFormed({data:?})"), - ty::ClauseKind::ConstEvaluatable(ct) => { - write!(f, "ConstEvaluatable({ct:?})") - } - } - } -} - -impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ty::PredicateKind::Clause(ref a) => a.fmt(f), - ty::PredicateKind::Subtype(ref pair) => pair.fmt(f), - ty::PredicateKind::Coerce(ref pair) => pair.fmt(f), - ty::PredicateKind::ObjectSafe(trait_def_id) => { - write!(f, "ObjectSafe({trait_def_id:?})") - } - ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => { - write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})") - } - ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"), - ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"), - ty::PredicateKind::AliasRelate(t1, t2, dir) => { - write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") - } - } - } -} - impl<'tcx> fmt::Debug for AliasTy<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { f.debug_struct("AliasTy") @@ -251,7 +202,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> { } } -impl<'tcx> fmt::Debug for ty::InferConst<'tcx> { +impl fmt::Debug for ty::InferConst { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { InferConst::Var(var) => write!(f, "{var:?}"), @@ -260,17 +211,17 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> { } } } -impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst { + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { use ty::InferConst::*; - match this.infcx.and_then(|infcx| infcx.universe_of_ct(*this.data)) { + match this.infcx.universe_of_ct(*this.data) { None => write!(f, "{:?}", this.data), Some(universe) => match *this.data { - Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()), - EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()), + Var(vid) => write!(f, "?{}_{}c", vid.index(), universe.index()), + EffectVar(vid) => write!(f, "?{}_{}e", vid.index(), universe.index()), Fresh(_) => { unreachable!() } @@ -281,12 +232,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> { impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { match this.data { @@ -314,12 +265,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> { impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { f.debug_struct("UnevaluatedConst") @@ -331,12 +282,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> { impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { // If this is a value, we spend some effort to make it look nice. @@ -392,8 +343,8 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> { } } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { match this.data.unpack() { @@ -410,8 +361,8 @@ impl<'tcx> fmt::Debug for Region<'tcx> { } } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { write!(f, "{:?}", &this.map(|data| data.kind())) @@ -419,11 +370,11 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> { } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { - match this.infcx.and_then(|infcx| infcx.universe_of_lt(*this.data)) { + match this.infcx.universe_of_lt(*this.data) { Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()), None => write!(f, "{:?}", this.data), } @@ -431,8 +382,8 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid { } impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { - fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( - this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { f.debug_tuple("Binder") @@ -498,7 +449,6 @@ TrivialTypeTraversalImpls! { crate::ty::IntVarValue, crate::ty::adjustment::PointerCoercion, crate::ty::RegionVid, - crate::ty::UniverseIndex, crate::ty::Variance, ::rustc_span::Span, ::rustc_span::symbol::Ident, @@ -515,7 +465,6 @@ TrivialTypeTraversalAndLiftImpls! { ::rustc_hir::Mutability, ::rustc_hir::Unsafety, ::rustc_target::spec::abi::Abi, - crate::ty::AliasRelationDirection, crate::ty::ClosureKind, crate::ty::ParamConst, crate::ty::ParamTy, @@ -862,7 +811,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { } } -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> { +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, _folder: &mut F, @@ -871,7 +820,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> { } } -impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst<'tcx> { +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst { fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>( &self, _visitor: &mut V, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 46aa5d950cb..44592b10d55 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -29,14 +29,15 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::cmp::Ordering; use std::fmt; -use std::marker::PhantomData; use std::ops::{ControlFlow, Deref, Range}; use ty::util::IntTypeExt; +use rustc_type_ir::ClauseKind as IrClauseKind; use rustc_type_ir::CollectAndApply; use rustc_type_ir::ConstKind as IrConstKind; use rustc_type_ir::DebugWithInfcx; use rustc_type_ir::DynKind; +use rustc_type_ir::PredicateKind as IrPredicateKind; use rustc_type_ir::RegionKind as IrRegionKind; use rustc_type_ir::TyKind as IrTyKind; use rustc_type_ir::TyKind::*; @@ -48,6 +49,8 @@ use super::GenericParamDefKind; pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>; pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>; pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>; +pub type PredicateKind<'tcx> = IrPredicateKind<TyCtxt<'tcx>>; +pub type ClauseKind<'tcx> = IrClauseKind<TyCtxt<'tcx>>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] @@ -683,8 +686,8 @@ pub enum ExistentialPredicate<'tcx> { } impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> { - fn fmt<InfCtx: rustc_type_ir::InferCtxtLike<TyCtxt<'tcx>>>( - this: rustc_type_ir::OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, + fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { fmt::Debug::fmt(&this.data, f) @@ -1583,26 +1586,22 @@ impl fmt::Debug for EarlyBoundRegion { } } -/// A **`const`** **v**ariable **ID**. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable, TyEncodable, TyDecodable)] -pub struct ConstVid<'tcx> { - pub index: u32, - pub phantom: PhantomData<&'tcx ()>, +rustc_index::newtype_index! { + /// A **`const`** **v**ariable **ID**. + #[debug_format = "?{}c"] + pub struct ConstVid {} } -/// An **effect** **v**ariable **ID**. -/// -/// Handling effect infer variables happens separately from const infer variables -/// because we do not want to reuse any of the const infer machinery. If we try to -/// relate an effect variable with a normal one, we would ICE, which can catch bugs -/// where we are not correctly using the effect var for an effect param. Fallback -/// is also implemented on top of having separate effect and normal const variables. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable)] -pub struct EffectVid<'tcx> { - pub index: u32, - pub phantom: PhantomData<&'tcx ()>, +rustc_index::newtype_index! { + /// An **effect** **v**ariable **ID**. + /// + /// Handling effect infer variables happens separately from const infer variables + /// because we do not want to reuse any of the const infer machinery. If we try to + /// relate an effect variable with a normal one, we would ICE, which can catch bugs + /// where we are not correctly using the effect var for an effect param. Fallback + /// is also implemented on top of having separate effect and normal const variables. + #[debug_format = "?{}e"] + pub struct EffectVid {} } rustc_index::newtype_index! { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 7d516410b20..58ad1eb900f 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -594,10 +594,27 @@ pub struct CanonicalUserTypeAnnotation<'tcx> { /// Canonical user type annotation. pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>; -impl<'tcx> CanonicalUserType<'tcx> { +/// A user-given type annotation attached to a constant. These arise +/// from constants that are named via paths, like `Foo::<A>::new` and +/// so forth. +#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] +#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)] +pub enum UserType<'tcx> { + Ty(Ty<'tcx>), + + /// The canonical type is the result of `type_of(def_id)` with the + /// given substitutions applied. + TypeOf(DefId, UserArgs<'tcx>), +} + +pub trait IsIdentity { + fn is_identity(&self) -> bool; +} + +impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, /// i.e., each thing is mapped to a canonical variable with the same index. - pub fn is_identity(&self) -> bool { + fn is_identity(&self) -> bool { match self.value { UserType::Ty(_) => false, UserType::TypeOf(_, user_args) => { @@ -640,19 +657,6 @@ impl<'tcx> CanonicalUserType<'tcx> { } } -/// A user-given type annotation attached to a constant. These arise -/// from constants that are named via paths, like `Foo::<A>::new` and -/// so forth. -#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] -#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub enum UserType<'tcx> { - Ty(Ty<'tcx>), - - /// The canonical type is the result of `type_of(def_id)` with the - /// given substitutions applied. - TypeOf(DefId, UserArgs<'tcx>), -} - impl<'tcx> std::fmt::Display for UserType<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index db3886b32be..32711c23dc4 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -379,6 +379,5 @@ mir_build_unused_unsafe = unnecessary `unsafe` block .label = unnecessary `unsafe` block mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block -mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn mir_build_variant_defined_here = not covered diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 24c6e0eae36..1cf8c202ea4 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -847,6 +847,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } + PatKind::InlineConstant { ref subpattern, .. } => { + self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f) + } + PatKind::Leaf { ref subpatterns } => { for subpattern in subpatterns { let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index f340feb40d4..32573b4d53a 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -204,6 +204,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } + PatKind::InlineConstant { subpattern: ref pattern, def: _ } => { + candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); + + Ok(()) + } + PatKind::Range(box PatRange { lo, hi, end }) => { let (range, bias) = match *lo.ty().kind() { ty::Char => { @@ -229,8 +235,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // correct the comparison. This is achieved by XORing with a bias (see // pattern/_match.rs for another pertinent example of this pattern). // - // Also, for performance, it's important to only do the second `try_to_bits` if - // necessary. + // Also, for performance, it's important to only do the second + // `try_to_bits` if necessary. let lo = lo.try_to_bits(sz).unwrap() ^ bias; if lo <= min { let hi = hi.try_to_bits(sz).unwrap() ^ bias; diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 30ce37a7ac1..5e7db7413df 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -73,6 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Or { .. } => bug!("or-patterns should have already been handled"), PatKind::AscribeUserType { .. } + | PatKind::InlineConstant { .. } | PatKind::Array { .. } | PatKind::Wild | PatKind::Binding { .. } @@ -111,6 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Or { .. } | PatKind::Binding { .. } | PatKind::AscribeUserType { .. } + | PatKind::InlineConstant { .. } | PatKind::Leaf { .. } | PatKind::Deref { .. } | PatKind::Error(_) => { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 8a3b67b8f03..1f817633a2a 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -53,10 +53,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( } /// Construct the MIR for a given `DefId`. -fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { - // Ensure unsafeck and abstract const building is ran before we steal the THIR. - tcx.ensure_with_value() - .thir_check_unsafety(tcx.typeck_root_def_id(def.to_def_id()).expect_local()); +fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { tcx.ensure_with_value().thir_abstract_const(def); if let Err(e) = tcx.check_match(def) { return construct_error(tcx, def, e); @@ -65,20 +62,27 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { let body = match tcx.thir_body(def) { Err(error_reported) => construct_error(tcx, def, error_reported), Ok((thir, expr)) => { - // We ran all queries that depended on THIR at the beginning - // of `mir_build`, so now we can steal it - let thir = thir.steal(); + let build_mir = |thir: &Thir<'tcx>| match thir.body_type { + thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig), + thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty), + }; - tcx.ensure().check_match(def); // this must run before MIR dump, because // "not all control paths return a value" is reported here. // // maybe move the check to a MIR pass? tcx.ensure().check_liveness(def); - match thir.body_type { - thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig), - thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty), + if tcx.sess.opts.unstable_opts.thir_unsafeck { + // Don't steal here if THIR unsafeck is being used. Instead + // steal in unsafeck. This is so that pattern inline constants + // can be evaluated as part of building the THIR of the parent + // function without a cycle. + build_mir(&thir.borrow()) + } else { + // We ran all queries that depended on THIR at the beginning + // of `mir_build`, so now we can steal it + build_mir(&thir.steal()) } } }; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 00d2afce8c6..45be5015371 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -13,6 +13,7 @@ use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; use rustc_span::Span; +use std::mem; use std::ops::Bound; struct UnsafetyVisitor<'a, 'tcx> { @@ -24,7 +25,6 @@ struct UnsafetyVisitor<'a, 'tcx> { /// The current "safety context". This notably tracks whether we are in an /// `unsafe` block, and whether it has been used. safety_context: SafetyContext, - body_unsafety: BodyUnsafety, /// The `#[target_feature]` attributes of the body. Used for checking /// calls to functions with `#[target_feature]` (RFC 2396). body_target_features: &'tcx [Symbol], @@ -34,43 +34,50 @@ struct UnsafetyVisitor<'a, 'tcx> { in_union_destructure: bool, param_env: ParamEnv<'tcx>, inside_adt: bool, + warnings: &'a mut Vec<UnusedUnsafeWarning>, } impl<'tcx> UnsafetyVisitor<'_, 'tcx> { fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) { - if let ( - SafetyContext::UnsafeBlock { span: enclosing_span, .. }, - SafetyContext::UnsafeBlock { span: block_span, hir_id, .. }, - ) = (self.safety_context, safety_context) + let prev_context = mem::replace(&mut self.safety_context, safety_context); + + f(self); + + let safety_context = mem::replace(&mut self.safety_context, prev_context); + if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } = + safety_context { - self.warn_unused_unsafe( - hir_id, - block_span, - Some(UnusedUnsafeEnclosing::Block { - span: self.tcx.sess.source_map().guess_head_span(enclosing_span), - }), - ); - f(self); - } else { - let prev_context = self.safety_context; - self.safety_context = safety_context; + if !used { + self.warn_unused_unsafe(hir_id, span, None); - f(self); + if let SafetyContext::UnsafeBlock { + nested_used_blocks: ref mut prev_nested_used_blocks, + .. + } = self.safety_context + { + prev_nested_used_blocks.extend(nested_used_blocks); + } + } else { + for block in nested_used_blocks { + self.warn_unused_unsafe( + block.hir_id, + block.span, + Some(UnusedUnsafeEnclosing::Block { + span: self.tcx.sess.source_map().guess_head_span(span), + }), + ); + } - if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context { - self.warn_unused_unsafe( - hir_id, - span, - if self.unsafe_op_in_unsafe_fn_allowed() { - self.body_unsafety - .unsafe_fn_sig_span() - .map(|span| UnusedUnsafeEnclosing::Function { span }) - } else { - None - }, - ); + match self.safety_context { + SafetyContext::UnsafeBlock { + nested_used_blocks: ref mut prev_nested_used_blocks, + .. + } => { + prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span }); + } + _ => (), + } } - self.safety_context = prev_context; } } @@ -102,18 +109,12 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } fn warn_unused_unsafe( - &self, + &mut self, hir_id: hir::HirId, block_span: Span, enclosing_unsafe: Option<UnusedUnsafeEnclosing>, ) { - let block_span = self.tcx.sess.source_map().guess_head_span(block_span); - self.tcx.emit_spanned_lint( - UNUSED_UNSAFE, - hir_id, - block_span, - UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe }, - ); + self.warnings.push(UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe }); } /// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node. @@ -124,9 +125,18 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { /// Handle closures/coroutines/inline-consts, which is unsafecked with their parent body. fn visit_inner_body(&mut self, def: LocalDefId) { if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) { - let inner_thir = &inner_thir.borrow(); + // Runs all other queries that depend on THIR. + self.tcx.ensure_with_value().mir_built(def); + let inner_thir = &inner_thir.steal(); let hir_context = self.tcx.hir().local_def_id_to_hir_id(def); - let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self }; + let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe); + let mut inner_visitor = UnsafetyVisitor { + thir: inner_thir, + hir_context, + safety_context, + warnings: self.warnings, + ..*self + }; inner_visitor.visit_expr(&inner_thir[expr]); // Unsafe blocks can be used in the inner body, make sure to take it into account self.safety_context = inner_visitor.safety_context; @@ -193,8 +203,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { }); } BlockSafety::ExplicitUnsafe(hir_id) => { + let used = + matches!(self.tcx.lint_level_at_node(UNUSED_UNSAFE, hir_id), (Level::Allow, _)); self.in_safety_context( - SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false }, + SafetyContext::UnsafeBlock { + span: block.span, + hir_id, + used, + nested_used_blocks: Vec::new(), + }, |this| visit::walk_block(this, block), ); } @@ -224,6 +241,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns PatKind::Or { .. } | + PatKind::InlineConstant { .. } | PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } @@ -277,6 +295,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; } + PatKind::InlineConstant { def, .. } => { + self.visit_inner_body(*def); + } _ => { visit::walk_pat(self, pat); } @@ -475,36 +496,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } } -#[derive(Clone, Copy)] +#[derive(Clone)] enum SafetyContext { Safe, BuiltinUnsafeBlock, UnsafeFn, - UnsafeBlock { span: Span, hir_id: hir::HirId, used: bool }, + UnsafeBlock { + span: Span, + hir_id: hir::HirId, + used: bool, + nested_used_blocks: Vec<NestedUsedBlock>, + }, } #[derive(Clone, Copy)] -enum BodyUnsafety { - /// The body is not unsafe. - Safe, - /// The body is an unsafe function. The span points to - /// the signature of the function. - Unsafe(Span), +struct NestedUsedBlock { + hir_id: hir::HirId, + span: Span, } -impl BodyUnsafety { - /// Returns whether the body is unsafe. - fn is_unsafe(&self) -> bool { - matches!(self, BodyUnsafety::Unsafe(_)) - } - - /// If the body is unsafe, returns the `Span` of its signature. - fn unsafe_fn_sig_span(self) -> Option<Span> { - match self { - BodyUnsafety::Unsafe(span) => Some(span), - BodyUnsafety::Safe => None, - } - } +struct UnusedUnsafeWarning { + hir_id: hir::HirId, + block_span: Span, + enclosing_unsafe: Option<UnusedUnsafeEnclosing>, } #[derive(Clone, Copy, PartialEq)] @@ -788,34 +802,46 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { } let Ok((thir, expr)) = tcx.thir_body(def) else { return }; - let thir = &thir.borrow(); + // Runs all other queries that depend on THIR. + tcx.ensure_with_value().mir_built(def); + let thir = &thir.steal(); // If `thir` is empty, a type error occurred, skip this body. if thir.exprs.is_empty() { return; } let hir_id = tcx.hir().local_def_id_to_hir_id(def); - let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| { + let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| { if fn_sig.header.unsafety == hir::Unsafety::Unsafe { - BodyUnsafety::Unsafe(fn_sig.span) + SafetyContext::UnsafeFn } else { - BodyUnsafety::Safe + SafetyContext::Safe } }); let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features; - let safety_context = - if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe }; + let mut warnings = Vec::new(); let mut visitor = UnsafetyVisitor { tcx, thir, safety_context, hir_context: hir_id, - body_unsafety, body_target_features, assignment_info: None, in_union_destructure: false, param_env: tcx.param_env(def), inside_adt: false, + warnings: &mut warnings, }; visitor.visit_expr(&thir[expr]); + + warnings.sort_by_key(|w| w.block_span); + for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings { + let block_span = tcx.sess.source_map().guess_head_span(block_span); + tcx.emit_spanned_lint( + UNUSED_UNSAFE, + hir_id, + block_span, + UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe }, + ); + } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index c09dd186418..730670a8369 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -392,11 +392,6 @@ pub enum UnusedUnsafeEnclosing { #[primary_span] span: Span, }, - #[label(mir_build_unused_unsafe_enclosing_fn_label)] - Function { - #[primary_span] - span: Span, - }, } pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 099fefbf068..745c3046d22 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -20,7 +20,7 @@ mod build; mod check_unsafety; mod errors; pub mod lints; -pub mod thir; +mod thir; use rustc_middle::query::Providers; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 840c6e13bef..6c3564a20f6 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -191,11 +191,16 @@ impl<'tcx> Cx<'tcx> { source: self.mirror_expr(source), cast: PointerCoercion::ArrayToPointer, } - } else { - // check whether this is casting an enum variant discriminant - // to prevent cycles, we refer to the discriminant initializer + } else if let hir::ExprKind::Path(ref qpath) = source.kind + && let res = self.typeck_results().qpath_res(qpath, source.hir_id) + && let ty = self.typeck_results().node_type(source.hir_id) + && let ty::Adt(adt_def, args) = ty.kind() + && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res + { + // Check whether this is casting an enum variant discriminant. + // To prevent cycles, we refer to the discriminant initializer, // which is always an integer and thus doesn't need to know the - // enum's layout (or its tag type) to compute it during const eval + // enum's layout (or its tag type) to compute it during const eval. // Example: // enum Foo { // A, @@ -204,21 +209,6 @@ impl<'tcx> Cx<'tcx> { // The correct solution would be to add symbolic computations to miri, // so we wouldn't have to compute and store the actual value - let hir::ExprKind::Path(ref qpath) = source.kind else { - return ExprKind::Cast { source: self.mirror_expr(source) }; - }; - - let res = self.typeck_results().qpath_res(qpath, source.hir_id); - let ty = self.typeck_results().node_type(source.hir_id); - let ty::Adt(adt_def, args) = ty.kind() else { - return ExprKind::Cast { source: self.mirror_expr(source) }; - }; - - let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res - else { - return ExprKind::Cast { source: self.mirror_expr(source) }; - }; - let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx); @@ -255,6 +245,10 @@ impl<'tcx> Cx<'tcx> { }; ExprKind::Cast { source } + } else { + // Default to `ExprKind::Cast` for all explicit casts. + // MIR building then picks the right MIR casts based on the types. + ExprKind::Cast { source: self.mirror_expr(source) } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 86018340a69..2255220808e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1326,7 +1326,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let ctor; let fields; match &pat.kind { - PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern), + PatKind::AscribeUserType { subpattern, .. } + | PatKind::InlineConstant { subpattern, .. } => return mkpat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat), PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 76ed6d2b6d7..dd71ab1f8e5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -27,6 +27,7 @@ use rustc_middle::ty::{ self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt, TypeVisitableExt, UserType, }; +use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_target::abi::{FieldIdx, Integer}; @@ -88,15 +89,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range_endpoint( &mut self, expr: Option<&'tcx hir::Expr<'tcx>>, - ) -> Result<(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>), ErrorGuaranteed> { + ) -> Result< + (Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>), + ErrorGuaranteed, + > { match expr { - None => Ok((None, None)), + None => Ok((None, None, None)), Some(expr) => { - let (kind, ascr) = match self.lower_lit(expr) { + let (kind, ascr, inline_const) = match self.lower_lit(expr) { + PatKind::InlineConstant { subpattern, def } => { + (subpattern.kind, None, Some(def)) + } PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { - (kind, Some(ascription)) + (kind, Some(ascription), None) } - kind => (kind, None), + kind => (kind, None, None), }; let value = if let PatKind::Constant { value } = kind { value @@ -106,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ); return Err(self.tcx.sess.delay_span_bug(expr.span, msg)); }; - Ok((Some(value), ascr)) + Ok((Some(value), ascr, inline_const)) } } } @@ -177,8 +184,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { return Err(self.tcx.sess.delay_span_bug(span, msg)); } - let (lo, lo_ascr) = self.lower_pattern_range_endpoint(lo_expr)?; - let (hi, hi_ascr) = self.lower_pattern_range_endpoint(hi_expr)?; + let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?; + let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?; let lo = lo.unwrap_or_else(|| { // Unwrap is ok because the type is known to be numeric. @@ -237,6 +244,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; } } + for inline_const in [lo_inline, hi_inline] { + if let Some(def) = inline_const { + kind = + PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) }; + } + } Ok(kind) } @@ -599,11 +612,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // const eval path below. // FIXME: investigate the performance impact of removing this. let lit_input = match expr.kind { - hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), - hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { - hir::ExprKind::Lit(ref lit) => { - Some(LitToConstInput { lit: &lit.node, ty, neg: true }) - } + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind { + hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }), _ => None, }, _ => None, @@ -633,13 +644,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) { - self.const_to_pat( + let subpattern = self.const_to_pat( Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span, None, - ) - .kind + ); + PatKind::InlineConstant { subpattern, def: def_id } } else { // If that fails, convert it to an opaque constant pattern. match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { @@ -822,6 +833,9 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { PatKind::Deref { subpattern: subpattern.fold_with(folder) } } PatKind::Constant { value } => PatKind::Constant { value }, + PatKind::InlineConstant { def, subpattern: ref pattern } => { + PatKind::InlineConstant { def, subpattern: pattern.fold_with(folder) } + } PatKind::Range(ref range) => PatKind::Range(range.clone()), PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice { prefix: prefix.fold_with(folder), diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index c957611b975..c3b2309b7cd 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -692,7 +692,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { } PatKind::Deref { subpattern } => { print_indented!(self, "Deref { ", depth_lvl + 1); - print_indented!(self, "subpattern: ", depth_lvl + 2); + print_indented!(self, "subpattern:", depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } @@ -701,6 +701,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } + PatKind::InlineConstant { def, subpattern } => { + print_indented!(self, "InlineConstant {", depth_lvl + 1); + print_indented!(self, format!("def: {:?}", def), depth_lvl + 2); + print_indented!(self, "subpattern:", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } PatKind::Range(pat_range) => { print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 85a0be8a44c..2c29978173f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,13 +2,13 @@ //! //! Currently, this pass only propagates scalar values. -use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; +use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, @@ -16,8 +16,9 @@ use rustc_mir_dataflow::value_analysis::{ use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor}; use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; -use rustc_target::abi::{FieldIdx, VariantIdx}; +use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT}; +use crate::const_prop::throw_machine_stop_str; use crate::MirPass; // These constants are somewhat random guesses and have not been optimized. @@ -553,16 +554,151 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> { fn try_make_constant( &self, + ecx: &mut InterpCx<'tcx, 'tcx, DummyMachine>, place: Place<'tcx>, state: &State<FlatSet<Scalar>>, map: &Map, ) -> Option<Const<'tcx>> { - let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else { - return None; - }; let ty = place.ty(self.local_decls, self.patch.tcx).ty; - Some(Const::Val(ConstValue::Scalar(value.into()), ty)) + let layout = ecx.layout_of(ty).ok()?; + + if layout.is_zst() { + return Some(Const::zero_sized(ty)); + } + + if layout.is_unsized() { + return None; + } + + let place = map.find(place.as_ref())?; + if layout.abi.is_scalar() + && let Some(value) = propagatable_scalar(place, state, map) + { + return Some(Const::Val(ConstValue::Scalar(value), ty)); + } + + if matches!(layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { + let alloc_id = ecx + .intern_with_temp_alloc(layout, |ecx, dest| { + try_write_constant(ecx, dest, place, ty, state, map) + }) + .ok()?; + return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty)); + } + + None + } +} + +fn propagatable_scalar( + place: PlaceIndex, + state: &State<FlatSet<Scalar>>, + map: &Map, +) -> Option<Scalar> { + if let FlatSet::Elem(value) = state.get_idx(place, map) && value.try_to_int().is_ok() { + // Do not attempt to propagate pointers, as we may fail to preserve their identity. + Some(value) + } else { + None + } +} + +#[instrument(level = "trace", skip(ecx, state, map))] +fn try_write_constant<'tcx>( + ecx: &mut InterpCx<'_, 'tcx, DummyMachine>, + dest: &PlaceTy<'tcx>, + place: PlaceIndex, + ty: Ty<'tcx>, + state: &State<FlatSet<Scalar>>, + map: &Map, +) -> InterpResult<'tcx> { + let layout = ecx.layout_of(ty)?; + + // Fast path for ZSTs. + if layout.is_zst() { + return Ok(()); + } + + // Fast path for scalars. + if layout.abi.is_scalar() + && let Some(value) = propagatable_scalar(place, state, map) + { + return ecx.write_immediate(Immediate::Scalar(value), dest); + } + + match ty.kind() { + // ZSTs. Nothing to do. + ty::FnDef(..) => {} + + // Those are scalars, must be handled above. + ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => throw_machine_stop_str!("primitive type with provenance"), + + ty::Tuple(elem_tys) => { + for (i, elem) in elem_tys.iter().enumerate() { + let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else { + throw_machine_stop_str!("missing field in tuple") + }; + let field_dest = ecx.project_field(dest, i)?; + try_write_constant(ecx, &field_dest, field, elem, state, map)?; + } + } + + ty::Adt(def, args) => { + if def.is_union() { + throw_machine_stop_str!("cannot propagate unions") + } + + let (variant_idx, variant_def, variant_place, variant_dest) = if def.is_enum() { + let Some(discr) = map.apply(place, TrackElem::Discriminant) else { + throw_machine_stop_str!("missing discriminant for enum") + }; + let FlatSet::Elem(Scalar::Int(discr)) = state.get_idx(discr, map) else { + throw_machine_stop_str!("discriminant with provenance") + }; + let discr_bits = discr.assert_bits(discr.size()); + let Some((variant, _)) = def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) else { + throw_machine_stop_str!("illegal discriminant for enum") + }; + let Some(variant_place) = map.apply(place, TrackElem::Variant(variant)) else { + throw_machine_stop_str!("missing variant for enum") + }; + let variant_dest = ecx.project_downcast(dest, variant)?; + (variant, def.variant(variant), variant_place, variant_dest) + } else { + (FIRST_VARIANT, def.non_enum_variant(), place, dest.clone()) + }; + + for (i, field) in variant_def.fields.iter_enumerated() { + let ty = field.ty(*ecx.tcx, args); + let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else { + throw_machine_stop_str!("missing field in ADT") + }; + let field_dest = ecx.project_field(&variant_dest, i.as_usize())?; + try_write_constant(ecx, &field_dest, field, ty, state, map)?; + } + ecx.write_discriminant(variant_idx, dest)?; + } + + // Unsupported for now. + ty::Array(_, _) + + // Do not attempt to support indirection in constants. + | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_) + + | ty::Never + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::Coroutine(..) + | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"), + + ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(), } + + Ok(()) } impl<'mir, 'tcx> @@ -580,8 +716,13 @@ impl<'mir, 'tcx> ) { match &statement.kind { StatementKind::Assign(box (_, rvalue)) => { - OperandCollector { state, visitor: self, map: &results.analysis.0.map } - .visit_rvalue(rvalue, location); + OperandCollector { + state, + visitor: self, + ecx: &mut results.analysis.0.ecx, + map: &results.analysis.0.map, + } + .visit_rvalue(rvalue, location); } _ => (), } @@ -599,7 +740,12 @@ impl<'mir, 'tcx> // Don't overwrite the assignment if it already uses a constant (to keep the span). } StatementKind::Assign(box (place, _)) => { - if let Some(value) = self.try_make_constant(place, state, &results.analysis.0.map) { + if let Some(value) = self.try_make_constant( + &mut results.analysis.0.ecx, + place, + state, + &results.analysis.0.map, + ) { self.patch.assignments.insert(location, value); } } @@ -614,8 +760,13 @@ impl<'mir, 'tcx> terminator: &'mir Terminator<'tcx>, location: Location, ) { - OperandCollector { state, visitor: self, map: &results.analysis.0.map } - .visit_terminator(terminator, location); + OperandCollector { + state, + visitor: self, + ecx: &mut results.analysis.0.ecx, + map: &results.analysis.0.map, + } + .visit_terminator(terminator, location); } } @@ -670,6 +821,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> { struct OperandCollector<'tcx, 'map, 'locals, 'a> { state: &'a State<FlatSet<Scalar>>, visitor: &'a mut Collector<'tcx, 'locals>, + ecx: &'map mut InterpCx<'tcx, 'tcx, DummyMachine>, map: &'map Map, } @@ -682,7 +834,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { location: Location, ) { if let PlaceElem::Index(local) = elem - && let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map) + && let Some(value) = self.visitor.try_make_constant(self.ecx, local.into(), self.state, self.map) { self.visitor.patch.before_effect.insert((location, local.into()), value); } @@ -690,7 +842,9 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { if let Some(place) = operand.place() { - if let Some(value) = self.visitor.try_make_constant(place, self.state, self.map) { + if let Some(value) = + self.visitor.try_make_constant(self.ecx, place, self.state, self.map) + { self.visitor.patch.before_effect.insert((location, place), value); } else if !place.projection.is_empty() { // Try to propagate into `Index` projections. @@ -713,7 +867,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm } fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { - unimplemented!() + false } fn before_access_global( @@ -725,13 +879,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm is_write: bool, ) -> InterpResult<'tcx> { if is_write { - crate::const_prop::throw_machine_stop_str!("can't write to global"); + throw_machine_stop_str!("can't write to global"); } // If the static allocation is mutable, then we can't const prop it as its content // might be different at runtime. if alloc.inner().mutability.is_mut() { - crate::const_prop::throw_machine_stop_str!("can't access mutable globals in ConstProp"); + throw_machine_stop_str!("can't access mutable globals in ConstProp"); } Ok(()) @@ -781,7 +935,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> { - crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic"); + throw_machine_stop_str!("can't do pointer arithmetic"); } fn expose_ptr( diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 8b33e00c63c..277060573bc 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -438,10 +438,8 @@ impl<'tcx> Inliner<'tcx> { return Err("incompatible instruction set"); } - for feature in &callee_attrs.target_features { - if !self.codegen_fn_attrs.target_features.contains(feature) { - return Err("incompatible target feature"); - } + if callee_attrs.target_features != self.codegen_fn_attrs.target_features { + return Err("incompatible target features"); } Ok(()) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 25ef5245cf1..84d3b84e13f 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -402,11 +402,6 @@ passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export] passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments -passes_invalid_stability = - invalid stability version found - .label = invalid stability version - .item = the stability attribute annotates this item - passes_lang_item_fn_with_target_feature = `{$name}` language item function is not allowed to have `#[target_feature]` .label = `{$name}` language item function is not allowed to have `#[target_feature]` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 6f87b56c636..6e840f24c69 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1505,16 +1505,6 @@ pub struct UselessStability { } #[derive(Diagnostic)] -#[diag(passes_invalid_stability)] -pub struct InvalidStability { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_item)] - pub item_sp: Span, -} - -#[derive(Diagnostic)] #[diag(passes_cannot_stabilize_deprecated)] pub struct CannotStabilizeDeprecated { #[primary_span] diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index bb23dc257d7..41a240fa880 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -3,7 +3,7 @@ use crate::errors; use rustc_attr::{ - self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable, + self as attr, rust_version_symbol, ConstStability, Since, Stability, StabilityLevel, Unstable, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; @@ -226,37 +226,43 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) = (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) { - // Explicit version of iter::order::lt to handle parse errors properly - for (dep_v, stab_v) in - iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.')) - { - match stab_v.parse::<u64>() { - Err(_) => { - self.tcx.sess.emit_err(errors::InvalidStability { span, item_sp }); - break; - } - Ok(stab_vp) => match dep_v.parse::<u64>() { - Ok(dep_vp) => match dep_vp.cmp(&stab_vp) { - Ordering::Less => { - self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { - span, - item_sp, - }); + match stab_since { + Since::Current => { + self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); + } + Since::Version(stab_since) => { + // Explicit version of iter::order::lt to handle parse errors properly + for (dep_v, stab_v) in iter::zip( + dep_since.as_str().split('.'), + [stab_since.major, stab_since.minor, stab_since.patch], + ) { + match dep_v.parse::<u64>() { + Ok(dep_vp) => match dep_vp.cmp(&u64::from(stab_v)) { + Ordering::Less => { + self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { + span, + item_sp, + }); + break; + } + Ordering::Equal => continue, + Ordering::Greater => break, + }, + Err(_) => { + if dep_v != "TBD" { + self.tcx.sess.emit_err(errors::InvalidDeprecationVersion { + span, + item_sp, + }); + } break; } - Ordering::Equal => continue, - Ordering::Greater => break, - }, - Err(_) => { - if dep_v != "TBD" { - self.tcx.sess.emit_err(errors::InvalidDeprecationVersion { - span, - item_sp, - }); - } - break; } - }, + } + } + Since::Err => { + // An error already reported. Assume the unparseable stabilization + // version is older than the deprecation version. } } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index f2d6a0dff9c..4bb7e65747f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -210,22 +210,7 @@ where } } } - ty::Alias(ty::Weak, alias) => { - self.def_id_visitor.visit_def_id(alias.def_id, "type alias", &ty); - } - ty::Alias(ty::Projection, proj) => { - if V::SKIP_ASSOC_TYS { - // Visitors searching for minimal visibility/reachability want to - // conservatively approximate associated types like `<Type as Trait>::Alias` - // as visible/reachable even if both `Type` and `Trait` are private. - // Ideally, associated types should be substituted in the same way as - // free type aliases, but this isn't done yet. - return ControlFlow::Continue(()); - } - // This will also visit args if necessary, so we don't need to recurse. - return self.visit_projection_ty(proj); - } - ty::Alias(ty::Inherent, data) => { + ty::Alias(kind @ (ty::Inherent | ty::Weak | ty::Projection), data) => { if V::SKIP_ASSOC_TYS { // Visitors searching for minimal visibility/reachability want to // conservatively approximate associated types like `Type::Alias` @@ -235,9 +220,14 @@ where return ControlFlow::Continue(()); } + let kind = match kind { + ty::Inherent | ty::Projection => "associated type", + ty::Weak => "type alias", + ty::Opaque => unreachable!(), + }; self.def_id_visitor.visit_def_id( data.def_id, - "associated type", + kind, &LazyDefPathStr { def_id: data.def_id, tcx }, )?; diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 352bf98d01f..3b1f957c890 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -335,7 +335,7 @@ impl Resolver<'_, '_> { for unused in visitor.unused_imports.values() { let mut fixes = Vec::new(); - let mut spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) { + let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) { UnusedSpanResult::Used => continue, UnusedSpanResult::FlatUnused(span, remove) => { fixes.push((remove, String::new())); @@ -353,20 +353,19 @@ impl Resolver<'_, '_> { } }; - let len = spans.len(); - spans.sort(); - let ms = MultiSpan::from_spans(spans.clone()); - let mut span_snippets = spans + let ms = MultiSpan::from_spans(spans); + + let mut span_snippets = ms + .primary_spans() .iter() - .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) { - Ok(s) => Some(format!("`{s}`")), - _ => None, - }) + .filter_map(|span| tcx.sess.source_map().span_to_snippet(*span).ok()) + .map(|s| format!("`{s}`")) .collect::<Vec<String>>(); span_snippets.sort(); + let msg = format!( "unused import{}{}", - pluralize!(len), + pluralize!(ms.primary_spans().len()), if !span_snippets.is_empty() { format!(": {}", span_snippets.join(", ")) } else { @@ -376,7 +375,7 @@ impl Resolver<'_, '_> { let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span { "remove the whole `use` item" - } else if spans.len() > 1 { + } else if ms.primary_spans().len() > 1 { "remove the unused imports" } else { "remove the unused import" diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4ad838e5aed..edcc22d56c6 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -25,7 +25,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; -use thin_vec::ThinVec; +use thin_vec::{thin_vec, ThinVec}; use crate::errors::{ AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, @@ -1147,7 +1147,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { namespace: Namespace, parent_scope: &ParentScope<'a>, start_module: Module<'a>, - crate_name: Ident, + crate_path: ThinVec<ast::PathSegment>, filter_fn: FilterFn, ) -> Vec<ImportSuggestion> where @@ -1163,8 +1163,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(x) => Some(x), } { let in_module_is_extern = !in_module.def_id().is_local(); - // We have to visit module children in deterministic order to avoid - // instabilities in reported imports (#43552). in_module.for_each_child(self, |this, ident, ns, name_binding| { // avoid non-importable candidates if !name_binding.is_importable() { @@ -1214,12 +1212,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let res = name_binding.res(); if filter_fn(res) { // create the path - let mut segms = path_segments.clone(); - if lookup_ident.span.at_least_rust_2018() { + let mut segms = if lookup_ident.span.at_least_rust_2018() { // crate-local absolute paths start with `crate::` in edition 2018 // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660) - segms.insert(0, ast::PathSegment::from_ident(crate_name)); - } + crate_path.clone() + } else { + ThinVec::new() + }; + segms.append(&mut path_segments.clone()); segms.push(ast::PathSegment::from_ident(ident)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; @@ -1318,18 +1318,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { where FilterFn: Fn(Res) -> bool, { + let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))]; let mut suggestions = self.lookup_import_candidates_from_module( lookup_ident, namespace, parent_scope, self.graph_root, - Ident::with_dummy_span(kw::Crate), + crate_path, &filter_fn, ); if lookup_ident.span.at_least_rust_2018() { - let extern_prelude_names = self.extern_prelude.clone(); - for (ident, _) in extern_prelude_names.into_iter() { + for ident in self.extern_prelude.clone().into_keys() { if ident.span.from_expansion() { // Idents are adjusted to the root context before being // resolved in the extern prelude, so reporting this to the @@ -1340,13 +1340,43 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)); if let Some(crate_id) = crate_id { - let crate_root = self.expect_module(crate_id.as_def_id()); + let crate_def_id = crate_id.as_def_id(); + let crate_root = self.expect_module(crate_def_id); + + // Check if there's already an item in scope with the same name as the crate. + // If so, we have to disambiguate the potential import suggestions by making + // the paths *global* (i.e., by prefixing them with `::`). + let needs_disambiguation = + self.resolutions(parent_scope.module).borrow().iter().any( + |(key, name_resolution)| { + if key.ns == TypeNS + && key.ident == ident + && let Some(binding) = name_resolution.borrow().binding + { + match binding.res() { + // No disambiguation needed if the identically named item we + // found in scope actually refers to the crate in question. + Res::Def(_, def_id) => def_id != crate_def_id, + Res::PrimTy(_) => true, + _ => false, + } + } else { + false + } + }, + ); + let mut crate_path = ThinVec::new(); + if needs_disambiguation { + crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); + } + crate_path.push(ast::PathSegment::from_ident(ident)); + suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, parent_scope, crate_root, - ident, + crate_path, &filter_fn, )); } @@ -2554,7 +2584,7 @@ fn show_candidates( candidates.iter().for_each(|c| { (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) - .push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import)) + .push((pprust::path_to_string(&c.path), c.descr, c.did, &c.note, c.via_import)) }); // we want consistent results across executions, but candidates are produced diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 462e7e85c65..78e410488c3 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -169,6 +169,9 @@ pub enum MirSpanview { pub enum InstrumentCoverage { /// Default `-C instrument-coverage` or `-C instrument-coverage=statement` All, + /// Additionally, instrument branches and output branch coverage. + /// `-Zunstable-options -C instrument-coverage=branch` + Branch, /// `-Zunstable-options -C instrument-coverage=except-unused-generics` ExceptUnusedGenerics, /// `-Zunstable-options -C instrument-coverage=except-unused-functions` @@ -2736,26 +2739,24 @@ pub fn build_session_options( _ => {} } - // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes - // precedence. - match (cg.instrument_coverage, unstable_opts.instrument_coverage) { - (Some(ic_c), Some(ic_z)) if ic_c != ic_z => { - handler.early_error( - "incompatible values passed for `-C instrument-coverage` \ - and `-Z instrument-coverage`", - ); - } - (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {} - (Some(_), _) if !unstable_opts.unstable_options => { - handler.early_error("`-C instrument-coverage=except-*` requires `-Z unstable-options`"); - } - (None, None) => {} - (None, ic) => { - handler - .early_warn("`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`"); - cg.instrument_coverage = ic; + // Check for unstable values of `-C instrument-coverage`. + // This is what prevents them from being used on stable compilers. + match cg.instrument_coverage { + // Stable values: + Some(InstrumentCoverage::All | InstrumentCoverage::Off) | None => {} + // Unstable values: + Some( + InstrumentCoverage::Branch + | InstrumentCoverage::ExceptUnusedFunctions + | InstrumentCoverage::ExceptUnusedGenerics, + ) => { + if !unstable_opts.unstable_options { + handler.early_error( + "`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \ + require `-Z unstable-options`", + ); + } } - _ => {} } if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c090bcaf9d8..35c167837e5 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -389,7 +389,7 @@ mod desc { pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = - "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`"; + "`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`"; pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; @@ -931,6 +931,7 @@ mod parse { *slot = Some(match v { "all" => InstrumentCoverage::All, + "branch" => InstrumentCoverage::Branch, "except-unused-generics" | "except_unused_generics" => { InstrumentCoverage::ExceptUnusedGenerics } @@ -1356,6 +1357,7 @@ options! { reports (note, the compiler build config must include `profiler = true`); \ implies `-C symbol-mangling-version=v0`. Optional values are: `=all` (implicit value) + `=branch` `=except-unused-generics` `=except-unused-functions` `=off` (default)"), @@ -1591,15 +1593,6 @@ options! { "a default MIR inlining threshold (default: 50)"), input_stats: bool = (false, parse_bool, [UNTRACKED], "gather statistics about the input (default: no)"), - #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] - instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED], - "instrument the generated code to support LLVM source-based code coverage \ - reports (note, the compiler build config must include `profiler = true`); \ - implies `-C symbol-mangling-version=v0`. Optional values are: - `=all` (implicit value) - `=except-unused-generics` - `=except-unused-functions` - `=off` (default)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 79307498165..f823b556154 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -45,7 +45,7 @@ use std::fmt; use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::Arc; +use std::sync::{atomic::AtomicBool, Arc}; use std::time::Duration; pub struct OptimizationFuel { @@ -202,6 +202,12 @@ pub struct Session { /// The version of the rustc process, possibly including a commit hash and description. pub cfg_version: &'static str, + /// The inner atomic value is set to true when a feature marked as `internal` is + /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with + /// internal features are wontfix, and they are usually the cause of the ICEs. + /// None signifies that this is not tracked. + pub using_internal_features: Arc<AtomicBool>, + /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows /// This is mainly useful for other tools that reads that debuginfo to figure out @@ -702,6 +708,10 @@ impl Session { self.opts.cg.instrument_coverage() != InstrumentCoverage::Off } + pub fn instrument_coverage_branch(&self) -> bool { + self.opts.cg.instrument_coverage() == InstrumentCoverage::Branch + } + pub fn instrument_coverage_except_unused_generics(&self) -> bool { self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics } @@ -1385,6 +1395,7 @@ pub fn build_session( target_override: Option<Target>, cfg_version: &'static str, ice_file: Option<PathBuf>, + using_internal_features: Arc<AtomicBool>, expanded_args: Vec<String>, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override @@ -1521,6 +1532,7 @@ pub fn build_session( target_features: Default::default(), unstable_target_features: Default::default(), cfg_version, + using_internal_features, expanded_args, }; diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 41c7d3a8594..47dd7372f3d 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -9,6 +9,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +scoped-tls = "1.0" stable_mir = {path = "../stable_mir" } tracing = "0.1" diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index c24b9efe865..dcf6b904077 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -13,6 +13,7 @@ #![cfg_attr(not(bootstrap), doc(rust_logo))] #![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![cfg_attr(not(bootstrap), allow(internal_features))] +#![allow(rustc::usage_of_ty_tykind)] pub mod rustc_internal; diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index f42a9739320..78144524ac5 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -4,7 +4,7 @@ //! due to incomplete stable coverage. // Prefer importing stable_mir over internal rustc constructs to make this file more readable. -use crate::rustc_smir::{MaybeStable, Tables}; +use crate::rustc_smir::Tables; use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty}; use stable_mir::DefId; @@ -31,7 +31,7 @@ impl<'tcx> RustcInternal<'tcx> for GenericArgKind { match self { GenericArgKind::Lifetime(reg) => reg.internal(tables).into(), GenericArgKind::Type(ty) => ty.internal(tables).into(), - GenericArgKind::Const(cnst) => cnst.internal(tables).into(), + GenericArgKind::Const(cnst) => ty_const(cnst, tables).into(), } } } @@ -46,16 +46,22 @@ impl<'tcx> RustcInternal<'tcx> for Region { impl<'tcx> RustcInternal<'tcx> for Ty { type T = InternalTy<'tcx>; fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { - match tables.types[self.0] { - MaybeStable::Stable(_) => todo!(), - MaybeStable::Rustc(ty) => ty, + tables.types[*self] + } +} + +fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> { + match constant.internal(tables) { + rustc_middle::mir::Const::Ty(c) => c, + cnst => { + panic!("Trying to covert constant `{constant:?}` to type constant, but found {cnst:?}") } } } impl<'tcx> RustcInternal<'tcx> for Const { - type T = rustc_ty::Const<'tcx>; - fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { - todo!() + type T = rustc_middle::mir::Const<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.constants[self.id] } } diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index f7e519570fa..4d2a518226d 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -3,7 +3,7 @@ //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs //! until stable MIR is complete. -use crate::rustc_smir::Tables; +use crate::rustc_smir::{Stable, Tables, TablesWrapper}; use rustc_data_structures::fx; use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::interpret::AllocId; @@ -11,13 +11,24 @@ use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::Span; +use scoped_tls::scoped_thread_local; use stable_mir::ty::IndexedVal; +use std::cell::Cell; +use std::cell::RefCell; use std::fmt::Debug; use std::hash::Hash; use std::ops::Index; mod internal; +pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T { + with_tables(|tables| item.stable(tables)) +} + +pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T { + with_tables(|tables| item.internal(tables)) +} + impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> { type Output = DefId; @@ -125,18 +136,42 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { item.id.into() } +// A thread local variable that stores a pointer to the tables mapping between TyCtxt +// datastructures and stable MIR datastructures +scoped_thread_local! (static TLV: Cell<*const ()>); + +pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) { + assert!(!TLV.is_set()); + let ptr = tables as *const _ as *const (); + TLV.set(&Cell::new(ptr), || { + f(); + }); +} + +/// Loads the current context and calls a function with it. +/// Do not nest these, as that will ICE. +pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R { + assert!(TLV.is_set()); + TLV.with(|tlv| { + let ptr = tlv.get(); + assert!(!ptr.is_null()); + let wrapper = ptr as *const TablesWrapper<'tcx>; + let mut tables = unsafe { (*wrapper).0.borrow_mut() }; + f(&mut *tables) + }) +} + pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { - stable_mir::run( - Tables { - tcx, - def_ids: IndexMap::default(), - alloc_ids: IndexMap::default(), - spans: IndexMap::default(), - types: vec![], - instances: IndexMap::default(), - }, - f, - ); + let tables = TablesWrapper(RefCell::new(Tables { + tcx, + def_ids: IndexMap::default(), + alloc_ids: IndexMap::default(), + spans: IndexMap::default(), + types: IndexMap::default(), + instances: IndexMap::default(), + constants: IndexMap::default(), + })); + stable_mir::run(&tables, || init(&tables, f)); } #[macro_export] @@ -251,7 +286,7 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V /// Trait used to translate a stable construct to its rustc counterpart. /// /// This is basically a mirror of [crate::rustc_smir::Stable]. -pub(crate) trait RustcInternal<'tcx> { +pub trait RustcInternal<'tcx> { type T; fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T; } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index d5379797f1c..86b49eed4d1 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -20,30 +20,35 @@ use rustc_target::abi::FieldIdx; use stable_mir::mir::mono::InstanceDef; use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx}; use stable_mir::ty::{ - FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy, + Const, ConstId, ConstantKind, FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, + Span, TyKind, UintTy, }; use stable_mir::{self, opaque, Context, Filename}; +use std::cell::RefCell; use tracing::debug; mod alloc; mod builder; -impl<'tcx> Context for Tables<'tcx> { +impl<'tcx> Context for TablesWrapper<'tcx> { fn local_crate(&self) -> stable_mir::Crate { - smir_crate(self.tcx, LOCAL_CRATE) + let tables = self.0.borrow(); + smir_crate(tables.tcx, LOCAL_CRATE) } fn external_crates(&self) -> Vec<stable_mir::Crate> { - self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect() + let tables = self.0.borrow(); + tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect() } fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> { + let tables = self.0.borrow(); let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE] .iter() - .chain(self.tcx.crates(()).iter()) + .chain(tables.tcx.crates(()).iter()) .map(|crate_num| { - let crate_name = self.tcx.crate_name(*crate_num).to_string(); - (name == crate_name).then(|| smir_crate(self.tcx, *crate_num)) + let crate_name = tables.tcx.crate_name(*crate_num).to_string(); + (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num)) }) .into_iter() .filter_map(|c| c) @@ -52,212 +57,213 @@ impl<'tcx> Context for Tables<'tcx> { } fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String { - self.tcx.def_path_str(self[def_id]) + let tables = self.0.borrow(); + tables.tcx.def_path_str(tables[def_id]) } fn span_to_string(&self, span: stable_mir::ty::Span) -> String { - self.tcx.sess.source_map().span_to_diagnostic_string(self[span]) + let tables = self.0.borrow(); + tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span]) } fn get_filename(&self, span: &Span) -> Filename { + let tables = self.0.borrow(); opaque( - &self + &tables .tcx .sess .source_map() - .span_to_filename(self[*span]) + .span_to_filename(tables[*span]) .display(rustc_span::FileNameDisplayPreference::Local) .to_string(), ) } fn get_lines(&self, span: &Span) -> LineInfo { - let lines = &self.tcx.sess.source_map().span_to_location_info(self[*span]); + let tables = self.0.borrow(); + let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]); LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 } } - fn def_kind(&mut self, def_id: stable_mir::DefId) -> stable_mir::DefKind { - self.tcx.def_kind(self[def_id]).stable(self) + fn def_kind(&self, def_id: stable_mir::DefId) -> stable_mir::DefKind { + let mut tables = self.0.borrow_mut(); + tables.tcx.def_kind(tables[def_id]).stable(&mut *tables) } - fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> Span { - self.tcx.def_span(self[def_id]).stable(self) + fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { + let mut tables = self.0.borrow_mut(); + tables.tcx.def_span(tables[def_id]).stable(&mut *tables) } - fn all_local_items(&mut self) -> stable_mir::CrateItems { - self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect() + fn all_local_items(&self) -> stable_mir::CrateItems { + let mut tables = self.0.borrow_mut(); + tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect() } - fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> { - Some(self.crate_item(self.tcx.entry_fn(())?.0)) + fn entry_fn(&self) -> Option<stable_mir::CrateItem> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + Some(tables.crate_item(tcx.entry_fn(())?.0)) } - fn all_trait_decls(&mut self) -> stable_mir::TraitDecls { - self.tcx + fn all_trait_decls(&self) -> stable_mir::TraitDecls { + let mut tables = self.0.borrow_mut(); + tables + .tcx .traits(LOCAL_CRATE) .iter() - .map(|trait_def_id| self.trait_def(*trait_def_id)) + .map(|trait_def_id| tables.trait_def(*trait_def_id)) .collect() } - fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { - let def_id = self[trait_def.0]; - let trait_def = self.tcx.trait_def(def_id); - trait_def.stable(self) + fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { + let mut tables = self.0.borrow_mut(); + let def_id = tables[trait_def.0]; + let trait_def = tables.tcx.trait_def(def_id); + trait_def.stable(&mut *tables) } - fn all_trait_impls(&mut self) -> stable_mir::ImplTraitDecls { - self.tcx + fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls { + let mut tables = self.0.borrow_mut(); + tables + .tcx .trait_impls_in_crate(LOCAL_CRATE) .iter() - .map(|impl_def_id| self.impl_def(*impl_def_id)) + .map(|impl_def_id| tables.impl_def(*impl_def_id)) .collect() } - fn trait_impl(&mut self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { - let def_id = self[impl_def.0]; - let impl_trait = self.tcx.impl_trait_ref(def_id).unwrap(); - impl_trait.stable(self) + fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { + let mut tables = self.0.borrow_mut(); + let def_id = tables[impl_def.0]; + let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap(); + impl_trait.stable(&mut *tables) } - fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body { - let def_id = self[item]; - self.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(self) + fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body { + let mut tables = self.0.borrow_mut(); + let def_id = tables[item]; + tables.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(&mut tables) } - fn ty_kind(&mut self, ty: stable_mir::ty::Ty) -> TyKind { - self.types[ty.0].clone().stable(self) + fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind { + let mut tables = self.0.borrow_mut(); + tables.types[ty].kind().stable(&mut *tables) } - fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty { - let n = self.types.len(); - self.types.push(MaybeStable::Stable(kind)); - stable_mir::ty::Ty(n) + fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { + let mut tables = self.0.borrow_mut(); + let def_id = tables[def_id]; + let generics = tables.tcx.generics_of(def_id); + generics.stable(&mut *tables) } - fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { - let def_id = self[def_id]; - let generics = self.tcx.generics_of(def_id); - generics.stable(self) - } - - fn predicates_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { - let def_id = self[def_id]; - let ty::GenericPredicates { parent, predicates } = self.tcx.predicates_of(def_id); + fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { + let mut tables = self.0.borrow_mut(); + let def_id = tables[def_id]; + let ty::GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id); stable_mir::ty::GenericPredicates { - parent: parent.map(|did| self.trait_def(did)), + parent: parent.map(|did| tables.trait_def(did)), predicates: predicates .iter() .map(|(clause, span)| { - (clause.as_predicate().kind().skip_binder().stable(self), span.stable(self)) + ( + clause.as_predicate().kind().skip_binder().stable(&mut *tables), + span.stable(&mut *tables), + ) }) .collect(), } } fn explicit_predicates_of( - &mut self, + &self, def_id: stable_mir::DefId, ) -> stable_mir::ty::GenericPredicates { - let def_id = self[def_id]; - let ty::GenericPredicates { parent, predicates } = self.tcx.explicit_predicates_of(def_id); + let mut tables = self.0.borrow_mut(); + let def_id = tables[def_id]; + let ty::GenericPredicates { parent, predicates } = + tables.tcx.explicit_predicates_of(def_id); stable_mir::ty::GenericPredicates { - parent: parent.map(|did| self.trait_def(did)), + parent: parent.map(|did| tables.trait_def(did)), predicates: predicates .iter() .map(|(clause, span)| { - (clause.as_predicate().kind().skip_binder().stable(self), span.stable(self)) + ( + clause.as_predicate().kind().skip_binder().stable(&mut *tables), + span.stable(&mut *tables), + ) }) .collect(), } } - fn instance_body(&mut self, def: InstanceDef) -> Body { - let instance = self.instances[def]; - builder::BodyBuilder::new(self.tcx, instance).build(self) + fn instance_body(&self, def: InstanceDef) -> Body { + let mut tables = self.0.borrow_mut(); + let instance = tables.instances[def]; + builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables) } - fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty { - let instance = self.instances[def]; - let ty = instance.ty(self.tcx, ParamEnv::empty()); - self.intern_ty(ty) + fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty { + let mut tables = self.0.borrow_mut(); + let instance = tables.instances[def]; + instance.ty(tables.tcx, ParamEnv::empty()).stable(&mut *tables) } - fn instance_def_id(&mut self, def: InstanceDef) -> stable_mir::DefId { - let def_id = self.instances[def].def_id(); - self.create_def_id(def_id) + fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { + let mut tables = self.0.borrow_mut(); + let def_id = tables.instances[def].def_id(); + tables.create_def_id(def_id) } - fn mono_instance(&mut self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance { - let def_id = self[item.0]; - Instance::mono(self.tcx, def_id).stable(self) + fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance { + let mut tables = self.0.borrow_mut(); + let def_id = tables[item.0]; + Instance::mono(tables.tcx, def_id).stable(&mut *tables) } fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool { - let def_id = self[def_id]; - let generics = self.tcx.generics_of(def_id); - let result = generics.requires_monomorphization(self.tcx); + let tables = self.0.borrow(); + let def_id = tables[def_id]; + let generics = tables.tcx.generics_of(def_id); + let result = generics.requires_monomorphization(tables.tcx); result } fn resolve_instance( - &mut self, + &self, def: stable_mir::ty::FnDef, args: &stable_mir::ty::GenericArgs, ) -> Option<stable_mir::mir::mono::Instance> { - let def_id = def.0.internal(self); - let args_ref = args.internal(self); - match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) { - Ok(Some(instance)) => Some(instance.stable(self)), + let mut tables = self.0.borrow_mut(); + let def_id = def.0.internal(&mut *tables); + let args_ref = args.internal(&mut *tables); + match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) { + Ok(Some(instance)) => Some(instance.stable(&mut *tables)), Ok(None) | Err(_) => None, } } } -#[derive(Clone)] -pub enum MaybeStable<S, R> { - Stable(S), - Rustc(R), -} - -impl<'tcx, S, R> MaybeStable<S, R> { - fn stable(self, tables: &mut Tables<'tcx>) -> S - where - R: Stable<'tcx, T = S>, - { - match self { - MaybeStable::Stable(s) => s, - MaybeStable::Rustc(r) => r.stable(tables), - } - } -} - -impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> { - fn eq(&self, other: &R) -> bool { - match self { - MaybeStable::Stable(_) => false, - MaybeStable::Rustc(r) => r == other, - } - } -} +pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>); pub struct Tables<'tcx> { - pub tcx: TyCtxt<'tcx>, - pub def_ids: IndexMap<DefId, stable_mir::DefId>, - pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>, - pub spans: IndexMap<rustc_span::Span, Span>, - pub types: Vec<MaybeStable<TyKind, Ty<'tcx>>>, - pub instances: IndexMap<ty::Instance<'tcx>, InstanceDef>, + pub(crate) tcx: TyCtxt<'tcx>, + pub(crate) def_ids: IndexMap<DefId, stable_mir::DefId>, + pub(crate) alloc_ids: IndexMap<AllocId, stable_mir::AllocId>, + pub(crate) spans: IndexMap<rustc_span::Span, Span>, + pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>, + pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>, + pub(crate) constants: IndexMap<mir::Const<'tcx>, ConstId>, } impl<'tcx> Tables<'tcx> { fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty { - if let Some(id) = self.types.iter().position(|t| *t == ty) { - return stable_mir::ty::Ty(id); - } - let id = self.types.len(); - self.types.push(MaybeStable::Rustc(ty)); - stable_mir::ty::Ty(id) + self.types.create_or_fetch(ty) + } + + fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId { + self.constants.create_or_fetch(constant) } } @@ -270,7 +276,7 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate { } /// Trait used to convert between an internal MIR type to a Stable MIR type. -pub(crate) trait Stable<'tcx> { +pub trait Stable<'tcx> { /// The stable representation of the type implementing Stable. type T; /// Converts an object to the equivalent Stable MIR representation. @@ -281,9 +287,8 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { type T = stable_mir::mir::Body; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - stable_mir::mir::Body { - blocks: self - .basic_blocks + stable_mir::mir::Body::new( + self.basic_blocks .iter() .map(|block| stable_mir::mir::BasicBlock { terminator: block.terminator().stable(tables), @@ -294,15 +299,15 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { .collect(), }) .collect(), - locals: self - .local_decls + self.local_decls .iter() .map(|decl| stable_mir::mir::LocalDecl { - ty: tables.intern_ty(decl.ty), + ty: decl.ty.stable(tables), span: decl.source_info.span.stable(tables), }) .collect(), - } + self.arg_count, + ) } } @@ -396,7 +401,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast( cast_kind.stable(tables), op.stable(tables), - tables.intern_ty(*ty), + ty.stable(tables), ), BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp( bin_op.stable(tables), @@ -409,7 +414,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { ops.1.stable(tables), ), NullaryOp(null_op, ty) => { - stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), tables.intern_ty(*ty)) + stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables)) } UnaryOp(un_op, op) => { stable_mir::mir::Rvalue::UnaryOp(un_op.stable(tables), op.stable(tables)) @@ -420,7 +425,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { stable_mir::mir::Rvalue::Aggregate(agg_kind.stable(tables), operands) } ShallowInitBox(op, ty) => { - stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), tables.intern_ty(*ty)) + stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables)) } CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)), } @@ -564,7 +569,7 @@ impl<'tcx> Stable<'tcx> for ty::TermKind<'tcx> { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use stable_mir::ty::TermKind; match self { - ty::TermKind::Ty(ty) => TermKind::Type(tables.intern_ty(*ty)), + ty::TermKind::Ty(ty) => TermKind::Type(ty.stable(tables)), ty::TermKind::Const(cnst) => { let cnst = cnst.stable(tables); TermKind::Const(cnst) @@ -845,7 +850,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { match self { mir::AggregateKind::Array(ty) => { - stable_mir::mir::AggregateKind::Array(tables.intern_ty(*ty)) + stable_mir::mir::AggregateKind::Array(ty.stable(tables)) } mir::AggregateKind::Tuple => stable_mir::mir::AggregateKind::Tuple, mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => { @@ -877,13 +882,13 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { type T = stable_mir::mir::CoroutineKind; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - use rustc_hir::{AsyncCoroutineKind, CoroutineKind}; + use rustc_hir::{CoroutineKind, CoroutineSource}; match self { CoroutineKind::Async(async_gen) => { let async_gen = match async_gen { - AsyncCoroutineKind::Block => stable_mir::mir::AsyncCoroutineKind::Block, - AsyncCoroutineKind::Closure => stable_mir::mir::AsyncCoroutineKind::Closure, - AsyncCoroutineKind::Fn => stable_mir::mir::AsyncCoroutineKind::Fn, + CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block, + CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure, + CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn, }; stable_mir::mir::CoroutineKind::Async(async_gen) } @@ -1013,7 +1018,7 @@ impl<'tcx> Stable<'tcx> for ty::GenericArgKind<'tcx> { use stable_mir::ty::GenericArgKind; match self { ty::GenericArgKind::Lifetime(region) => GenericArgKind::Lifetime(region.stable(tables)), - ty::GenericArgKind::Type(ty) => GenericArgKind::Type(tables.intern_ty(*ty)), + ty::GenericArgKind::Type(ty) => GenericArgKind::Type(ty.stable(tables)), ty::GenericArgKind::Const(cnst) => GenericArgKind::Const(cnst.stable(tables)), } } @@ -1059,11 +1064,7 @@ impl<'tcx> Stable<'tcx> for ty::FnSig<'tcx> { use stable_mir::ty::{Abi, FnSig}; FnSig { - inputs_and_output: self - .inputs_and_output - .iter() - .map(|ty| tables.intern_ty(ty)) - .collect(), + inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(), c_variadic: self.c_variadic, unsafety: self.unsafety.stable(tables), abi: match self.abi { @@ -1201,9 +1202,16 @@ impl<'tcx> Stable<'tcx> for hir::Movability { } impl<'tcx> Stable<'tcx> for Ty<'tcx> { + type T = stable_mir::ty::Ty; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.intern_ty(*self) + } +} + +impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { type T = stable_mir::ty::TyKind; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - match self.kind() { + match self { ty::Bool => TyKind::RigidTy(RigidTy::Bool), ty::Char => TyKind::RigidTy(RigidTy::Char), ty::Int(int_ty) => TyKind::RigidTy(RigidTy::Int(int_ty.stable(tables))), @@ -1216,15 +1224,15 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> { ty::Foreign(def_id) => TyKind::RigidTy(RigidTy::Foreign(tables.foreign_def(*def_id))), ty::Str => TyKind::RigidTy(RigidTy::Str), ty::Array(ty, constant) => { - TyKind::RigidTy(RigidTy::Array(tables.intern_ty(*ty), constant.stable(tables))) + TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables))) } - ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(tables.intern_ty(*ty))), + ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))), ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => { - TyKind::RigidTy(RigidTy::RawPtr(tables.intern_ty(*ty), mutbl.stable(tables))) + TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables))) } ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref( region.stable(tables), - tables.intern_ty(*ty), + ty.stable(tables), mutbl.stable(tables), )), ty::FnDef(def_id, generic_args) => { @@ -1251,9 +1259,9 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> { movability.stable(tables), )), ty::Never => TyKind::RigidTy(RigidTy::Never), - ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple( - fields.iter().map(|ty| tables.intern_ty(ty)).collect(), - )), + ty::Tuple(fields) => { + TyKind::RigidTy(RigidTy::Tuple(fields.iter().map(|ty| ty.stable(tables)).collect())) + } ty::Alias(alias_kind, alias_ty) => { TyKind::Alias(alias_kind.stable(tables), alias_ty.stable(tables)) } @@ -1272,32 +1280,32 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { type T = stable_mir::ty::Const; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - stable_mir::ty::Const { - literal: match self.kind() { - ty::Value(val) => { - let const_val = tables.tcx.valtree_to_const_val((self.ty(), val)); - stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( - self.ty(), - const_val, - tables, - )) - } - ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)), - ty::ErrorCt(_) => unreachable!(), - ty::InferCt(_) => unreachable!(), - ty::BoundCt(_, _) => unimplemented!(), - ty::PlaceholderCt(_) => unimplemented!(), - ty::Unevaluated(uv) => { - stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { - def: tables.const_def(uv.def), - args: uv.args.stable(tables), - promoted: None, - }) - } - ty::ExprCt(_) => unimplemented!(), - }, - ty: tables.intern_ty(self.ty()), - } + let kind = match self.kind() { + ty::Value(val) => { + let const_val = tables.tcx.valtree_to_const_val((self.ty(), val)); + stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( + self.ty(), + const_val, + tables, + )) + } + ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)), + ty::ErrorCt(_) => unreachable!(), + ty::InferCt(_) => unreachable!(), + ty::BoundCt(_, _) => unimplemented!(), + ty::PlaceholderCt(_) => unimplemented!(), + ty::Unevaluated(uv) => { + stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { + def: tables.const_def(uv.def), + args: uv.args.stable(tables), + promoted: None, + }) + } + ty::ExprCt(_) => unimplemented!(), + }; + let ty = self.ty().stable(tables); + let id = tables.intern_const(mir::Const::Ty(*self)); + Const::new(kind, ty, id) } } @@ -1382,22 +1390,23 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { match *self { mir::Const::Ty(c) => c.stable(tables), - mir::Const::Unevaluated(unev_const, ty) => stable_mir::ty::Const { - literal: stable_mir::ty::ConstantKind::Unevaluated( - stable_mir::ty::UnevaluatedConst { + mir::Const::Unevaluated(unev_const, ty) => { + let kind = + stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { def: tables.const_def(unev_const.def), args: unev_const.args.stable(tables), promoted: unev_const.promoted.map(|u| u.as_u32()), - }, - ), - ty: tables.intern_ty(ty), - }, - mir::Const::Val(val, ty) => stable_mir::ty::Const { - literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( - ty, val, tables, - )), - ty: tables.intern_ty(ty), - }, + }); + let ty = ty.stable(tables); + let id = tables.intern_const(*self); + Const::new(kind, ty, id) + } + mir::Const::Val(val, ty) => { + let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables)); + let ty = ty.stable(tables); + let id = tables.intern_const(*self); + Const::new(kind, ty, id) + } } } } @@ -1511,30 +1520,32 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { type T = stable_mir::ty::ClauseKind; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { - use ty::ClauseKind::*; + use ty::ClauseKind; match *self { - Trait(trait_object) => stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables)), - RegionOutlives(region_outlives) => { + ClauseKind::Trait(trait_object) => { + stable_mir::ty::ClauseKind::Trait(trait_object.stable(tables)) + } + ClauseKind::RegionOutlives(region_outlives) => { stable_mir::ty::ClauseKind::RegionOutlives(region_outlives.stable(tables)) } - TypeOutlives(type_outlives) => { + ClauseKind::TypeOutlives(type_outlives) => { let ty::OutlivesPredicate::<_, _>(a, b) = type_outlives; stable_mir::ty::ClauseKind::TypeOutlives(stable_mir::ty::OutlivesPredicate( - tables.intern_ty(a), + a.stable(tables), b.stable(tables), )) } - Projection(projection_predicate) => { + ClauseKind::Projection(projection_predicate) => { stable_mir::ty::ClauseKind::Projection(projection_predicate.stable(tables)) } - ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType( + ClauseKind::ConstArgHasType(const_, ty) => stable_mir::ty::ClauseKind::ConstArgHasType( const_.stable(tables), - tables.intern_ty(ty), + ty.stable(tables), ), - WellFormed(generic_arg) => { + ClauseKind::WellFormed(generic_arg) => { stable_mir::ty::ClauseKind::WellFormed(generic_arg.unpack().stable(tables)) } - ConstEvaluatable(const_) => { + ClauseKind::ConstEvaluatable(const_) => { stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables)) } } @@ -1559,7 +1570,7 @@ impl<'tcx> Stable<'tcx> for ty::SubtypePredicate<'tcx> { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { let ty::SubtypePredicate { a, b, a_is_expected: _ } = self; - stable_mir::ty::SubtypePredicate { a: tables.intern_ty(*a), b: tables.intern_ty(*b) } + stable_mir::ty::SubtypePredicate { a: a.stable(tables), b: b.stable(tables) } } } @@ -1568,7 +1579,7 @@ impl<'tcx> Stable<'tcx> for ty::CoercePredicate<'tcx> { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { let ty::CoercePredicate { a, b } = self; - stable_mir::ty::CoercePredicate { a: tables.intern_ty(*a), b: tables.intern_ty(*b) } + stable_mir::ty::CoercePredicate { a: a.stable(tables), b: b.stable(tables) } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 38ae8f570e9..ff61143a12b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -910,6 +910,7 @@ symbols! { iter, iter_mut, iter_repeat, + iterator, iterator_collect_fn, kcfi, keyword, @@ -957,6 +958,7 @@ symbols! { log_syntax, logf32, logf64, + loongarch_target_feature, loop_break_value, lt, macro_at_most_once_rep, diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/abi/call/csky.rs index bbe95fa20ac..706493b0a6a 100644 --- a/compiler/rustc_target/src/abi/call/csky.rs +++ b/compiler/rustc_target/src/abi/call/csky.rs @@ -1,17 +1,39 @@ -// See https://github.com/llvm/llvm-project/blob/d85b94bf0080dcd780656c0f5e6342800720eba9/llvm/lib/Target/CSKY/CSKYCallingConv.td -use crate::abi::call::{ArgAbi, FnAbi}; +// Reference: CSKY ABI Manual +// https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1695027452256/T-HEAD_800_Series_ABI_Standards_Manual.pdf +// +// Reference: Clang CSKY lowering code +// https://github.com/llvm/llvm-project/blob/4a074f32a6914f2a8d7215d78758c24942dddc3d/clang/lib/CodeGen/Targets/CSKY.cpp#L76-L162 -fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) { - if ret.layout.is_aggregate() || ret.layout.size.bits() > 64 { - ret.make_indirect(); +use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform}; + +fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) { + // For return type, aggregate which <= 2*XLen will be returned in registers. + // Otherwise, aggregate will be returned indirectly. + if arg.layout.is_aggregate() { + let total = arg.layout.size; + if total.bits() > 64 { + arg.make_indirect(); + } else if total.bits() > 32 { + arg.cast_to(Uniform { unit: Reg::i32(), total }); + } else { + arg.cast_to(Reg::i32()); + } } else { - ret.extend_integer_width_to(32); + arg.extend_integer_width_to(32); } } fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) { - if arg.layout.is_aggregate() || arg.layout.size.bits() > 64 { - arg.make_indirect(); + // For argument type, the first 4*XLen parts of aggregate will be passed + // in registers, and the rest will be passed in stack. + // So we can coerce to integers directly and let backend handle it correctly. + if arg.layout.is_aggregate() { + let total = arg.layout.size; + if total.bits() > 32 { + arg.cast_to(Uniform { unit: Reg::i32(), total }); + } else { + arg.cast_to(Reg::i32()); + } } else { arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 20253b32add..a9792ca2795 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -28,6 +28,11 @@ trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-claus .label = invalid on-clause here trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute + .help = only `message`, `note` and `label` are allowed as options + .label = invalid option found here + +trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute + .help = at least one of the `message`, `note` and `label` options are expected trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> [none] {""} diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 0c214ca8753..6562bc86f99 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -37,6 +37,8 @@ pub(super) trait GoalKind<'tcx>: fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; + fn polarity(self) -> ty::ImplPolarity; + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs index 4950a444ffb..be631552c57 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs @@ -101,6 +101,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { self.projection_ty.trait_ref(tcx) } + fn polarity(self) -> ty::ImplPolarity { + ty::ImplPolarity::Positive + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index fa91a125b6a..7c4f6562f10 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -22,6 +22,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { self.trait_ref } + fn polarity(self) -> ty::ImplPolarity { + self.polarity + } + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } @@ -238,14 +242,25 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - if goal.predicate.polarity != ty::ImplPolarity::Positive { - return Err(NoSolution); - } - - if let ty::FnPtr(..) = goal.predicate.self_ty().kind() { - ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) - } else { - Err(NoSolution) + let self_ty = goal.predicate.self_ty(); + match goal.predicate.polarity { + ty::ImplPolarity::Positive => { + if self_ty.is_fn_ptr() { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } + ty::ImplPolarity::Negative => { + // If a type is rigid and not a fn ptr, then we know for certain + // that it does *not* implement `FnPtr`. + if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() { + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + Err(NoSolution) + } + } + ty::ImplPolarity::Reservation => bug!(), } } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 29b0c7189f9..dcf5fd86929 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -9,20 +9,18 @@ use crate::infer::InferOk; use crate::solve::inspect; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; use crate::traits::engine::TraitEngineExt; -use crate::traits::outlives_bounds::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; use crate::traits::structural_normalize::StructurallyNormalizeExt; -use crate::traits::util::impl_subject_and_oblig; use crate::traits::NormalizeExt; use crate::traits::SkipLeakCheck; use crate::traits::{ - self, Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations, + Obligation, ObligationCause, ObligationCtxt, PredicateObligation, PredicateObligations, SelectionContext, }; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; -use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, TraitEngine}; use rustc_middle::traits::query::NoSolution; @@ -32,12 +30,11 @@ use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE; use rustc_span::symbol::sym; use rustc_span::DUMMY_SP; use std::fmt::Debug; -use std::iter; use std::ops::ControlFlow; /// Whether we do the orphan check relative to this crate or @@ -142,16 +139,13 @@ pub fn overlapping_impls( Some(overlap) } -fn with_fresh_ty_vars<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - impl_def_id: DefId, -) -> ty::ImplHeader<'tcx> { - let tcx = selcx.tcx(); - let impl_args = selcx.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); +fn fresh_impl_header<'tcx>(infcx: &InferCtxt<'tcx>, impl_def_id: DefId) -> ty::ImplHeader<'tcx> { + let tcx = infcx.tcx; + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); - let header = ty::ImplHeader { + ty::ImplHeader { impl_def_id, + impl_args, self_ty: tcx.type_of(impl_def_id).instantiate(tcx, impl_args), trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.instantiate(tcx, impl_args)), predicates: tcx @@ -160,10 +154,18 @@ fn with_fresh_ty_vars<'cx, 'tcx>( .iter() .map(|(c, _)| c.as_predicate()) .collect(), - }; + } +} + +fn fresh_impl_header_normalized<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + impl_def_id: DefId, +) -> ty::ImplHeader<'tcx> { + let header = fresh_impl_header(infcx, impl_def_id); let InferOk { value: mut header, obligations } = - selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(header); + infcx.at(&ObligationCause::dummy(), param_env).normalize(header); header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); header @@ -206,12 +208,13 @@ fn overlap<'tcx>( // empty environment. let param_env = ty::ParamEnv::empty(); - let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id); - let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id); + let impl1_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl1_def_id); + let impl2_header = fresh_impl_header_normalized(selcx.infcx, param_env, impl2_def_id); // Equate the headers to find their intersection (the general type, with infer vars, // that may apply both impls). - let mut obligations = equate_impl_headers(selcx.infcx, &impl1_header, &impl2_header)?; + let mut obligations = + equate_impl_headers(selcx.infcx, param_env, &impl1_header, &impl2_header)?; debug!("overlap: unification check succeeded"); obligations.extend( @@ -312,20 +315,22 @@ fn overlap<'tcx>( #[instrument(level = "debug", skip(infcx), ret)] fn equate_impl_headers<'tcx>( infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, impl1: &ty::ImplHeader<'tcx>, impl2: &ty::ImplHeader<'tcx>, ) -> Option<PredicateObligations<'tcx>> { - let result = match (impl1.trait_ref, impl2.trait_ref) { - (Some(impl1_ref), Some(impl2_ref)) => infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref), - (None, None) => infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( - DefineOpaqueTypes::Yes, - impl1.self_ty, - impl2.self_ty, - ), - _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), - }; + let result = + match (impl1.trait_ref, impl2.trait_ref) { + (Some(impl1_ref), Some(impl2_ref)) => infcx + .at(&ObligationCause::dummy(), param_env) + .eq(DefineOpaqueTypes::Yes, impl1_ref, impl2_ref), + (None, None) => infcx.at(&ObligationCause::dummy(), param_env).eq( + DefineOpaqueTypes::Yes, + impl1.self_ty, + impl2.self_ty, + ), + _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), + }; result.map(|infer_ok| infer_ok.obligations).ok() } @@ -391,107 +396,182 @@ fn impl_intersection_has_negative_obligation( ) -> bool { debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id); - // Create an infcx, taking the predicates of impl1 as assumptions: - let infcx = tcx.infer_ctxt().build(); - // create a parameter environment corresponding to a (placeholder) instantiation of impl1 - let impl_env = tcx.param_env(impl1_def_id); - let subject1 = match traits::fully_normalize( - &infcx, - ObligationCause::dummy(), - impl_env, - tcx.impl_subject(impl1_def_id).instantiate_identity(), - ) { - Ok(s) => s, - Err(err) => { - tcx.sess.delay_span_bug( - tcx.def_span(impl1_def_id), - format!("failed to fully normalize {impl1_def_id:?}: {err:?}"), - ); - return false; - } - }; + let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build(); + let universe = infcx.universe(); - // Attempt to prove that impl2 applies, given all of the above. - let selcx = &mut SelectionContext::new(&infcx); - let impl2_args = infcx.fresh_args_for_item(DUMMY_SP, impl2_def_id); - let (subject2, normalization_obligations) = - impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_args, |_, _| { - ObligationCause::dummy() - }); - - // do the impls unify? If not, then it's not currently possible to prove any - // obligations about their intersection. - let Ok(InferOk { obligations: equate_obligations, .. }) = - infcx.at(&ObligationCause::dummy(), impl_env).eq(DefineOpaqueTypes::No, subject1, subject2) + let impl1_header = fresh_impl_header(infcx, impl1_def_id); + let param_env = + ty::EarlyBinder::bind(tcx.param_env(impl1_def_id)).instantiate(tcx, impl1_header.impl_args); + + let impl2_header = fresh_impl_header(infcx, impl2_def_id); + + // Equate the headers to find their intersection (the general type, with infer vars, + // that may apply both impls). + let Some(_equate_obligations) = + equate_impl_headers(infcx, param_env, &impl1_header, &impl2_header) else { - debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2); return false; }; - for obligation in normalization_obligations.into_iter().chain(equate_obligations) { - if negative_impl_exists(&infcx, &obligation, impl1_def_id) { - debug!("overlap: obligation unsatisfiable {:?}", obligation); - return true; - } - } + plug_infer_with_placeholders(infcx, universe, (impl1_header.impl_args, impl2_header.impl_args)); - false + util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args)) + .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env)) } -/// Try to prove that a negative impl exist for the obligation or its supertraits. -/// -/// If such a negative impl exists, then the obligation definitely must not hold -/// due to coherence, even if it's not necessarily "knowable" in this crate. Any -/// valid impl downstream would not be able to exist due to the overlapping -/// negative impl. -#[instrument(level = "debug", skip(infcx))] -fn negative_impl_exists<'tcx>( +fn plug_infer_with_placeholders<'tcx>( infcx: &InferCtxt<'tcx>, - o: &PredicateObligation<'tcx>, - body_def_id: DefId, -) -> bool { - // Try to prove a negative obligation exists for super predicates - for pred in util::elaborate(infcx.tcx, iter::once(o.predicate)) { - if prove_negated_obligation(infcx.fork(), &o.with(infcx.tcx, pred), body_def_id) { - return true; + universe: ty::UniverseIndex, + value: impl TypeVisitable<TyCtxt<'tcx>>, +) { + struct PlugInferWithPlaceholder<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + universe: ty::UniverseIndex, + var: ty::BoundVar, + } + + impl<'tcx> PlugInferWithPlaceholder<'_, 'tcx> { + fn next_var(&mut self) -> ty::BoundVar { + let var = self.var; + self.var = self.var + 1; + var + } + } + + impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlugInferWithPlaceholder<'_, 'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + let ty = self.infcx.shallow_resolve(ty); + if ty.is_ty_var() { + let Ok(InferOk { value: (), obligations }) = + self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( + DefineOpaqueTypes::No, + ty, + Ty::new_placeholder( + self.infcx.tcx, + ty::Placeholder { + universe: self.universe, + bound: ty::BoundTy { + var: self.next_var(), + kind: ty::BoundTyKind::Anon, + }, + }, + ), + ) + else { + bug!() + }; + assert_eq!(obligations, &[]); + ControlFlow::Continue(()) + } else { + ty.super_visit_with(self) + } + } + + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { + let ct = self.infcx.shallow_resolve(ct); + if ct.is_ct_infer() { + let Ok(InferOk { value: (), obligations }) = + self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( + DefineOpaqueTypes::No, + ct, + ty::Const::new_placeholder( + self.infcx.tcx, + ty::Placeholder { universe: self.universe, bound: self.next_var() }, + ct.ty(), + ), + ) + else { + bug!() + }; + assert_eq!(obligations, &[]); + ControlFlow::Continue(()) + } else { + ct.super_visit_with(self) + } + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + if let ty::ReVar(vid) = *r { + let r = self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(self.infcx.tcx, vid); + if r.is_var() { + let Ok(InferOk { value: (), obligations }) = + self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( + DefineOpaqueTypes::No, + r, + ty::Region::new_placeholder( + self.infcx.tcx, + ty::Placeholder { + universe: self.universe, + bound: ty::BoundRegion { + var: self.next_var(), + kind: ty::BoundRegionKind::BrAnon, + }, + }, + ), + ) + else { + bug!() + }; + assert_eq!(obligations, &[]); + } + } + ControlFlow::Continue(()) } } - false + value.visit_with(&mut PlugInferWithPlaceholder { + infcx, + universe, + var: ty::BoundVar::from_u32(0), + }); } -#[instrument(level = "debug", skip(infcx))] -fn prove_negated_obligation<'tcx>( - infcx: InferCtxt<'tcx>, - o: &PredicateObligation<'tcx>, - body_def_id: DefId, +fn try_prove_negated_where_clause<'tcx>( + root_infcx: &InferCtxt<'tcx>, + clause: ty::Clause<'tcx>, + param_env: ty::ParamEnv<'tcx>, ) -> bool { - let tcx = infcx.tcx; - - let Some(o) = o.flip_polarity(tcx) else { + let Some(negative_predicate) = clause.as_predicate().flip_polarity(root_infcx.tcx) else { return false; }; - let param_env = o.param_env; - let ocx = ObligationCtxt::new(&infcx); - ocx.register_obligation(o); - let errors = ocx.select_all_or_error(); - if !errors.is_empty() { + // FIXME(with_negative_coherence): the infcx has region contraints from equating + // the impl headers as requirements. Given that the only region constraints we + // get are involving inference regions in the root, it shouldn't matter, but + // still sus. + // + // We probably should just throw away the region obligations registered up until + // now, or ideally use them as assumptions when proving the region obligations + // that we get from proving the negative predicate below. + let ref infcx = root_infcx.fork(); + let ocx = ObligationCtxt::new(infcx); + + ocx.register_obligation(Obligation::new( + infcx.tcx, + ObligationCause::dummy(), + param_env, + negative_predicate, + )); + if !ocx.select_all_or_error().is_empty() { return false; } - let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID); + // FIXME: We could use the assumed_wf_types from both impls, I think, + // if that wasn't implemented just for LocalDefId, and we'd need to do + // the normalization ourselves since this is totally fallible... + let outlives_env = OutlivesEnvironment::new(param_env); - let ocx = ObligationCtxt::new(&infcx); - let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id) else { + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { return false; - }; + } - let outlives_env = OutlivesEnvironment::with_bounds( - param_env, - infcx.implied_bounds_tys(param_env, body_def_id, wf_tys), - ); - infcx.resolve_regions(&outlives_env).is_empty() + true } /// Returns whether all impls which would apply to the `trait_ref` @@ -506,13 +586,6 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>( trait_ref: ty::TraitRef<'tcx>, mut lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>, ) -> Result<Result<(), Conflict>, E> { - if Some(trait_ref.def_id) == tcx.lang_items().fn_ptr_trait() { - // The only types implementing `FnPtr` are function pointers, - // so if there's no impl of `FnPtr` in the current crate, - // then such an impl will never be added in the future. - return Ok(Ok(())); - } - if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() { // A downstream or cousin crate is allowed to implement some // substitution of this trait-ref. diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 88f47b03cc8..d9a1a98191d 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -37,10 +37,10 @@ impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => { Box::new(FulfillmentContext::new(infcx)) } - (TraitSolver::Next | TraitSolver::NextCoherence, true) => { + (TraitSolver::Classic | TraitSolver::Next | TraitSolver::NextCoherence, true) => { Box::new(NextFulfillmentCtxt::new(infcx)) } - _ => bug!( + (TraitSolver::Next, false) => bug!( "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver() diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 016c44c20f6..c96e41b88bd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -1,5 +1,8 @@ use super::{ObligationCauseCode, PredicateObligation}; use crate::infer::error_reporting::TypeErrCtxt; +use rustc_ast::AttrArgs; +use rustc_ast::AttrArgsEq; +use rustc_ast::AttrKind; use rustc_ast::{Attribute, MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; @@ -342,7 +345,22 @@ pub enum AppendConstMessage { #[derive(LintDiagnostic)] #[diag(trait_selection_malformed_on_unimplemented_attr)] -pub struct NoValueInOnUnimplementedLint; +#[help] +pub struct MalformedOnUnimplementedAttrLint { + #[label] + pub span: Span, +} + +impl MalformedOnUnimplementedAttrLint { + fn new(span: Span) -> Self { + Self { span } + } +} + +#[derive(LintDiagnostic)] +#[diag(trait_selection_missing_options_for_on_unimplemented_attr)] +#[help] +pub struct MissingOptionsForOnUnimplementedAttr; impl<'tcx> OnUnimplementedDirective { fn parse( @@ -453,7 +471,7 @@ impl<'tcx> OnUnimplementedDirective { UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), vec![item.span()], - NoValueInOnUnimplementedLint, + MalformedOnUnimplementedAttrLint::new(item.span()), ); } else { // nothing found @@ -530,21 +548,40 @@ impl<'tcx> OnUnimplementedDirective { append_const_msg: None, })) } else { + let item = attr.get_normal_item(); + let report_span = match &item.args { + AttrArgs::Empty => item.path.span, + AttrArgs::Delimited(args) => args.dspan.entire(), + AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => eq_span.to(expr.span), + AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span), + }; + tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), - attr.span, - NoValueInOnUnimplementedLint, + report_span, + MalformedOnUnimplementedAttrLint::new(report_span), ); Ok(None) } } else if is_diagnostic_namespace_variant { - tcx.emit_spanned_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), - attr.span, - NoValueInOnUnimplementedLint, - ); + match &attr.kind { + AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + attr.span, + MalformedOnUnimplementedAttrLint::new(attr.span), + ); + } + _ => tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + attr.span, + MissingOptionsForOnUnimplementedAttr, + ), + }; + Ok(None) } else { let reported = diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 78b466907b3..b9a08056ad1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; -use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Node}; +use rustc_hir::{CoroutineKind, CoroutineSource, Node}; use rustc_hir::{Expr, HirId}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -2410,7 +2410,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .and_then(|coroutine_did| { Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() { CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"), - CoroutineKind::Async(AsyncCoroutineKind::Fn) => self + CoroutineKind::Async(CoroutineSource::Fn) => self .tcx .parent(coroutine_did) .as_local() @@ -2419,10 +2419,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .map(|name| { format!("future returned by `{name}` is not {trait_name}") })?, - CoroutineKind::Async(AsyncCoroutineKind::Block) => { + CoroutineKind::Async(CoroutineSource::Block) => { format!("future created by async block is not {trait_name}") } - CoroutineKind::Async(AsyncCoroutineKind::Closure) => { + CoroutineKind::Async(CoroutineSource::Closure) => { format!("future created by async closure is not {trait_name}") } }) @@ -2995,11 +2995,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let sp = self.tcx.def_span(def_id); // Special-case this to say "async block" instead of `[static coroutine]`. - let kind = tcx.coroutine_kind(def_id).unwrap().descr(); + let kind = tcx.coroutine_kind(def_id).unwrap(); err.span_note( sp, with_forced_trimmed_paths!(format!( - "required because it's used within this {kind}", + "required because it's used within this {kind:#}", )), ) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 1245b4a7756..353a69ef6d3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1611,9 +1611,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> { self.tcx.hir().body(body_id).coroutine_kind.map(|gen_kind| match gen_kind { hir::CoroutineKind::Coroutine => "a coroutine", - hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) => "an async block", - hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn) => "an async function", - hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure) => "an async closure", + hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block", + hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function", + hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure", }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 55b5604b16b..fb9cf51b513 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,5 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; +use rustc_data_structures::captures::Captures; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; @@ -68,7 +69,7 @@ pub struct PendingPredicateObligation<'tcx> { // should mostly optimize for reading speed, while modifying is not as relevant. // // For whatever reason using a boxed slice is slower than using a `Vec` here. - pub stalled_on: Vec<TyOrConstInferVar<'tcx>>, + pub stalled_on: Vec<TyOrConstInferVar>, } // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -669,7 +670,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { &mut self, obligation: &PredicateObligation<'tcx>, trait_obligation: PolyTraitObligation<'tcx>, - stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, + stalled_on: &mut Vec<TyOrConstInferVar>, ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let infcx = self.selcx.infcx; if obligation.predicate.is_global() && !self.selcx.is_intercrate() { @@ -722,7 +723,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { &mut self, obligation: &PredicateObligation<'tcx>, project_obligation: PolyProjectionObligation<'tcx>, - stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, + stalled_on: &mut Vec<TyOrConstInferVar>, ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { let tcx = self.selcx.tcx(); @@ -775,7 +776,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { fn args_infer_vars<'a, 'tcx>( selcx: &SelectionContext<'a, 'tcx>, args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, -) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> { +) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> { selcx .infcx .resolve_vars_if_possible(args) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 2d05f934393..dfc4bdf1484 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -97,6 +97,10 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { /// object. Note that object-safe traits can have some /// non-vtable-safe methods, so long as they require `Self: Sized` or /// otherwise ensure that they cannot be used when `Self = Trait`. +/// +/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards +/// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and +/// [`WHERE_CLAUSES_OBJECT_SAFETY`]. pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); @@ -105,10 +109,9 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A return false; } - match virtual_call_violation_for_method(tcx, trait_def_id, method) { - None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, - Some(_) => false, - } + virtual_call_violations_for_method(tcx, trait_def_id, method) + .iter() + .all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf)) } fn object_safety_violations_for_trait( @@ -119,7 +122,7 @@ fn object_safety_violations_for_trait( let mut violations: Vec<_> = tcx .associated_items(trait_def_id) .in_definition_order() - .filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item)) + .flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item)) .collect(); // Check the trait itself. @@ -357,49 +360,52 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// Returns `Some(_)` if this item makes the containing trait not object safe. #[instrument(level = "debug", skip(tcx), ret)] -fn object_safety_violation_for_assoc_item( +fn object_safety_violations_for_assoc_item( tcx: TyCtxt<'_>, trait_def_id: DefId, item: ty::AssocItem, -) -> Option<ObjectSafetyViolation> { +) -> Vec<ObjectSafetyViolation> { // Any item that has a `Self : Sized` requisite is otherwise // exempt from the regulations. if tcx.generics_require_sized_self(item.def_id) { - return None; + return Vec::new(); } match item.kind { // Associated consts are never object safe, as they can't have `where` bounds yet at all, // and associated const bounds in trait objects aren't a thing yet either. ty::AssocKind::Const => { - Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)) + vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)] } - ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| { - let node = tcx.hir().get_if_local(item.def_id); - // Get an accurate span depending on the violation. - let span = match (&v, node) { - (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, - (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, - (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, - (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { - node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) - } - _ => item.ident(tcx).span, - }; + ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) + .into_iter() + .map(|v| { + let node = tcx.hir().get_if_local(item.def_id); + // Get an accurate span depending on the violation. + let span = match (&v, node) { + (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, + (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, + (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, + (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { + node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) + } + _ => item.ident(tcx).span, + }; - ObjectSafetyViolation::Method(item.name, v, span) - }), + ObjectSafetyViolation::Method(item.name, v, span) + }) + .collect(), // Associated types can only be object safe if they have `Self: Sized` bounds. ty::AssocKind::Type => { if !tcx.features().generic_associated_types_extended && !tcx.generics_of(item.def_id).params.is_empty() && !item.is_impl_trait_in_trait() { - Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)) + vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)] } else { // We will permit associated types if they are explicitly mentioned in the trait object. // We can't check this here, as here we only check if it is guaranteed to not be possible. - None + Vec::new() } } } @@ -409,11 +415,11 @@ fn object_safety_violation_for_assoc_item( /// object; this does not necessarily imply that the enclosing trait /// is not object safe, because the method might have a where clause /// `Self:Sized`. -fn virtual_call_violation_for_method<'tcx>( +fn virtual_call_violations_for_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: ty::AssocItem, -) -> Option<MethodViolationCode> { +) -> Vec<MethodViolationCode> { let sig = tcx.fn_sig(method.def_id).instantiate_identity(); // The method's first parameter must be named `self` @@ -438,9 +444,14 @@ fn virtual_call_violation_for_method<'tcx>( } else { None }; - return Some(MethodViolationCode::StaticMethod(sugg)); + + // Not having `self` parameter messes up the later checks, + // so we need to return instead of pushing + return vec![MethodViolationCode::StaticMethod(sugg)]; } + let mut errors = Vec::new(); + for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) { if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { let span = if let Some(hir::Node::TraitItem(hir::TraitItem { @@ -452,20 +463,20 @@ fn virtual_call_violation_for_method<'tcx>( } else { None }; - return Some(MethodViolationCode::ReferencesSelfInput(span)); + errors.push(MethodViolationCode::ReferencesSelfInput(span)); } } if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { - return Some(MethodViolationCode::ReferencesSelfOutput); + errors.push(MethodViolationCode::ReferencesSelfOutput); } if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) { - return Some(code); + errors.push(code); } // We can't monomorphize things like `fn foo<A>(...)`. let own_counts = tcx.generics_of(method.def_id).own_counts(); - if own_counts.types + own_counts.consts != 0 { - return Some(MethodViolationCode::Generic); + if own_counts.types > 0 || own_counts.consts > 0 { + errors.push(MethodViolationCode::Generic); } let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0)); @@ -485,7 +496,7 @@ fn virtual_call_violation_for_method<'tcx>( } else { None }; - return Some(MethodViolationCode::UndispatchableReceiver(span)); + errors.push(MethodViolationCode::UndispatchableReceiver(span)); } else { // Do sanity check to make sure the receiver actually has the layout of a pointer. @@ -593,10 +604,10 @@ fn virtual_call_violation_for_method<'tcx>( contains_illegal_self_type_reference(tcx, trait_def_id, pred) }) { - return Some(MethodViolationCode::WhereClauseReferencesSelf); + errors.push(MethodViolationCode::WhereClauseReferencesSelf); } - None + errors } /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. @@ -709,7 +720,6 @@ fn object_ty_for_trait<'tcx>( // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like // `self: Wrapper<Self>`. -#[allow(dead_code)] fn receiver_is_dispatchable<'tcx>( tcx: TyCtxt<'tcx>, method: ty::AssocItem, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c3f56ae2756..af30d9121d1 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -898,7 +898,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { - bug!("Bound vars outside of `self.universe_indices`"); + bug!( + "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); } ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); @@ -916,7 +919,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { - bug!("Bound vars outside of `self.universe_indices`"); + bug!( + "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); } ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); @@ -935,7 +941,10 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { if debruijn.as_usize() + 1 > self.current_index.as_usize() + self.universe_indices.len() => { - bug!("Bound vars outside of `self.universe_indices`"); + bug!( + "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}", + self.universe_indices + ); } ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 349741a698c..c761d0d103e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -293,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> _ => unreachable!(), }?; // We don't expect ambiguity. - if result.is_ambiguous() { + if !result.value.is_proven() { // Rustdoc normalizes possibly not well-formed types, so only // treat this as a bug if we're not in rustdoc. if !tcx.sess.opts.actually_rustdoc { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index ee50a36be55..123881d9bc6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -52,8 +52,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; - // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl. - // There are no compiler built-in rules for this. + // Negative trait predicates have different rules than positive trait predicates. if obligation.polarity() == ty::ImplPolarity::Negative { self.assemble_candidates_for_trait_alias(obligation, &mut candidates); self.assemble_candidates_from_impls(obligation, &mut candidates); @@ -1064,6 +1063,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + match self_ty.skip_binder().kind() { ty::FnPtr(_) => candidates.vec.push(BuiltinCandidate { has_nested: false }), ty::Bool diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 1a9de150041..dabe25589a0 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(assert_matches)] +#![feature(associated_type_defaults)] #![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(if_let_guard)] @@ -39,6 +40,7 @@ mod layout_sanity_check; mod needs_drop; mod opaque_types; pub mod representability; +pub mod sig_types; mod structural_match; mod ty; diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 0010570e7b3..d1a154fe20d 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -53,14 +53,10 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { fn parent(&self) -> Option<LocalDefId> { match self.tcx.def_kind(self.item) { - DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias => None, DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { Some(self.tcx.local_parent(self.item)) } - other => span_bug!( - self.tcx.def_span(self.item), - "unhandled item with opaque types: {other:?}" - ), + _ => None, } } @@ -98,14 +94,6 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { hir_id == scope } - fn collect_body_and_predicate_taits(&mut self) { - // Look at all where bounds. - self.tcx.predicates_of(self.item).instantiate_identity(self.tcx).visit_with(self); - // An item is allowed to constrain opaques declared within its own body (but not nested within - // nested functions). - self.collect_taits_declared_in_body(); - } - #[instrument(level = "trace", skip(self))] fn collect_taits_declared_in_body(&mut self) { let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(self.item)).value; @@ -132,6 +120,13 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } } +impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> { + fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> ControlFlow<!> { + self.visit_spanned(span, value); + ControlFlow::Continue(()) + } +} + impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { #[instrument(skip(self), ret, level = "trace")] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> { @@ -269,41 +264,27 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { } } -fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] { +fn opaque_types_defined_by<'tcx>( + tcx: TyCtxt<'tcx>, + item: LocalDefId, +) -> &'tcx ty::List<LocalDefId> { let kind = tcx.def_kind(item); trace!(?kind); let mut collector = OpaqueTypeCollector::new(tcx, item); + super::sig_types::walk_types(tcx, item, &mut collector); match kind { - // Walk over the signature of the function-like to find the opaques. - DefKind::AssocFn | DefKind::Fn => { - let ty_sig = tcx.fn_sig(item).instantiate_identity(); - let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap(); - // Walk over the inputs and outputs manually in order to get good spans for them. - collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output()); - for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) { - collector.visit_spanned(hir.span, ty.map_bound(|x| *x)); - } - collector.collect_body_and_predicate_taits(); - } - // Walk over the type of the item to find opaques. - DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { - let span = match tcx.hir().get_by_def_id(item).ty() { - Some(ty) => ty.span, - _ => tcx.def_span(item), - }; - collector.visit_spanned(span, tcx.type_of(item).instantiate_identity()); - collector.collect_body_and_predicate_taits(); - } - // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` - DefKind::TyAlias | DefKind::AssocTy => { - tcx.type_of(item).instantiate_identity().visit_with(&mut collector); - } - DefKind::OpaqueTy => { - for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() { - collector.visit_spanned(span, pred); - } + DefKind::AssocFn + | DefKind::Fn + | DefKind::Static(_) + | DefKind::Const + | DefKind::AssocConst + | DefKind::AnonConst => { + collector.collect_taits_declared_in_body(); } - DefKind::Mod + DefKind::OpaqueTy + | DefKind::TyAlias + | DefKind::AssocTy + | DefKind::Mod | DefKind::Struct | DefKind::Union | DefKind::Enum @@ -322,12 +303,13 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [ | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Impl { .. } => {} - // Closures and coroutines are type checked with their parent, so there is no difference here. + // Closures and coroutines are type checked with their parent, so we need to allow all + // opaques from the closure signature *and* from the parent body. DefKind::Closure | DefKind::Coroutine | DefKind::InlineConst => { - return tcx.opaque_types_defined_by(tcx.local_parent(item)); + collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item))); } } - tcx.arena.alloc_from_iter(collector.opaques) + tcx.mk_local_def_ids(&collector.opaques) } pub(super) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs new file mode 100644 index 00000000000..1ab39974e0f --- /dev/null +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -0,0 +1,129 @@ +//! This module contains helpers for walking all types of +//! a signature, while preserving spans as much as possible + +use std::ops::ControlFlow; + +use rustc_hir::{def::DefKind, def_id::LocalDefId}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::Span; +use rustc_type_ir::visit::TypeVisitable; + +pub trait SpannedTypeVisitor<'tcx> { + type BreakTy = !; + fn visit( + &mut self, + span: Span, + value: impl TypeVisitable<TyCtxt<'tcx>>, + ) -> ControlFlow<Self::BreakTy>; +} + +pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( + tcx: TyCtxt<'tcx>, + item: LocalDefId, + visitor: &mut V, +) -> ControlFlow<V::BreakTy> { + let kind = tcx.def_kind(item); + trace!(?kind); + match kind { + DefKind::Coroutine => { + match tcx.type_of(item).instantiate_identity().kind() { + ty::Coroutine(_, args, _) => visitor.visit(tcx.def_span(item), args.as_coroutine().sig())?, + _ => bug!(), + } + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + // Walk over the signature of the function-like + DefKind::Closure | DefKind::AssocFn | DefKind::Fn => { + let ty_sig = match kind { + DefKind::Closure => match tcx.type_of(item).instantiate_identity().kind() { + ty::Closure(_, args) => args.as_closure().sig(), + _ => bug!(), + }, + _ => tcx.fn_sig(item).instantiate_identity(), + }; + let hir_sig = tcx.hir().get_by_def_id(item).fn_decl().unwrap(); + // Walk over the inputs and outputs manually in order to get good spans for them. + visitor.visit(hir_sig.output.span(), ty_sig.output()); + for (hir, ty) in hir_sig.inputs.iter().zip(ty_sig.inputs().iter()) { + visitor.visit(hir.span, ty.map_bound(|x| *x))?; + } + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + // Walk over the type behind the alias + DefKind::TyAlias {..} | DefKind::AssocTy | + // Walk over the type of the item + DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => { + let span = match tcx.hir().get_by_def_id(item).ty() { + Some(ty) => ty.span, + _ => tcx.def_span(item), + }; + visitor.visit(span, tcx.type_of(item).instantiate_identity()); + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + DefKind::OpaqueTy => { + for (pred, span) in tcx.explicit_item_bounds(item).instantiate_identity_iter_copied() { + visitor.visit(span, pred)?; + } + } + // Look at field types + DefKind::Struct | DefKind::Union | DefKind::Enum => { + let span = tcx.def_ident_span(item).unwrap(); + visitor.visit(span, tcx.type_of(item).instantiate_identity()); + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + // Does not have a syntactical signature + DefKind::InlineConst => {} + DefKind::Impl { of_trait } => { + if of_trait { + let span = tcx.hir().get_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span; + let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..]; + visitor.visit(span, args)?; + } + let span = match tcx.hir().get_by_def_id(item).ty() { + Some(ty) => ty.span, + _ => tcx.def_span(item), + }; + visitor.visit(span, tcx.type_of(item).instantiate_identity()); + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + }} + DefKind::Trait => { + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + DefKind::TraitAlias => { + for (pred, span) in tcx.predicates_of(item).instantiate_identity(tcx) { + visitor.visit(span, pred)?; + } + } + | DefKind::Variant + | DefKind::ForeignTy + | DefKind::TyParam + | DefKind::ConstParam + | DefKind::Ctor(_, _) + | DefKind::Field + | DefKind::LifetimeParam => { + span_bug!( + tcx.def_span(item), + "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help" + ) + } + // These don't have any types. + | DefKind::ExternCrate + | DefKind::ForeignMod + | DefKind::Macro(_) + | DefKind::GlobalAsm + | DefKind::Mod + | DefKind::Use => {} + } + ControlFlow::Continue(()) +} diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs new file mode 100644 index 00000000000..c0b6aed98ef --- /dev/null +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -0,0 +1,169 @@ +use std::fmt; +use std::hash; +use std::ops::ControlFlow; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_serialize::{Decodable, Encodable}; + +use crate::fold::{FallibleTypeFolder, TypeFoldable}; +use crate::visit::{TypeVisitable, TypeVisitor}; +use crate::TyDecoder; +use crate::{HashStableContext, Interner, TyEncoder, UniverseIndex}; + +/// A "canonicalized" type `V` is one where all free inference +/// variables have been rewritten to "canonical vars". These are +/// numbered starting from 0 in order of first appearance. +pub struct Canonical<I: Interner, V> { + pub value: V, + pub max_universe: UniverseIndex, + pub variables: I::CanonicalVars, +} + +impl<I: Interner, V> Canonical<I, V> { + /// Allows you to map the `value` of a canonical while keeping the + /// same set of bound variables. + /// + /// **WARNING:** This function is very easy to mis-use, hence the + /// name! In particular, the new value `W` must use all **the + /// same type/region variables** in **precisely the same order** + /// as the original! (The ordering is defined by the + /// `TypeFoldable` implementation of the type in question.) + /// + /// An example of a **correct** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical<I, T> = ...; + /// let b: Canonical<I, (T,)> = a.unchecked_map(|v| (v, )); + /// ``` + /// + /// An example of an **incorrect** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical<I, T> = ...; + /// let ty: Ty<I> = ...; + /// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty)); + /// ``` + pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> { + let Canonical { max_universe, variables, value } = self; + Canonical { max_universe, variables, value: map_op(value) } + } + + /// Allows you to map the `value` of a canonical while keeping the same set of + /// bound variables. + /// + /// **WARNING:** This function is very easy to mis-use, hence the name! See + /// the comment of [Canonical::unchecked_map] for more details. + pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> { + let Canonical { max_universe, variables, value: _ } = self; + Canonical { max_universe, variables, value } + } +} + +impl<I: Interner, V: hash::Hash> hash::Hash for Canonical<I, V> { + fn hash<H: hash::Hasher>(&self, state: &mut H) { + self.value.hash(state); + self.max_universe.hash(state); + self.variables.hash(state); + } +} + +impl<CTX: HashStableContext, I: Interner, V: HashStable<CTX>> HashStable<CTX> for Canonical<I, V> +where + I::CanonicalVars: HashStable<CTX>, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.value.hash_stable(hcx, hasher); + self.max_universe.hash_stable(hcx, hasher); + self.variables.hash_stable(hcx, hasher); + } +} + +impl<I: Interner, V: Eq> Eq for Canonical<I, V> {} + +impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + && self.max_universe == other.max_universe + && self.variables == other.variables + } +} + +impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", + self.value, self.max_universe, self.variables + ) + } +} + +impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Canonical") + .field("value", &self.value) + .field("max_universe", &self.max_universe) + .field("variables", &self.variables) + .finish() + } +} + +impl<I: Interner, V: Clone> Clone for Canonical<I, V> { + fn clone(&self) -> Self { + Canonical { + value: self.value.clone(), + max_universe: self.max_universe.clone(), + variables: self.variables.clone(), + } + } +} + +impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {} + +impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V> +where + I::CanonicalVars: TypeFoldable<I>, +{ + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(Canonical { + value: self.value.try_fold_with(folder)?, + max_universe: self.max_universe.try_fold_with(folder)?, + variables: self.variables.try_fold_with(folder)?, + }) + } +} + +impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V> +where + I::CanonicalVars: TypeVisitable<I>, +{ + fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> ControlFlow<F::BreakTy> { + self.value.visit_with(folder)?; + self.max_universe.visit_with(folder)?; + self.variables.visit_with(folder) + } +} + +impl<I: Interner, E: TyEncoder<I = I>, V: Encodable<E>> Encodable<E> for Canonical<I, V> +where + I::CanonicalVars: Encodable<E>, +{ + fn encode(&self, s: &mut E) { + self.value.encode(s); + self.max_universe.encode(s); + self.variables.encode(s); + } +} + +impl<I: Interner, D: TyDecoder<I = I>, V: Decodable<D>> Decodable<D> for Canonical<I, V> +where + I::CanonicalVars: Decodable<D>, +{ + fn decode(d: &mut D) -> Self { + Canonical { + value: Decodable::decode(d), + max_universe: Decodable::decode(d), + variables: Decodable::decode(d), + } + } +} diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs index 3b638934629..2fbc8f76fa4 100644 --- a/compiler/rustc_type_ir/src/codec.rs +++ b/compiler/rustc_type_ir/src/codec.rs @@ -1,4 +1,4 @@ -use crate::Interner; +use crate::{Interner, PredicateKind}; use rustc_data_structures::fx::FxHashMap; use rustc_serialize::{Decoder, Encoder}; @@ -30,9 +30,7 @@ pub trait TyEncoder: Encoder { fn type_shorthands(&mut self) -> &mut FxHashMap<<Self::I as Interner>::Ty, usize>; - fn predicate_shorthands( - &mut self, - ) -> &mut FxHashMap<<Self::I as Interner>::PredicateKind, usize>; + fn predicate_shorthands(&mut self) -> &mut FxHashMap<PredicateKind<Self::I>, usize>; fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId); } diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index f84841c9f64..a40c41583af 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -1,12 +1,13 @@ use rustc_data_structures::stable_hasher::HashStable; +use rustc_data_structures::stable_hasher::StableHasher; use rustc_serialize::{Decodable, Decoder, Encodable}; use std::cmp::Ordering; use std::fmt; use std::hash; use crate::{ - DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx, - TyDecoder, TyEncoder, + DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder, + TyEncoder, WithInfcx, }; use self::ConstKind::*; @@ -86,11 +87,7 @@ where I::ErrorGuaranteed: HashStable<CTX>, I::ExprConst: HashStable<CTX>, { - fn hash_stable( - &self, - hcx: &mut CTX, - hasher: &mut rustc_data_structures::stable_hasher::StableHasher, - ) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { const_kind_discriminant(self).hash_stable(hcx, hasher); match self { Param(p) => p.hash_stable(hcx, hasher), @@ -231,13 +228,13 @@ impl<I: Interner> Clone for ConstKind<I> { impl<I: Interner> fmt::Debug for ConstKind<I> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { - fn fmt<InfCtx: InferCtxtLike<I>>( - this: OptWithInfcx<'_, I, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { use ConstKind::*; diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs index 7c6a7846900..4ea3eb3e84f 100644 --- a/compiler/rustc_type_ir/src/debug.rs +++ b/compiler/rustc_type_ir/src/debug.rs @@ -3,38 +3,48 @@ use crate::{Interner, UniverseIndex}; use core::fmt; use std::marker::PhantomData; -pub trait InferCtxtLike<I: Interner> { - fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>; +pub trait InferCtxtLike { + type Interner: Interner; - fn universe_of_lt(&self, lt: I::InferRegion) -> Option<UniverseIndex>; + fn universe_of_ty(&self, ty: <Self::Interner as Interner>::InferTy) -> Option<UniverseIndex>; - fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>; + fn universe_of_lt( + &self, + lt: <Self::Interner as Interner>::InferRegion, + ) -> Option<UniverseIndex>; + + fn universe_of_ct(&self, ct: <Self::Interner as Interner>::InferConst) + -> Option<UniverseIndex>; } -impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible { +pub struct NoInfcx<I>(PhantomData<I>); + +impl<I: Interner> InferCtxtLike for NoInfcx<I> { + type Interner = I; + fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> { - match *self {} + None } fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> { - match *self {} + None } fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> { - match *self {} + None } } pub trait DebugWithInfcx<I: Interner>: fmt::Debug { - fn fmt<InfCtx: InferCtxtLike<I>>( - this: OptWithInfcx<'_, I, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut fmt::Formatter<'_>, ) -> fmt::Result; } impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T { - fn fmt<InfCtx: InferCtxtLike<I>>( - this: OptWithInfcx<'_, I, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut fmt::Formatter<'_>, ) -> fmt::Result { <T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f) @@ -42,8 +52,8 @@ impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T { } impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] { - fn fmt<InfCtx: InferCtxtLike<I>>( - this: OptWithInfcx<'_, I, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut fmt::Formatter<'_>, ) -> fmt::Result { match f.alternate() { @@ -70,46 +80,45 @@ impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] { } } -pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> { +pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> { pub data: T, - pub infcx: Option<&'a InfCtx>, - _interner: PhantomData<I>, + pub infcx: &'a Infcx, } -impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {} +impl<Infcx: InferCtxtLike, T: Copy> Copy for WithInfcx<'_, Infcx, T> {} -impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> { +impl<Infcx: InferCtxtLike, T: Clone> Clone for WithInfcx<'_, Infcx, T> { fn clone(&self) -> Self { - Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner } + Self { data: self.data.clone(), infcx: self.infcx } } } -impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> { - pub fn new_no_ctx(data: T) -> Self { - Self { data, infcx: None, _interner: PhantomData } +impl<'a, I: Interner, T> WithInfcx<'a, NoInfcx<I>, T> { + pub fn with_no_infcx(data: T) -> Self { + Self { data, infcx: &NoInfcx(PhantomData) } } } -impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> { - pub fn new(data: T, infcx: &'a InfCtx) -> Self { - Self { data, infcx: Some(infcx), _interner: PhantomData } +impl<'a, Infcx: InferCtxtLike, T> WithInfcx<'a, Infcx, T> { + pub fn new(data: T, infcx: &'a Infcx) -> Self { + Self { data, infcx } } - pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> { - OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData } + pub fn wrap<U>(self, u: U) -> WithInfcx<'a, Infcx, U> { + WithInfcx { data: u, infcx: self.infcx } } - pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> { - OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData } + pub fn map<U>(self, f: impl FnOnce(T) -> U) -> WithInfcx<'a, Infcx, U> { + WithInfcx { data: f(self.data), infcx: self.infcx } } - pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> { - OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData } + pub fn as_ref(&self) -> WithInfcx<'a, Infcx, &T> { + WithInfcx { data: &self.data, infcx: self.infcx } } } -impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug - for OptWithInfcx<'_, I, InfCtx, T> +impl<Infcx: InferCtxtLike, T: DebugWithInfcx<Infcx::Interner>> fmt::Debug + for WithInfcx<'_, Infcx, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DebugWithInfcx::fmt(self.as_ref(), f) diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 60e4c587993..7f75e5b35a2 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -14,14 +14,11 @@ pub trait Interner: Sized { + Ord + IntoIterator<Item = Self::GenericArg>; type GenericArg: Clone + DebugWithInfcx<Self> + Hash + Ord; + type Term: Clone + Debug + Hash + Ord; type Binder<T>; - - // Predicates - type Predicate; - type PredicateKind: Clone + Debug + Hash + PartialEq + Eq; - type TypeAndMut: Clone + Debug + Hash + Ord; + type CanonicalVars: Clone + Debug + Hash + Eq; // Kinds of tys type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord; @@ -56,6 +53,16 @@ pub trait Interner: Sized { type InferRegion: Clone + DebugWithInfcx<Self> + Hash + Ord; type PlaceholderRegion: Clone + Debug + Hash + Ord; + // Predicates + type Predicate: Clone + Debug + Hash + Eq; + type TraitPredicate: Clone + Debug + Hash + Eq; + type RegionOutlivesPredicate: Clone + Debug + Hash + Eq; + type TypeOutlivesPredicate: Clone + Debug + Hash + Eq; + type ProjectionPredicate: Clone + Debug + Hash + Eq; + type SubtypePredicate: Clone + Debug + Hash + Eq; + type CoercePredicate: Clone + Debug + Hash + Eq; + type ClosureKind: Clone + Debug + Hash + Eq; + fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Mutability); } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index d4ca9da96e4..a056fbeda98 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -26,17 +26,21 @@ pub mod visit; #[macro_use] mod macros; +mod canonical; mod const_kind; mod debug; mod flags; mod interner; +mod predicate_kind; mod region_kind; +pub use canonical::*; pub use codec::*; pub use const_kind::*; -pub use debug::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; +pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx}; pub use flags::*; pub use interner::*; +pub use predicate_kind::*; pub use region_kind::*; pub use ty_info::*; pub use ty_kind::*; diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 9e10c65c20d..cfed84a35c6 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -49,4 +49,6 @@ TrivialTypeTraversalImpls! { u64, String, crate::DebruijnIndex, + crate::AliasRelationDirection, + crate::UniverseIndex, } diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs new file mode 100644 index 00000000000..f6fabe691c6 --- /dev/null +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -0,0 +1,626 @@ +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_serialize::Decoder; +use rustc_serialize::{Decodable, Encodable}; +use std::fmt; +use std::hash; +use std::ops::ControlFlow; + +use crate::fold::{FallibleTypeFolder, TypeFoldable}; +use crate::visit::{TypeVisitable, TypeVisitor}; +use crate::{HashStableContext, Interner}; +use crate::{TyDecoder, TyEncoder}; + +/// A clause is something that can appear in where bounds or be inferred +/// by implied bounds. +pub enum ClauseKind<I: Interner> { + /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be + /// the `Self` type of the trait reference and `A`, `B`, and `C` + /// would be the type parameters. + Trait(I::TraitPredicate), + + /// `where 'a: 'b` + RegionOutlives(I::RegionOutlivesPredicate), + + /// `where T: 'a` + TypeOutlives(I::TypeOutlivesPredicate), + + /// `where <T as TraitRef>::Name == X`, approximately. + /// See the `ProjectionPredicate` struct for details. + Projection(I::ProjectionPredicate), + + /// Ensures that a const generic argument to a parameter `const N: u8` + /// is of type `u8`. + ConstArgHasType(I::Const, I::Ty), + + /// No syntax: `T` well-formed. + WellFormed(I::GenericArg), + + /// Constant initializer must evaluate successfully. + ConstEvaluatable(I::Const), +} + +impl<I: Interner> Clone for ClauseKind<I> { + fn clone(&self) -> Self { + match self { + Self::Trait(arg0) => Self::Trait(arg0.clone()), + Self::RegionOutlives(arg0) => Self::RegionOutlives(arg0.clone()), + Self::TypeOutlives(arg0) => Self::TypeOutlives(arg0.clone()), + Self::Projection(arg0) => Self::Projection(arg0.clone()), + Self::ConstArgHasType(arg0, arg1) => Self::ConstArgHasType(arg0.clone(), arg1.clone()), + Self::WellFormed(arg0) => Self::WellFormed(arg0.clone()), + Self::ConstEvaluatable(arg0) => Self::ConstEvaluatable(arg0.clone()), + } + } +} + +impl<I: Interner> Copy for ClauseKind<I> +where + I::Ty: Copy, + I::Const: Copy, + I::GenericArg: Copy, + I::TraitPredicate: Copy, + I::ProjectionPredicate: Copy, + I::TypeOutlivesPredicate: Copy, + I::RegionOutlivesPredicate: Copy, +{ +} + +impl<I: Interner> PartialEq for ClauseKind<I> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Trait(l0), Self::Trait(r0)) => l0 == r0, + (Self::RegionOutlives(l0), Self::RegionOutlives(r0)) => l0 == r0, + (Self::TypeOutlives(l0), Self::TypeOutlives(r0)) => l0 == r0, + (Self::Projection(l0), Self::Projection(r0)) => l0 == r0, + (Self::ConstArgHasType(l0, l1), Self::ConstArgHasType(r0, r1)) => l0 == r0 && l1 == r1, + (Self::WellFormed(l0), Self::WellFormed(r0)) => l0 == r0, + (Self::ConstEvaluatable(l0), Self::ConstEvaluatable(r0)) => l0 == r0, + _ => false, + } + } +} + +impl<I: Interner> Eq for ClauseKind<I> {} + +fn clause_kind_discriminant<I: Interner>(value: &ClauseKind<I>) -> usize { + match value { + ClauseKind::Trait(_) => 0, + ClauseKind::RegionOutlives(_) => 1, + ClauseKind::TypeOutlives(_) => 2, + ClauseKind::Projection(_) => 3, + ClauseKind::ConstArgHasType(_, _) => 4, + ClauseKind::WellFormed(_) => 5, + ClauseKind::ConstEvaluatable(_) => 6, + } +} + +impl<I: Interner> hash::Hash for ClauseKind<I> { + fn hash<H: hash::Hasher>(&self, state: &mut H) { + clause_kind_discriminant(self).hash(state); + match self { + ClauseKind::Trait(p) => p.hash(state), + ClauseKind::RegionOutlives(p) => p.hash(state), + ClauseKind::TypeOutlives(p) => p.hash(state), + ClauseKind::Projection(p) => p.hash(state), + ClauseKind::ConstArgHasType(c, t) => { + c.hash(state); + t.hash(state); + } + ClauseKind::WellFormed(t) => t.hash(state), + ClauseKind::ConstEvaluatable(c) => c.hash(state), + } + } +} + +impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for ClauseKind<I> +where + I::Ty: HashStable<CTX>, + I::Const: HashStable<CTX>, + I::GenericArg: HashStable<CTX>, + I::TraitPredicate: HashStable<CTX>, + I::ProjectionPredicate: HashStable<CTX>, + I::TypeOutlivesPredicate: HashStable<CTX>, + I::RegionOutlivesPredicate: HashStable<CTX>, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + clause_kind_discriminant(self).hash_stable(hcx, hasher); + match self { + ClauseKind::Trait(p) => p.hash_stable(hcx, hasher), + ClauseKind::RegionOutlives(p) => p.hash_stable(hcx, hasher), + ClauseKind::TypeOutlives(p) => p.hash_stable(hcx, hasher), + ClauseKind::Projection(p) => p.hash_stable(hcx, hasher), + ClauseKind::ConstArgHasType(c, t) => { + c.hash_stable(hcx, hasher); + t.hash_stable(hcx, hasher); + } + ClauseKind::WellFormed(t) => t.hash_stable(hcx, hasher), + ClauseKind::ConstEvaluatable(c) => c.hash_stable(hcx, hasher), + } + } +} + +impl<I: Interner> TypeFoldable<I> for ClauseKind<I> +where + I::Ty: TypeFoldable<I>, + I::Const: TypeFoldable<I>, + I::GenericArg: TypeFoldable<I>, + I::TraitPredicate: TypeFoldable<I>, + I::ProjectionPredicate: TypeFoldable<I>, + I::TypeOutlivesPredicate: TypeFoldable<I>, + I::RegionOutlivesPredicate: TypeFoldable<I>, +{ + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(match self { + ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?), + ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?), + ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?), + ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?), + ClauseKind::ConstArgHasType(c, t) => { + ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?) + } + ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?), + ClauseKind::ConstEvaluatable(p) => { + ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?) + } + }) + } +} + +impl<I: Interner> TypeVisitable<I> for ClauseKind<I> +where + I::Ty: TypeVisitable<I>, + I::Const: TypeVisitable<I>, + I::GenericArg: TypeVisitable<I>, + I::TraitPredicate: TypeVisitable<I>, + I::ProjectionPredicate: TypeVisitable<I>, + I::TypeOutlivesPredicate: TypeVisitable<I>, + I::RegionOutlivesPredicate: TypeVisitable<I>, +{ + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + match self { + ClauseKind::Trait(p) => p.visit_with(visitor), + ClauseKind::RegionOutlives(p) => p.visit_with(visitor), + ClauseKind::TypeOutlives(p) => p.visit_with(visitor), + ClauseKind::Projection(p) => p.visit_with(visitor), + ClauseKind::ConstArgHasType(c, t) => { + c.visit_with(visitor)?; + t.visit_with(visitor) + } + ClauseKind::WellFormed(p) => p.visit_with(visitor), + ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor), + } + } +} + +impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for ClauseKind<I> +where + I::Ty: Decodable<D>, + I::Const: Decodable<D>, + I::GenericArg: Decodable<D>, + I::TraitPredicate: Decodable<D>, + I::ProjectionPredicate: Decodable<D>, + I::TypeOutlivesPredicate: Decodable<D>, + I::RegionOutlivesPredicate: Decodable<D>, +{ + fn decode(d: &mut D) -> Self { + match Decoder::read_usize(d) { + 0 => ClauseKind::Trait(Decodable::decode(d)), + 1 => ClauseKind::RegionOutlives(Decodable::decode(d)), + 2 => ClauseKind::TypeOutlives(Decodable::decode(d)), + 3 => ClauseKind::Projection(Decodable::decode(d)), + 4 => ClauseKind::ConstArgHasType(Decodable::decode(d), Decodable::decode(d)), + 5 => ClauseKind::WellFormed(Decodable::decode(d)), + 6 => ClauseKind::ConstEvaluatable(Decodable::decode(d)), + _ => panic!( + "{}", + format!( + "invalid enum variant tag while decoding `{}`, expected 0..{}", + "ClauseKind", 7, + ) + ), + } + } +} + +impl<I: Interner, E: TyEncoder> Encodable<E> for ClauseKind<I> +where + I::Ty: Encodable<E>, + I::Const: Encodable<E>, + I::GenericArg: Encodable<E>, + I::TraitPredicate: Encodable<E>, + I::ProjectionPredicate: Encodable<E>, + I::TypeOutlivesPredicate: Encodable<E>, + I::RegionOutlivesPredicate: Encodable<E>, +{ + fn encode(&self, s: &mut E) { + let discriminant = clause_kind_discriminant(self); + match self { + ClauseKind::Trait(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)), + ClauseKind::RegionOutlives(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)), + ClauseKind::TypeOutlives(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)), + ClauseKind::Projection(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)), + ClauseKind::ConstArgHasType(c, t) => s.emit_enum_variant(discriminant, |s| { + c.encode(s); + t.encode(s); + }), + ClauseKind::WellFormed(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)), + ClauseKind::ConstEvaluatable(p) => s.emit_enum_variant(discriminant, |s| p.encode(s)), + } + } +} + +pub enum PredicateKind<I: Interner> { + /// Prove a clause + Clause(ClauseKind<I>), + + /// Trait must be object-safe. + ObjectSafe(I::DefId), + + /// No direct syntax. May be thought of as `where T: FnFoo<...>` + /// for some generic args `...` and `T` being a closure type. + /// Satisfied (or refuted) once we know the closure's kind. + ClosureKind(I::DefId, I::GenericArgs, I::ClosureKind), + + /// `T1 <: T2` + /// + /// This obligation is created most often when we have two + /// unresolved type variables and hence don't have enough + /// information to process the subtyping obligation yet. + Subtype(I::SubtypePredicate), + + /// `T1` coerced to `T2` + /// + /// Like a subtyping obligation, this is created most often + /// when we have two unresolved type variables and hence + /// don't have enough information to process the coercion + /// obligation yet. At the moment, we actually process coercions + /// very much like subtyping and don't handle the full coercion + /// logic. + Coerce(I::CoercePredicate), + + /// Constants must be equal. The first component is the const that is expected. + ConstEquate(I::Const, I::Const), + + /// A marker predicate that is always ambiguous. + /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous. + Ambiguous, + + /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. + /// This predicate requires two terms to be equal to eachother. + /// + /// Only used for new solver + AliasRelate(I::Term, I::Term, AliasRelationDirection), +} + +impl<I: Interner> Copy for PredicateKind<I> +where + I::DefId: Copy, + I::Const: Copy, + I::GenericArgs: Copy, + I::Term: Copy, + I::CoercePredicate: Copy, + I::SubtypePredicate: Copy, + I::ClosureKind: Copy, + ClauseKind<I>: Copy, +{ +} + +impl<I: Interner> Clone for PredicateKind<I> { + fn clone(&self) -> Self { + match self { + Self::Clause(arg0) => Self::Clause(arg0.clone()), + Self::ObjectSafe(arg0) => Self::ObjectSafe(arg0.clone()), + Self::ClosureKind(arg0, arg1, arg2) => { + Self::ClosureKind(arg0.clone(), arg1.clone(), arg2.clone()) + } + Self::Subtype(arg0) => Self::Subtype(arg0.clone()), + Self::Coerce(arg0) => Self::Coerce(arg0.clone()), + Self::ConstEquate(arg0, arg1) => Self::ConstEquate(arg0.clone(), arg1.clone()), + Self::Ambiguous => Self::Ambiguous, + Self::AliasRelate(arg0, arg1, arg2) => { + Self::AliasRelate(arg0.clone(), arg1.clone(), arg2.clone()) + } + } + } +} + +impl<I: Interner> PartialEq for PredicateKind<I> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Clause(l0), Self::Clause(r0)) => l0 == r0, + (Self::ObjectSafe(l0), Self::ObjectSafe(r0)) => l0 == r0, + (Self::ClosureKind(l0, l1, l2), Self::ClosureKind(r0, r1, r2)) => { + l0 == r0 && l1 == r1 && l2 == r2 + } + (Self::Subtype(l0), Self::Subtype(r0)) => l0 == r0, + (Self::Coerce(l0), Self::Coerce(r0)) => l0 == r0, + (Self::ConstEquate(l0, l1), Self::ConstEquate(r0, r1)) => l0 == r0 && l1 == r1, + (Self::AliasRelate(l0, l1, l2), Self::AliasRelate(r0, r1, r2)) => { + l0 == r0 && l1 == r1 && l2 == r2 + } + _ => core::mem::discriminant(self) == core::mem::discriminant(other), + } + } +} + +impl<I: Interner> Eq for PredicateKind<I> {} + +fn predicate_kind_discriminant<I: Interner>(value: &PredicateKind<I>) -> usize { + match value { + PredicateKind::Clause(_) => 0, + PredicateKind::ObjectSafe(_) => 1, + PredicateKind::ClosureKind(_, _, _) => 2, + PredicateKind::Subtype(_) => 3, + PredicateKind::Coerce(_) => 4, + PredicateKind::ConstEquate(_, _) => 5, + PredicateKind::Ambiguous => 6, + PredicateKind::AliasRelate(_, _, _) => 7, + } +} + +impl<I: Interner> hash::Hash for PredicateKind<I> { + fn hash<H: hash::Hasher>(&self, state: &mut H) { + predicate_kind_discriminant(self).hash(state); + match self { + PredicateKind::Clause(p) => p.hash(state), + PredicateKind::ObjectSafe(d) => d.hash(state), + PredicateKind::ClosureKind(d, g, k) => { + d.hash(state); + g.hash(state); + k.hash(state); + } + PredicateKind::Subtype(p) => p.hash(state), + PredicateKind::Coerce(p) => p.hash(state), + PredicateKind::ConstEquate(c1, c2) => { + c1.hash(state); + c2.hash(state); + } + PredicateKind::Ambiguous => {} + PredicateKind::AliasRelate(t1, t2, r) => { + t1.hash(state); + t2.hash(state); + r.hash(state); + } + } + } +} + +impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for PredicateKind<I> +where + I::DefId: HashStable<CTX>, + I::Const: HashStable<CTX>, + I::GenericArgs: HashStable<CTX>, + I::Term: HashStable<CTX>, + I::CoercePredicate: HashStable<CTX>, + I::SubtypePredicate: HashStable<CTX>, + I::ClosureKind: HashStable<CTX>, + ClauseKind<I>: HashStable<CTX>, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + predicate_kind_discriminant(self).hash_stable(hcx, hasher); + match self { + PredicateKind::Clause(p) => p.hash_stable(hcx, hasher), + PredicateKind::ObjectSafe(d) => d.hash_stable(hcx, hasher), + PredicateKind::ClosureKind(d, g, k) => { + d.hash_stable(hcx, hasher); + g.hash_stable(hcx, hasher); + k.hash_stable(hcx, hasher); + } + PredicateKind::Subtype(p) => p.hash_stable(hcx, hasher), + PredicateKind::Coerce(p) => p.hash_stable(hcx, hasher), + PredicateKind::ConstEquate(c1, c2) => { + c1.hash_stable(hcx, hasher); + c2.hash_stable(hcx, hasher); + } + PredicateKind::Ambiguous => {} + PredicateKind::AliasRelate(t1, t2, r) => { + t1.hash_stable(hcx, hasher); + t2.hash_stable(hcx, hasher); + r.hash_stable(hcx, hasher); + } + } + } +} + +impl<I: Interner> TypeFoldable<I> for PredicateKind<I> +where + I::DefId: TypeFoldable<I>, + I::Const: TypeFoldable<I>, + I::GenericArgs: TypeFoldable<I>, + I::Term: TypeFoldable<I>, + I::CoercePredicate: TypeFoldable<I>, + I::SubtypePredicate: TypeFoldable<I>, + I::ClosureKind: TypeFoldable<I>, + ClauseKind<I>: TypeFoldable<I>, +{ + fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { + Ok(match self { + PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?), + PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?), + PredicateKind::ClosureKind(d, g, k) => PredicateKind::ClosureKind( + d.try_fold_with(folder)?, + g.try_fold_with(folder)?, + k.try_fold_with(folder)?, + ), + PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?), + PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?), + PredicateKind::ConstEquate(a, b) => { + PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?) + } + PredicateKind::Ambiguous => PredicateKind::Ambiguous, + PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate( + a.try_fold_with(folder)?, + b.try_fold_with(folder)?, + d.try_fold_with(folder)?, + ), + }) + } +} + +impl<I: Interner> TypeVisitable<I> for PredicateKind<I> +where + I::DefId: TypeVisitable<I>, + I::Const: TypeVisitable<I>, + I::GenericArgs: TypeVisitable<I>, + I::Term: TypeVisitable<I>, + I::CoercePredicate: TypeVisitable<I>, + I::SubtypePredicate: TypeVisitable<I>, + I::ClosureKind: TypeVisitable<I>, + ClauseKind<I>: TypeVisitable<I>, +{ + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + match self { + PredicateKind::Clause(p) => p.visit_with(visitor), + PredicateKind::ObjectSafe(d) => d.visit_with(visitor), + PredicateKind::ClosureKind(d, g, k) => { + d.visit_with(visitor)?; + g.visit_with(visitor)?; + k.visit_with(visitor) + } + PredicateKind::Subtype(s) => s.visit_with(visitor), + PredicateKind::Coerce(s) => s.visit_with(visitor), + PredicateKind::ConstEquate(a, b) => { + a.visit_with(visitor)?; + b.visit_with(visitor) + } + PredicateKind::Ambiguous => ControlFlow::Continue(()), + PredicateKind::AliasRelate(a, b, d) => { + a.visit_with(visitor)?; + b.visit_with(visitor)?; + d.visit_with(visitor) + } + } + } +} + +impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for PredicateKind<I> +where + I::DefId: Decodable<D>, + I::Const: Decodable<D>, + I::GenericArgs: Decodable<D>, + I::Term: Decodable<D>, + I::CoercePredicate: Decodable<D>, + I::SubtypePredicate: Decodable<D>, + I::ClosureKind: Decodable<D>, + ClauseKind<I>: Decodable<D>, +{ + fn decode(d: &mut D) -> Self { + match Decoder::read_usize(d) { + 0 => PredicateKind::Clause(Decodable::decode(d)), + 1 => PredicateKind::ObjectSafe(Decodable::decode(d)), + 2 => PredicateKind::ClosureKind( + Decodable::decode(d), + Decodable::decode(d), + Decodable::decode(d), + ), + 3 => PredicateKind::Subtype(Decodable::decode(d)), + 4 => PredicateKind::Coerce(Decodable::decode(d)), + 5 => PredicateKind::ConstEquate(Decodable::decode(d), Decodable::decode(d)), + 6 => PredicateKind::Ambiguous, + 7 => PredicateKind::AliasRelate( + Decodable::decode(d), + Decodable::decode(d), + Decodable::decode(d), + ), + _ => panic!( + "{}", + format!( + "invalid enum variant tag while decoding `{}`, expected 0..{}", + "PredicateKind", 8, + ) + ), + } + } +} + +impl<I: Interner, E: TyEncoder> Encodable<E> for PredicateKind<I> +where + I::DefId: Encodable<E>, + I::Const: Encodable<E>, + I::GenericArgs: Encodable<E>, + I::Term: Encodable<E>, + I::CoercePredicate: Encodable<E>, + I::SubtypePredicate: Encodable<E>, + I::ClosureKind: Encodable<E>, + ClauseKind<I>: Encodable<E>, +{ + fn encode(&self, s: &mut E) { + let discriminant = predicate_kind_discriminant(self); + match self { + PredicateKind::Clause(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)), + PredicateKind::ObjectSafe(d) => s.emit_enum_variant(discriminant, |s| d.encode(s)), + PredicateKind::ClosureKind(d, g, k) => s.emit_enum_variant(discriminant, |s| { + d.encode(s); + g.encode(s); + k.encode(s); + }), + PredicateKind::Subtype(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)), + PredicateKind::Coerce(c) => s.emit_enum_variant(discriminant, |s| c.encode(s)), + PredicateKind::ConstEquate(a, b) => s.emit_enum_variant(discriminant, |s| { + a.encode(s); + b.encode(s); + }), + PredicateKind::Ambiguous => s.emit_enum_variant(discriminant, |_s| {}), + PredicateKind::AliasRelate(a, b, d) => s.emit_enum_variant(discriminant, |s| { + a.encode(s); + b.encode(s); + d.encode(s); + }), + } + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] +#[derive(HashStable_Generic, Encodable, Decodable)] +pub enum AliasRelationDirection { + Equate, + Subtype, +} + +impl std::fmt::Display for AliasRelationDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AliasRelationDirection::Equate => write!(f, "=="), + AliasRelationDirection::Subtype => write!(f, "<:"), + } + } +} + +// FIXME: Convert to DebugWithInfcx impl +impl<I: Interner> fmt::Debug for ClauseKind<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ClauseKind::ConstArgHasType(ct, ty) => write!(f, "ConstArgHasType({ct:?}, {ty:?})"), + ClauseKind::Trait(a) => a.fmt(f), + ClauseKind::RegionOutlives(pair) => pair.fmt(f), + ClauseKind::TypeOutlives(pair) => pair.fmt(f), + ClauseKind::Projection(pair) => pair.fmt(f), + ClauseKind::WellFormed(data) => write!(f, "WellFormed({data:?})"), + ClauseKind::ConstEvaluatable(ct) => { + write!(f, "ConstEvaluatable({ct:?})") + } + } + } +} + +// FIXME: Convert to DebugWithInfcx impl +impl<I: Interner> fmt::Debug for PredicateKind<I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + PredicateKind::Clause(a) => a.fmt(f), + PredicateKind::Subtype(pair) => pair.fmt(f), + PredicateKind::Coerce(pair) => pair.fmt(f), + PredicateKind::ObjectSafe(trait_def_id) => { + write!(f, "ObjectSafe({trait_def_id:?})") + } + PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => { + write!(f, "ClosureKind({closure_def_id:?}, {closure_args:?}, {kind:?})") + } + PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"), + PredicateKind::Ambiguous => write!(f, "Ambiguous"), + PredicateKind::AliasRelate(t1, t2, dir) => { + write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})") + } + } + } +} diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 0006eec4d30..19576ea58f1 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -1,12 +1,13 @@ use rustc_data_structures::stable_hasher::HashStable; +use rustc_data_structures::stable_hasher::StableHasher; use rustc_serialize::{Decodable, Decoder, Encodable}; use std::cmp::Ordering; use std::fmt; use std::hash; use crate::{ - DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx, - TyDecoder, TyEncoder, + DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder, + TyEncoder, WithInfcx, }; use self::RegionKind::*; @@ -274,8 +275,8 @@ impl<I: Interner> hash::Hash for RegionKind<I> { } impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { - fn fmt<InfCtx: InferCtxtLike<I>>( - this: OptWithInfcx<'_, I, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { match this.data { @@ -301,12 +302,12 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { } impl<I: Interner> fmt::Debug for RegionKind<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } // This is manually implemented because a derive would require `I: Encodable` -impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I> +impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for RegionKind<I> where I::EarlyBoundRegion: Encodable<E>, I::BoundRegion: Encodable<E>, @@ -381,11 +382,7 @@ where I::PlaceholderRegion: HashStable<CTX>, { #[inline] - fn hash_stable( - &self, - hcx: &mut CTX, - hasher: &mut rustc_data_structures::stable_hasher::StableHasher, - ) { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { std::mem::discriminant(self).hash_stable(hcx, hasher); match self { ReErased | ReStatic | ReError(_) => { diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 91bfce9a142..b542547589a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -11,7 +11,7 @@ use crate::HashStableContext; use crate::Interner; use crate::TyDecoder; use crate::TyEncoder; -use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; +use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx}; use self::TyKind::*; @@ -534,8 +534,8 @@ impl<I: Interner> hash::Hash for TyKind<I> { } impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { - fn fmt<InfCtx: InferCtxtLike<I>>( - this: OptWithInfcx<'_, I, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> fmt::Result { match this.data { @@ -617,12 +617,12 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { // This is manually implemented because a derive would require `I: Debug` impl<I: Interner> fmt::Debug for TyKind<I> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - OptWithInfcx::new_no_ctx(self).fmt(f) + WithInfcx::with_no_infcx(self).fmt(f) } } // This is manually implemented because a derive would require `I: Encodable` -impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I> +impl<I: Interner, E: TyEncoder<I = I>> Encodable<E> for TyKind<I> where I::ErrorGuaranteed: Encodable<E>, I::AdtDef: Encodable<E>, @@ -640,7 +640,6 @@ where I::BoundTy: Encodable<E>, I::PlaceholderTy: Encodable<E>, I::InferTy: Encodable<E>, - I::PredicateKind: Encodable<E>, I::AllocId: Encodable<E>, { fn encode(&self, e: &mut E) { @@ -753,7 +752,6 @@ where I::BoundTy: Decodable<D>, I::PlaceholderTy: Decodable<D>, I::InferTy: Decodable<D>, - I::PredicateKind: Decodable<D>, I::AllocId: Decodable<D>, { fn decode(d: &mut D) -> Self { @@ -817,11 +815,7 @@ where I::ErrorGuaranteed: HashStable<CTX>, { #[inline] - fn hash_stable( - &self, - __hcx: &mut CTX, - __hasher: &mut rustc_data_structures::stable_hasher::StableHasher, - ) { + fn hash_stable(&self, __hcx: &mut CTX, __hasher: &mut StableHasher) { std::mem::discriminant(self).hash_stable(__hcx, __hasher); match self { Bool => {} @@ -1239,12 +1233,12 @@ impl fmt::Debug for InferTy { } impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy { - fn fmt<InfCtx: InferCtxtLike<I>>( - this: OptWithInfcx<'_, I, InfCtx, &Self>, + fn fmt<Infcx: InferCtxtLike<Interner = I>>( + this: WithInfcx<'_, Infcx, &Self>, f: &mut fmt::Formatter<'_>, ) -> fmt::Result { use InferTy::*; - match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) { + match this.infcx.universe_of_ty(*this.data) { None => write!(f, "{:?}", this.data), Some(universe) => match *this.data { TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()), diff --git a/compiler/stable_mir/src/fold.rs b/compiler/stable_mir/src/fold.rs deleted file mode 100644 index ca6ea92c4a1..00000000000 --- a/compiler/stable_mir/src/fold.rs +++ /dev/null @@ -1,245 +0,0 @@ -use std::ops::ControlFlow; - -use crate::Opaque; - -use super::ty::{ - Allocation, Binder, Const, ConstDef, ConstantKind, ExistentialPredicate, FnSig, GenericArgKind, - GenericArgs, Promoted, Region, RigidTy, TermKind, Ty, TyKind, UnevaluatedConst, -}; - -pub trait Folder: Sized { - type Break; - fn fold_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> { - ty.super_fold(self) - } - fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> { - c.super_fold(self) - } - fn fold_reg(&mut self, reg: &Region) -> ControlFlow<Self::Break, Region> { - reg.super_fold(self) - } -} - -pub trait Foldable: Sized + Clone { - fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - self.super_fold(folder) - } - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self>; -} - -impl Foldable for Ty { - fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - folder.fold_ty(self) - } - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - let mut kind = self.kind(); - match &mut kind { - super::ty::TyKind::RigidTy(ty) => *ty = ty.fold(folder)?, - super::ty::TyKind::Alias(_, alias) => alias.args = alias.args.fold(folder)?, - super::ty::TyKind::Param(_) => {} - super::ty::TyKind::Bound(_, _) => {} - } - ControlFlow::Continue(kind.into()) - } -} - -impl Foldable for Const { - fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - folder.fold_const(self) - } - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - let mut this = self.clone(); - match &mut this.literal { - super::ty::ConstantKind::Allocated(alloc) => *alloc = alloc.fold(folder)?, - super::ty::ConstantKind::Unevaluated(uv) => *uv = uv.fold(folder)?, - super::ty::ConstantKind::Param(_) => {} - } - this.ty = this.ty.fold(folder)?; - ControlFlow::Continue(this) - } -} - -impl Foldable for Opaque { - fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(self.clone()) - } -} - -impl Foldable for Allocation { - fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(self.clone()) - } -} - -impl Foldable for UnevaluatedConst { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - let UnevaluatedConst { def, args, promoted } = self; - ControlFlow::Continue(UnevaluatedConst { - def: def.fold(folder)?, - args: args.fold(folder)?, - promoted: promoted.fold(folder)?, - }) - } -} - -impl Foldable for ConstDef { - fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(*self) - } -} - -impl<T: Foldable> Foldable for Option<T> { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(match self { - Some(val) => Some(val.fold(folder)?), - None => None, - }) - } -} - -impl Foldable for Promoted { - fn super_fold<V: Folder>(&self, _folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(*self) - } -} - -impl Foldable for GenericArgs { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(GenericArgs(self.0.fold(folder)?)) - } -} - -impl Foldable for Region { - fn fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - folder.fold_reg(self) - } - fn super_fold<V: Folder>(&self, _: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(self.clone()) - } -} - -impl Foldable for GenericArgKind { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - let mut this = self.clone(); - match &mut this { - GenericArgKind::Lifetime(lt) => *lt = lt.fold(folder)?, - GenericArgKind::Type(t) => *t = t.fold(folder)?, - GenericArgKind::Const(c) => *c = c.fold(folder)?, - } - ControlFlow::Continue(this) - } -} - -impl Foldable for RigidTy { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - let mut this = self.clone(); - match &mut this { - RigidTy::Bool - | RigidTy::Char - | RigidTy::Int(_) - | RigidTy::Uint(_) - | RigidTy::Float(_) - | RigidTy::Never - | RigidTy::Foreign(_) - | RigidTy::Str => {} - RigidTy::Array(t, c) => { - *t = t.fold(folder)?; - *c = c.fold(folder)?; - } - RigidTy::Slice(inner) => *inner = inner.fold(folder)?, - RigidTy::RawPtr(ty, _) => *ty = ty.fold(folder)?, - RigidTy::Ref(reg, ty, _) => { - *reg = reg.fold(folder)?; - *ty = ty.fold(folder)? - } - RigidTy::FnDef(_, args) => *args = args.fold(folder)?, - RigidTy::FnPtr(sig) => *sig = sig.fold(folder)?, - RigidTy::Closure(_, args) => *args = args.fold(folder)?, - RigidTy::Coroutine(_, args, _) => *args = args.fold(folder)?, - RigidTy::Dynamic(pred, r, _) => { - *pred = pred.fold(folder)?; - *r = r.fold(folder)?; - } - RigidTy::Tuple(fields) => *fields = fields.fold(folder)?, - RigidTy::Adt(_, args) => *args = args.fold(folder)?, - } - ControlFlow::Continue(this) - } -} - -impl<T: Foldable> Foldable for Vec<T> { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - let mut this = self.clone(); - for arg in &mut this { - *arg = arg.fold(folder)?; - } - ControlFlow::Continue(this) - } -} - -impl<T: Foldable> Foldable for Binder<T> { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(Self { - value: self.value.fold(folder)?, - bound_vars: self.bound_vars.clone(), - }) - } -} - -impl Foldable for ExistentialPredicate { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - let mut this = self.clone(); - match &mut this { - ExistentialPredicate::Trait(tr) => tr.generic_args = tr.generic_args.fold(folder)?, - ExistentialPredicate::Projection(p) => { - p.term = p.term.fold(folder)?; - p.generic_args = p.generic_args.fold(folder)?; - } - ExistentialPredicate::AutoTrait(_) => {} - } - ControlFlow::Continue(this) - } -} - -impl Foldable for TermKind { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(match self { - TermKind::Type(t) => TermKind::Type(t.fold(folder)?), - TermKind::Const(c) => TermKind::Const(c.fold(folder)?), - }) - } -} - -impl Foldable for FnSig { - fn super_fold<V: Folder>(&self, folder: &mut V) -> ControlFlow<V::Break, Self> { - ControlFlow::Continue(Self { - inputs_and_output: self.inputs_and_output.fold(folder)?, - c_variadic: self.c_variadic, - unsafety: self.unsafety, - abi: self.abi.clone(), - }) - } -} - -pub enum Never {} - -/// In order to instantiate a `Foldable`'s generic parameters with specific arguments, -/// `GenericArgs` can be used as a `Folder` that replaces all mentions of generic params -/// with the entries in its list. -impl Folder for GenericArgs { - type Break = Never; - - fn fold_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break, Ty> { - ControlFlow::Continue(match ty.kind() { - TyKind::Param(p) => self[p], - _ => *ty, - }) - } - - fn fold_const(&mut self, c: &Const) -> ControlFlow<Self::Break, Const> { - ControlFlow::Continue(match &c.literal { - ConstantKind::Param(p) => self[p.clone()].clone(), - _ => c.clone(), - }) - } -} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index be5ccac78c7..38915afaa0c 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -32,7 +32,6 @@ use self::ty::{ extern crate scoped_tls; pub mod error; -pub mod fold; pub mod mir; pub mod ty; pub mod visitor; @@ -175,17 +174,17 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait { } pub trait Context { - fn entry_fn(&mut self) -> Option<CrateItem>; + fn entry_fn(&self) -> Option<CrateItem>; /// Retrieve all items of the local crate that have a MIR associated with them. - fn all_local_items(&mut self) -> CrateItems; - fn mir_body(&mut self, item: DefId) -> mir::Body; - fn all_trait_decls(&mut self) -> TraitDecls; - fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl; - fn all_trait_impls(&mut self) -> ImplTraitDecls; - fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait; - fn generics_of(&mut self, def_id: DefId) -> Generics; - fn predicates_of(&mut self, def_id: DefId) -> GenericPredicates; - fn explicit_predicates_of(&mut self, def_id: DefId) -> GenericPredicates; + fn all_local_items(&self) -> CrateItems; + fn mir_body(&self, item: DefId) -> mir::Body; + fn all_trait_decls(&self) -> TraitDecls; + fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl; + fn all_trait_impls(&self) -> ImplTraitDecls; + fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait; + fn generics_of(&self, def_id: DefId) -> Generics; + fn predicates_of(&self, def_id: DefId) -> GenericPredicates; + fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates; /// Get information about the local crate. fn local_crate(&self) -> Crate; /// Retrieve a list of all external crates. @@ -207,61 +206,55 @@ pub trait Context { fn get_lines(&self, span: &Span) -> LineInfo; /// Returns the `kind` of given `DefId` - fn def_kind(&mut self, def_id: DefId) -> DefKind; + fn def_kind(&self, def_id: DefId) -> DefKind; /// `Span` of an item - fn span_of_an_item(&mut self, def_id: DefId) -> Span; + fn span_of_an_item(&self, def_id: DefId) -> Span; /// Obtain the representation of a type. - fn ty_kind(&mut self, ty: Ty) -> TyKind; - - /// Create a new `Ty` from scratch without information from rustc. - fn mk_ty(&mut self, kind: TyKind) -> Ty; + fn ty_kind(&self, ty: Ty) -> TyKind; /// Get the body of an Instance. /// FIXME: Monomorphize the body. - fn instance_body(&mut self, instance: InstanceDef) -> Body; + fn instance_body(&self, instance: InstanceDef) -> Body; /// Get the instance type with generic substitutions applied and lifetimes erased. - fn instance_ty(&mut self, instance: InstanceDef) -> Ty; + fn instance_ty(&self, instance: InstanceDef) -> Ty; /// Get the instance. - fn instance_def_id(&mut self, instance: InstanceDef) -> DefId; + fn instance_def_id(&self, instance: InstanceDef) -> DefId; /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. - fn mono_instance(&mut self, item: CrateItem) -> Instance; + fn mono_instance(&self, item: CrateItem) -> Instance; /// Item requires monomorphization. fn requires_monomorphization(&self, def_id: DefId) -> bool; /// Resolve an instance from the given function definition and generic arguments. - fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option<Instance>; + fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt // datastructures and stable MIR datastructures -scoped_thread_local! (static TLV: Cell<*mut ()>); +scoped_thread_local! (static TLV: Cell<*const ()>); -pub fn run(mut context: impl Context, f: impl FnOnce()) { +pub fn run(context: &dyn Context, f: impl FnOnce()) { assert!(!TLV.is_set()); - fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) { - let ptr: *mut () = &mut context as *mut &mut _ as _; - TLV.set(&Cell::new(ptr), || { - f(); - }); - } - g(&mut context, f); + let ptr: *const () = &context as *const &_ as _; + TLV.set(&Cell::new(ptr), || { + f(); + }); } /// Loads the current context and calls a function with it. /// Do not nest these, as that will ICE. -pub fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R { +pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R { assert!(TLV.is_set()); TLV.with(|tlv| { let ptr = tlv.get(); assert!(!ptr.is_null()); - f(unsafe { *(ptr as *mut &mut dyn Context) }) + f(unsafe { *(ptr as *const &dyn Context) }) }) } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 5eee1ec00df..50c37e8f910 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -2,10 +2,60 @@ use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability use crate::Opaque; use crate::{ty::Ty, Span}; +/// The SMIR representation of a single function. #[derive(Clone, Debug)] pub struct Body { pub blocks: Vec<BasicBlock>, - pub locals: LocalDecls, + + // Declarations of locals within the function. + // + // The first local is the return value pointer, followed by `arg_count` + // locals for the function arguments, followed by any user-declared + // variables and temporaries. + locals: LocalDecls, + + // The number of arguments this function takes. + arg_count: usize, +} + +impl Body { + /// Constructs a `Body`. + /// + /// A constructor is required to build a `Body` from outside the crate + /// because the `arg_count` and `locals` fields are private. + pub fn new(blocks: Vec<BasicBlock>, locals: LocalDecls, arg_count: usize) -> Self { + // If locals doesn't contain enough entries, it can lead to panics in + // `ret_local`, `arg_locals`, and `inner_locals`. + assert!( + locals.len() > arg_count, + "A Body must contain at least a local for the return value and each of the function's arguments" + ); + Self { blocks, locals, arg_count } + } + + /// Return local that holds this function's return value. + pub fn ret_local(&self) -> &LocalDecl { + &self.locals[0] + } + + /// Locals in `self` that correspond to this function's arguments. + pub fn arg_locals(&self) -> &[LocalDecl] { + &self.locals[1..][..self.arg_count] + } + + /// Inner locals for this function. These are the locals that are + /// neither the return local nor the argument locals. + pub fn inner_locals(&self) -> &[LocalDecl] { + &self.locals[self.arg_count + 1..] + } + + /// Convenience function to get all the locals in this function. + /// + /// Locals are typically accessed via the more specific methods `ret_local`, + /// `arg_locals`, and `inner_locals`. + pub fn locals(&self) -> &[LocalDecl] { + &self.locals + } } type LocalDecls = Vec<LocalDecl>; @@ -135,12 +185,12 @@ pub enum UnOp { #[derive(Clone, Debug)] pub enum CoroutineKind { - Async(AsyncCoroutineKind), + Async(CoroutineSource), Coroutine, } #[derive(Clone, Debug)] -pub enum AsyncCoroutineKind { +pub enum CoroutineSource { Block, Closure, Fn, @@ -467,7 +517,7 @@ pub enum NullOp { } impl Operand { - pub fn ty(&self, locals: &LocalDecls) -> Ty { + pub fn ty(&self, locals: &[LocalDecl]) -> Ty { match self { Operand::Copy(place) | Operand::Move(place) => place.ty(locals), Operand::Constant(c) => c.ty(), @@ -477,12 +527,12 @@ impl Operand { impl Constant { pub fn ty(&self) -> Ty { - self.literal.ty + self.literal.ty() } } impl Place { - pub fn ty(&self, locals: &LocalDecls) -> Ty { + pub fn ty(&self, locals: &[LocalDecl]) -> Ty { let _start_ty = locals[self.local].ty; todo!("Implement projection") } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 8f7f8bd4e38..0dbf6fe23aa 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -6,7 +6,7 @@ use super::{ use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Formatter}; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct Ty(pub usize); impl Debug for Ty { @@ -21,18 +21,37 @@ impl Ty { } } -impl From<TyKind> for Ty { - fn from(value: TyKind) -> Self { - with(|context| context.mk_ty(value)) +/// Represents a constant in MIR or from the Type system. +#[derive(Clone, Debug)] +pub struct Const { + /// The constant kind. + kind: ConstantKind, + /// The constant type. + ty: Ty, + /// Used for internal tracking of the internal constant. + pub id: ConstId, +} + +impl Const { + /// Build a constant. Note that this should only be used by the compiler. + pub fn new(kind: ConstantKind, ty: Ty, id: ConstId) -> Const { + Const { kind, ty, id } } -} -#[derive(Debug, Clone)] -pub struct Const { - pub literal: ConstantKind, - pub ty: Ty, + /// Retrieve the constant kind. + pub fn kind(&self) -> &ConstantKind { + &self.kind + } + + /// Get the constant type. + pub fn ty(&self) -> Ty { + self.ty + } } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ConstId(pub usize); + type Ident = Opaque; #[derive(Debug, Clone)] @@ -108,15 +127,6 @@ pub struct LineInfo { pub end_col: usize, } -impl IndexedVal for Span { - fn to_val(index: usize) -> Self { - Span(index) - } - fn to_index(&self) -> usize { - self.0 - } -} - #[derive(Clone, Debug)] pub enum TyKind { RigidTy(RigidTy), @@ -603,3 +613,20 @@ pub trait IndexedVal { fn to_index(&self) -> usize; } + +macro_rules! index_impl { + ($name:ident) => { + impl IndexedVal for $name { + fn to_val(index: usize) -> Self { + $name(index) + } + fn to_index(&self) -> usize { + self.0 + } + } + }; +} + +index_impl!(ConstId); +index_impl!(Ty); +index_impl!(Span); diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs index a6020cc5bd9..c337f5b68d3 100644 --- a/compiler/stable_mir/src/visitor.rs +++ b/compiler/stable_mir/src/visitor.rs @@ -47,12 +47,12 @@ impl Visitable for Const { visitor.visit_const(self) } fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { - match &self.literal { + match &self.kind() { super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, super::ty::ConstantKind::Param(_) => {} } - self.ty.visit(visitor) + self.ty().visit(visitor) } } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index b2c9a0800c9..6908c824f44 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -6,7 +6,7 @@ //! match those defined by C, so that code that interacts with C will //! refer to the correct types. -#![stable(feature = "", since = "1.30.0")] +#![stable(feature = "core_ffi", since = "1.30.0")] #![allow(non_camel_case_types)] use crate::fmt; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index c7ace58afa8..166d04e078d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -69,6 +69,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} message = "`{Self}` is not an iterator" )] #[doc(notable_trait)] +#[cfg_attr(not(bootstrap), lang = "iterator")] #[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] pub trait Iterator { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 03243e31348..a1220d45a5c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -253,6 +253,7 @@ #![feature(try_blocks)] #![feature(unboxed_closures)] #![feature(unsized_fn_params)] +#![feature(with_negative_coherence)] // tidy-alphabetical-end // // Target features: diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 8396aecf947..55116285842 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -1,6 +1,4 @@ -use crate::cmp::Ordering; use crate::fmt::{self, Write}; -use crate::hash; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use super::display_buffer::DisplayBuffer; @@ -63,7 +61,7 @@ pub enum SocketAddr { /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); /// assert_eq!(socket.port(), 8080); /// ``` -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV4 { ip: Ipv4Addr, @@ -96,7 +94,7 @@ pub struct SocketAddrV4 { /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); /// assert_eq!(socket.port(), 8080); /// ``` -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct SocketAddrV6 { ip: Ipv6Addr, @@ -644,48 +642,3 @@ impl fmt::Debug for SocketAddrV6 { fmt::Display::fmt(self, fmt) } } - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddrV4 { - #[inline] - fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl PartialOrd for SocketAddrV6 { - #[inline] - fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl Ord for SocketAddrV4 { - #[inline] - fn cmp(&self, other: &SocketAddrV4) -> Ordering { - self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) - } -} - -#[stable(feature = "socketaddr_ordering", since = "1.45.0")] -impl Ord for SocketAddrV6 { - #[inline] - fn cmp(&self, other: &SocketAddrV6) -> Ordering { - self.ip().cmp(other.ip()).then(self.port().cmp(&other.port())) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for SocketAddrV4 { - fn hash<H: hash::Hasher>(&self, s: &mut H) { - (self.port, self.ip).hash(s) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for SocketAddrV6 { - fn hash<H: hash::Hasher>(&self, s: &mut H) { - (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s) - } -} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 8b127132c1c..a6c1adfac65 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -114,7 +114,7 @@ macro_rules! midpoint_impl { without modifying the original"] #[inline] pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { - // Use the well known branchless algorthim from Hacker's Delight to compute + // Use the well known branchless algorithm from Hacker's Delight to compute // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`. ((self ^ rhs) >> 1) + (self & rhs) } diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index e01a893a068..cd5ca988f7e 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -29,7 +29,7 @@ pub enum CoroutineState<Y, R> { /// The trait implemented by builtin coroutine types. /// -/// Coroutines, also commonly referred to as coroutines, are currently an +/// Coroutines are currently an /// experimental language feature in Rust. Added in [RFC 2033] coroutines are /// currently intended to primarily provide a building block for async/await /// syntax but will likely extend to also providing an ergonomic definition for diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs index 35a69cead48..3d013d37e04 100644 --- a/library/core/tests/net/socket_addr.rs +++ b/library/core/tests/net/socket_addr.rs @@ -199,6 +199,9 @@ fn compare() { let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap(); let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap(); let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap(); + let v6_4 = "[2001:db8:f00::2001%42]:23456".parse::<SocketAddrV6>().unwrap(); + let mut v6_5 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap(); + v6_5.set_flowinfo(17); // equality assert_eq!(v4_1, v4_1); @@ -207,6 +210,8 @@ fn compare() { assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); assert!(v4_1 != v4_2); assert!(v6_1 != v6_2); + assert!(v6_3 != v6_4); + assert!(v6_3 != v6_5); // compare different addresses assert!(v4_1 < v4_2); @@ -226,6 +231,12 @@ fn compare() { assert!(v4_3 > v4_1); assert!(v6_3 > v6_1); + // compare the same address with different scope_id + assert!(v6_3 < v6_4); + + // compare the same address with different flowinfo + assert!(v6_3 < v6_5); + // compare with an inferred right-hand side assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 063464046e0..bca5d859b66 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1140,10 +1140,10 @@ pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> { #[repr(transparent)] pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>); -#[stable(feature = "iovec-send-sync", since = "1.44.0")] +#[stable(feature = "iovec_send_sync", since = "1.44.0")] unsafe impl<'a> Send for IoSliceMut<'a> {} -#[stable(feature = "iovec-send-sync", since = "1.44.0")] +#[stable(feature = "iovec_send_sync", since = "1.44.0")] unsafe impl<'a> Sync for IoSliceMut<'a> {} #[stable(feature = "iovec", since = "1.36.0")] @@ -1283,10 +1283,10 @@ impl<'a> DerefMut for IoSliceMut<'a> { #[repr(transparent)] pub struct IoSlice<'a>(sys::io::IoSlice<'a>); -#[stable(feature = "iovec-send-sync", since = "1.44.0")] +#[stable(feature = "iovec_send_sync", since = "1.44.0")] unsafe impl<'a> Send for IoSlice<'a> {} -#[stable(feature = "iovec-send-sync", since = "1.44.0")] +#[stable(feature = "iovec_send_sync", since = "1.44.0")] unsafe impl<'a> Sync for IoSlice<'a> {} #[stable(feature = "iovec", since = "1.36.0")] diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index 73c530786b2..3dbab4cc486 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -134,9 +134,19 @@ mod imp { // OpenBSD requires this flag for stack mapping // otherwise the said mapping will fail as a no-op on most systems // and has a different meaning on FreeBSD - #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",))] + #[cfg(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "dragonfly", + ))] let flags = MAP_PRIVATE | MAP_ANON | libc::MAP_STACK; - #[cfg(not(any(target_os = "openbsd", target_os = "netbsd", target_os = "linux",)))] + #[cfg(not(any( + target_os = "openbsd", + target_os = "netbsd", + target_os = "linux", + target_os = "dragonfly", + )))] let flags = MAP_PRIVATE | MAP_ANON; let stackp = mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0); diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 96a0eb75582..19f666d0463 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -50,6 +50,7 @@ dependencies = [ "fd-lock", "filetime", "hex", + "home", "ignore", "junction", "libc", @@ -351,6 +352,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] +name = "home" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" +dependencies = [ + "winapi", +] + +[[package]] name = "ignore" version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e236421b7f5..bc025f44484 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -40,6 +40,7 @@ clap_complete = "4.4.3" cmake = "0.1.38" filetime = "0.2" hex = "0.4" +home = "0.5.4" ignore = "0.4.10" libc = "0.2" object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py index 7f16cac7890..e6caabec4f6 100644 --- a/src/bootstrap/bootstrap_test.py +++ b/src/bootstrap/bootstrap_test.py @@ -103,7 +103,6 @@ class GenerateAndParseConfig(unittest.TestCase): """Test that we can serialize and deserialize a config.toml file""" def test_no_args(self): build = serialize_and_parse([]) - self.assertEqual(build.get_toml("change-id"), '116998') self.assertEqual(build.get_toml("profile"), 'dist') self.assertIsNone(build.get_toml("llvm.download-ci-llvm")) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 241ae16e595..04bf9723edd 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -124,6 +124,13 @@ fn main() { if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { cmd.arg("--remap-path-prefix").arg(&map); } + // The remap flags for Cargo registry sources need to be passed after the remapping for the + // Rust source code directory, to handle cases when $CARGO_HOME is inside the source directory. + if let Ok(maps) = env::var("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP") { + for map in maps.split('\t') { + cmd.arg("--remap-path-prefix").arg(map); + } + } // Force all crates compiled by this compiler to (a) be unstable and (b) // allow the `rustc_private` feature to link to other unstable crates diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs index f5f80ba2a0b..dbbce6fe220 100644 --- a/src/bootstrap/src/bin/rustdoc.rs +++ b/src/bootstrap/src/bin/rustdoc.rs @@ -70,7 +70,9 @@ fn main() { cmd.arg("--cfg=bootstrap"); } cmd.arg("-Zunstable-options"); + // #[cfg(bootstrap)] cmd.arg("--check-cfg=values(bootstrap)"); + // cmd.arg("--check-cfg=cfg(bootstrap)"); if verbose > 1 { eprintln!( diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 039a87e760d..36653dcfb20 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -2,7 +2,7 @@ use std::any::{type_name, Any}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::env; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Write}; use std::fs::{self, File}; use std::hash::Hash; @@ -1401,19 +1401,28 @@ impl<'a> Builder<'a> { rustflags.arg("-Zunstable-options"); } - // Enable cfg checking of cargo features for everything but std and also enable cfg - // checking of names and values. + // #[cfg(bootstrap)] + let use_new_check_cfg_syntax = self.local_rebuild; + + // Enable compile-time checking of `cfg` names, values and Cargo `features`. // // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like // backtrace, core_simd, std_float, ...), those dependencies have their own // features but cargo isn't involved in the #[path] process and so cannot pass the // complete list of features, so for that reason we don't enable checking of // features for std crates. - cargo.arg(if mode != Mode::Std { - "-Zcheck-cfg=names,values,output,features" + if use_new_check_cfg_syntax { + cargo.arg("-Zcheck-cfg"); + if mode == Mode::Std { + rustflags.arg("--check-cfg=cfg(feature,values(any()))"); + } } else { - "-Zcheck-cfg=names,values,output" - }); + cargo.arg(if mode != Mode::Std { + "-Zcheck-cfg=names,values,output,features" + } else { + "-Zcheck-cfg=names,values,output" + }); + } // Add extra cfg not defined in/by rustc // @@ -1433,7 +1442,12 @@ impl<'a> Builder<'a> { .collect::<String>(), None => String::new(), }; - rustflags.arg(&format!("--check-cfg=values({name}{values})")); + if use_new_check_cfg_syntax { + let values = values.strip_prefix(",").unwrap_or(&values); // remove the first `,` + rustflags.arg(&format!("--check-cfg=cfg({name},values({values}))")); + } else { + rustflags.arg(&format!("--check-cfg=values({name}{values})")); + } } } @@ -1449,7 +1463,11 @@ impl<'a> Builder<'a> { // We also declare that the flag is expected, which we need to do to not // get warnings about it being unexpected. hostflags.arg("-Zunstable-options"); - hostflags.arg("--check-cfg=values(bootstrap)"); + if use_new_check_cfg_syntax { + hostflags.arg("--check-cfg=cfg(bootstrap)"); + } else { + hostflags.arg("--check-cfg=values(bootstrap)"); + } // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`, // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See @@ -1767,6 +1785,20 @@ impl<'a> Builder<'a> { cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to); } + if self.config.rust_remap_debuginfo { + // FIXME: handle vendored sources + let registry_src = t!(home::cargo_home()).join("registry").join("src"); + let mut env_var = OsString::new(); + for entry in t!(std::fs::read_dir(registry_src)) { + if !env_var.is_empty() { + env_var.push("\t"); + } + env_var.push(t!(entry).path()); + env_var.push("=/rust/deps"); + } + cargo.env("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP", env_var); + } + // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); self.add_rust_test_threads(&mut cargo); diff --git a/src/doc/book b/src/doc/book -Subproject 72187f5cd0beaaa9c6f584156bcd88f921871e8 +Subproject 3dca2fc50b922a8efb94903b9fee8bb42ab48f3 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject eac173690b8cc99094e1d88bd49dd61127fbd28 +Subproject 22bca3d0f6e9b9b556689b54ce96f25b46ecd1b diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject ddfa4214487686e91b21aa29afb972c08a8f0d5 +Subproject 1842257814919fa62e81bdecd5e8f95be2839db diff --git a/src/doc/reference b/src/doc/reference -Subproject 142b2ed77d33f37a9973772bd95e6144ed9dce4 +Subproject 16fd3c06d9e558dae2d52000818274ae70c9e90 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 8eb3a01ab74c567b7174784892fb807f2c632d6 +Subproject 6709beeb7d0fbc5ffc91ac4893a24434123b9bf diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject b98af7d661e4744baab81fb8dc7a049e44a4a99 +Subproject b0ee9ec8fa59a6c7620165e061f4747202377a6 diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md index 57c717c182d..a54abcb606e 100644 --- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md +++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md @@ -10,9 +10,15 @@ target | std | host | notes `csky-unknown-linux-gnuabiv2hf` | ✓ | | C-SKY abiv2 Linux, hardfloat (little endian) Reference: -https://c-sky.github.io/ -https://gitlab.com/c-sky/ +- [CSKY ABI Manual](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1695027452256/T-HEAD_800_Series_ABI_Standards_Manual.pdf) +- [csky-linux-gnuabiv2-toolchain](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource/1356021/1619528643136/csky-linux-gnuabiv2-tools-x86_64-glibc-linux-4.9.56-20210423.tar.gz) +- [csky-linux-gnuabiv2-qemu](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1689324918932/xuantie-qemu-x86_64-Ubuntu-18.04-20230714-0202.tar.gz) + +other links: + +- https://c-sky.github.io/ +- https://gitlab.com/c-sky/ ## Target maintainers diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index ca18ec567a4..7a3ef5e9e2b 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -123,7 +123,7 @@ rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ fn do_embedded() {} // and because names exhaustiveness was not disabled #[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg() -fn do_features() {} // and because names exhaustiveness was not disbaled +fn do_features() {} // and because names exhaustiveness was not disabled #[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg() // and because no value checking was enable for "has_feathers" diff --git a/src/doc/unstable-book/src/language-features/coroutines.md b/src/doc/unstable-book/src/language-features/coroutines.md index fb1ba791aef..f8e5a22fbd5 100644 --- a/src/doc/unstable-book/src/language-features/coroutines.md +++ b/src/doc/unstable-book/src/language-features/coroutines.md @@ -18,7 +18,7 @@ Coroutines are an extra-unstable feature in the compiler right now. Added in [RFC 2033] they're mostly intended right now as a information/constraint gathering phase. The intent is that experimentation can happen on the nightly compiler before actual stabilization. A further RFC will be required to -stabilize coroutines/coroutines and will likely contain at least a few small +stabilize coroutines and will likely contain at least a few small tweaks to the overall design. [RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6a7410144fd..449aac4cfc8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -12,7 +12,7 @@ use thin_vec::ThinVec; use rustc_ast as ast; use rustc_ast_pretty::pprust; -use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; +use rustc_attr::{ConstStability, Deprecation, Since, Stability, StabilityLevel}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; @@ -585,14 +585,14 @@ impl Item { }) } - pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> { + pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Since> { match self.stability(tcx)?.level { StabilityLevel::Stable { since, .. } => Some(since), StabilityLevel::Unstable { .. } => None, } } - pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> { + pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Since> { match self.const_stability(tcx)?.level { StabilityLevel::Stable { since, .. } => Some(since), StabilityLevel::Unstable { .. } => None, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9066061f1a2..94e557dcfdb 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -23,6 +23,7 @@ use std::cell::RefCell; use std::mem; use std::rc::Rc; use std::sync::LazyLock; +use std::sync::{atomic::AtomicBool, Arc}; use crate::clean::inline::build_external_trait; use crate::clean::{self, ItemId}; @@ -198,6 +199,7 @@ pub(crate) fn create_config( .. }: RustdocOptions, RenderOptions { document_private, .. }: &RenderOptions, + using_internal_features: Arc<AtomicBool>, ) -> rustc_interface::Config { // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); @@ -293,6 +295,7 @@ pub(crate) fn create_config( make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + using_internal_features, expanded_args, } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index db69cf5752d..97913345e8f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -110,6 +110,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + using_internal_features: Arc::default(), expanded_args: options.expanded_args.clone(), }; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 89e29d8b59b..e01341acf43 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -48,7 +48,7 @@ use std::str; use std::string::ToString; use askama::Template; -use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; +use rustc_attr::{ConstStability, Deprecation, Since, StabilityLevel, CURRENT_RUSTC_VERSION}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; @@ -911,13 +911,17 @@ fn assoc_method( /// consequence of the above rules. fn render_stability_since_raw_with_extra( w: &mut Buffer, - ver: Option<Symbol>, + ver: Option<Since>, const_stability: Option<ConstStability>, - containing_ver: Option<Symbol>, - containing_const_ver: Option<Symbol>, + containing_ver: Option<Since>, + containing_const_ver: Option<Since>, extra_class: &str, ) -> bool { - let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver); + let stable_version = if ver != containing_ver && let Some(ver) = &ver { + since_to_string(ver) + } else { + None + }; let mut title = String::new(); let mut stability = String::new(); @@ -931,7 +935,8 @@ fn render_stability_since_raw_with_extra( Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. }) if Some(since) != containing_const_ver => { - Some((format!("const since {since}"), format!("const: {since}"))) + since_to_string(&since) + .map(|since| (format!("const since {since}"), format!("const: {since}"))) } Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => { let unstable = if let Some(n) = issue { @@ -971,13 +976,21 @@ fn render_stability_since_raw_with_extra( !stability.is_empty() } +fn since_to_string(since: &Since) -> Option<String> { + match since { + Since::Version(since) => Some(since.to_string()), + Since::Current => Some(CURRENT_RUSTC_VERSION.to_owned()), + Since::Err => None, + } +} + #[inline] fn render_stability_since_raw( w: &mut Buffer, - ver: Option<Symbol>, + ver: Option<Since>, const_stability: Option<ConstStability>, - containing_ver: Option<Symbol>, - containing_const_ver: Option<Symbol>, + containing_ver: Option<Since>, + containing_const_ver: Option<Since>, ) -> bool { render_stability_since_raw_with_extra( w, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 67f5ea5d98b..41aee06c8d2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -74,6 +74,7 @@ extern crate jemalloc_sys; use std::env::{self, VarError}; use std::io::{self, IsTerminal}; use std::process; +use std::sync::{atomic::AtomicBool, Arc}; use rustc_driver::abort_on_err; use rustc_errors::ErrorGuaranteed; @@ -157,7 +158,7 @@ pub fn main() { let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); - rustc_driver::install_ice_hook( + let using_internal_features = rustc_driver::install_ice_hook( "https://github.com/rust-lang/rust/issues/new\ ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md", |_| (), @@ -177,7 +178,7 @@ pub fn main() { rustc_driver::init_env_logger(&handler, "RUSTDOC_LOG"); let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&handler) { - Some(args) => main_args(&mut handler, &args), + Some(args) => main_args(&mut handler, &args, using_internal_features), _ => { #[allow(deprecated)] @@ -701,7 +702,11 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( } } -fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult { +fn main_args( + handler: &mut EarlyErrorHandler, + at_args: &[String], + using_internal_features: Arc<AtomicBool>, +) -> MainResult { // Throw away the first argument, the name of the binary. // In case of at_args being empty, as might be the case by // passing empty argument array to execve under some platforms, @@ -752,7 +757,8 @@ fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult (false, true) => { let input = options.input.clone(); let edition = options.edition; - let config = core::create_config(handler, options, &render_options); + let config = + core::create_config(handler, options, &render_options, using_internal_features); // `markdown::render` can invoke `doctest::make_test`, which // requires session globals and a thread pool, so we use @@ -785,7 +791,7 @@ fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult let scrape_examples_options = options.scrape_examples_options.clone(); let bin_crate = options.bin_crate; - let config = core::create_config(handler, options, &render_options); + let config = core::create_config(handler, options, &render_options, using_internal_features); interface::run_compiler(config, |compiler| { let sess = compiler.session(); diff --git a/src/tools/cargo b/src/tools/cargo -Subproject d2f6a048529eb8e9ebc55d793abd63456c98fac +Subproject df3509237935f9418351b77803df7bc05c009b3 diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 56f56fff1e7..050df68a0fa 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{AsyncCoroutineKind, Body, BodyId, CoroutineKind, ExprKind, QPath}; +use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,7 +45,7 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - use AsyncCoroutineKind::{Block, Closure}; + use CoroutineSource::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index ae8618dcaa0..0c356934992 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{AsyncCoroutineKind, Body, CoroutineKind}; +use rustc_hir::{CoroutineSource, Body, CoroutineKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -195,7 +195,7 @@ impl LateLintPass<'_> for AwaitHolding { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - use AsyncCoroutineKind::{Block, Closure, Fn}; + use CoroutineSource::{Block, Closure, Fn}; if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 5a87e75722d..a75c76d6fe0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - AsyncCoroutineKind, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, + CoroutineSource, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); + if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block)); then { return Some(closure_body); } diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index ed279a3813d..b3a2060d6ac 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{AsyncCoroutineKind, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{CoroutineSource, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind { + if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 2e895d5f236..bf9bdacba5b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{AsyncCoroutineKind, Closure, CoroutineKind, Expr, ExprKind, MatchSource}; +use rustc_hir::{CoroutineSource, Closure, CoroutineKind, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) && - matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) + matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) { cx .typeck_results() diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index f6096ea546d..1e465ac91b7 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -5,6 +5,7 @@ use crate::msrvs::Msrv; use hir::LangItem; +use rustc_attr::{Since, CURRENT_RUSTC_VERSION}; use rustc_const_eval::transform::check_consts::ConstCx; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -370,19 +371,24 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { // function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. - // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver` - // doesn't accept the `-dev` version number so we have to strip it off. - let short_version = since - .as_str() - .split('-') - .next() - .expect("rustc_attr::StabilityLevel::Stable::since` is empty"); + let const_stab_rust_version = match since { + Since::Version(version) => RustcVersion::new( + u32::from(version.major), + u32::from(version.minor), + u32::from(version.patch), + ), + Since::Current => { + // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. + // `rustc-semver` doesn't accept the `-dev` version number so we have to strip it off. + let short_version = CURRENT_RUSTC_VERSION.split('-').next().unwrap(); + RustcVersion::parse(short_version).unwrap_or_else(|err| { + panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{CURRENT_RUSTC_VERSION}`, {err:?}") + }) + }, + Since::Err => return false, + }; - let since = rustc_span::Symbol::intern(short_version); - - msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| { - panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}") - })) + msrv.meets(const_stab_rust_version) } else { // Unstable const fn with the feature enabled. msrv.current().is_none() diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 0e81419f1fa..11290f88a49 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -178,7 +178,7 @@ pub fn main() { rustc_driver::init_rustc_env_logger(&handler); - rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| { + let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| { // FIXME: this macro calls unwrap internally but is called in a panicking context! It's not // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't // accept a generic closure. @@ -265,9 +265,11 @@ pub fn main() { let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package); if clippy_enabled { args.extend(clippy_args); - rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }).run() + rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }) + .set_using_internal_features(using_internal_features).run() } else { - rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }).run() + rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }) + .set_using_internal_features(using_internal_features).run() } })) } diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index 30be9dde73c..f929bec9583 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -24,6 +24,16 @@ help: you might be missing a type parameter LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | +++++ -error: aborting due to 2 previous errors +error[E0046]: not all trait items implemented, missing: `VAL` + --> $DIR/ice-6252.rs:11:1 + | +LL | const VAL: T; + | ------------ `VAL` from trait +... +LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0046, E0412. +For more information about an error, try `rustc --explain E0046`. diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs index 7b9dc76b8f1..775e071147c 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs @@ -1,8 +1,8 @@ // This file provides a const function that is unstably const forever. #![feature(staged_api)] -#![stable(feature = "1", since = "1.0.0")] +#![stable(feature = "clippytest", since = "1.0.0")] -#[stable(feature = "1", since = "1.0.0")] +#[stable(feature = "clippytest", since = "1.0.0")] #[rustc_const_unstable(feature = "foo", issue = "none")] pub const fn unstably_const_fn() {} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ac270a1f0ba..87d0404e7d8 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3999,10 +3999,10 @@ impl<'test> TestCx<'test> { let passes = std::mem::take(&mut test_info.passes); let proc_res = self.compile_test_with_passes(should_run, Emit::Mir, passes); - self.check_mir_dump(test_info); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); } + self.check_mir_dump(test_info); if let WillExecute::Yes = should_run { let proc_res = self.exec_compiled_test(); diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index eda1ceb4084..5078e9eaab3 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -108,7 +108,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic env/var MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0335ad3c1d8..60ae5d12598 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -9e3f784eb2c7c847b6c3578b373c0e0bc9233ca3 +2e4e2a8f288f642cafcc41fff211955ceddc453d diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index fc6151772a0..531128ed2ec 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -241,6 +241,7 @@ fn run_compiler( mut args: Vec<String>, target_crate: bool, callbacks: &mut (dyn rustc_driver::Callbacks + Send), + using_internal_features: std::sync::Arc<std::sync::atomic::AtomicBool> ) -> ! { if target_crate { // Miri needs a custom sysroot for target crates. @@ -273,7 +274,8 @@ fn run_compiler( // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { - rustc_driver::RunCompiler::new(&args, callbacks).run() + rustc_driver::RunCompiler::new(&args, callbacks) + .set_using_internal_features(using_internal_features).run() }); std::process::exit(exit_code) } @@ -295,7 +297,7 @@ fn main() { // If the environment asks us to actually be rustc, then do that. if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { // Earliest rustc setup. - rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ()); + let using_internal_features = rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ()); rustc_driver::init_rustc_env_logger(&handler); let target_crate = if crate_kind == "target" { @@ -311,11 +313,12 @@ fn main() { env::args().collect(), target_crate, &mut MiriBeRustCompilerCalls { target_crate }, + using_internal_features, ) } // Add an ICE bug report hook. - rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ()); + let using_internal_features = rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ()); // Init loggers the Miri way. init_early_loggers(&handler); @@ -578,5 +581,5 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config }) + run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config }, using_internal_features) } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index b63b0bdff12..4232cd396c9 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -661,13 +661,11 @@ impl<'tcx> Tree { for (perms_range, perms) in self.rperms.iter_mut_all() { let idx = self.tag_mapping.get(&tag).unwrap(); // Only visit initialized permissions - if let Some(p) = perms.get(idx) && p.initialized { - TreeVisitor { - nodes: &mut self.nodes, - tag_mapping: &self.tag_mapping, - perms, - } - .traverse_nonchildren( + if let Some(p) = perms.get(idx) + && p.initialized + { + TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms } + .traverse_nonchildren( tag, |args| node_app(perms_range.clone(), args), |args| err_handler(perms_range.clone(), args), diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index bec2972c50d..4cab86af886 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -41,6 +41,7 @@ //! on the data-race detection code. use std::{ + borrow::Cow, cell::{Cell, Ref, RefCell, RefMut}, fmt::Debug, mem, @@ -167,7 +168,7 @@ pub struct DataRace; /// explicitly to reduce memory usage for the /// common case where no atomic operations /// exists on the memory cell. -#[derive(Clone, PartialEq, Eq, Default, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] struct AtomicMemoryCellClocks { /// The clock-vector of the timestamp of the last atomic /// read operation performed by each thread. @@ -186,6 +187,11 @@ struct AtomicMemoryCellClocks { /// happen-before a thread if an acquire-load is /// performed on the data. sync_vector: VClock, + + /// The size of accesses to this atomic location. + /// We use this to detect non-synchronized mixed-size accesses. Since all accesses must be + /// aligned to their size, this is sufficient to detect imperfectly overlapping accesses. + size: Size, } /// Type of write operation: allocating memory @@ -220,54 +226,101 @@ impl WriteType { /// for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock timestamp of the last write - /// corresponding to the writing threads timestamp. - write: VTimestamp, - - /// The identifier of the vector index, corresponding to a thread - /// that performed the last write operation. - write_index: VectorIdx, + /// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need + /// a full `VClock` here, it's always a single thread and nothing synchronizes, so the effective + /// clock is all-0 except for the thread that did the write. + write: (VectorIdx, VTimestamp), /// The type of operation that the write index represents, /// either newly allocated memory, a non-atomic write or /// a deallocation of memory. write_type: WriteType, - /// The vector-clock of the timestamp of the last read operation - /// performed by a thread since the last write operation occurred. - /// It is reset to zero on each write operation. + /// The vector-clock of all non-atomic reads that happened since the last non-atomic write + /// (i.e., we join together the "singleton" clocks corresponding to each read). It is reset to + /// zero on each write operation. read: VClock, - /// Atomic acquire & release sequence tracking clocks. + /// Atomic access, acquire, release sequence tracking clocks. /// For non-atomic memory in the common case this /// value is set to None. atomic_ops: Option<Box<AtomicMemoryCellClocks>>, } +impl AtomicMemoryCellClocks { + fn new(size: Size) -> Self { + AtomicMemoryCellClocks { + read_vector: Default::default(), + write_vector: Default::default(), + sync_vector: Default::default(), + size, + } + } +} + impl MemoryCellClocks { /// Create a new set of clocks representing memory allocated /// at a given vector timestamp and index. fn new(alloc: VTimestamp, alloc_index: VectorIdx) -> Self { MemoryCellClocks { read: VClock::default(), - write: alloc, - write_index: alloc_index, + write: (alloc_index, alloc), write_type: WriteType::Allocate, atomic_ops: None, } } + #[inline] + fn write_was_before(&self, other: &VClock) -> bool { + // This is the same as `self.write() <= other` but + // without actually manifesting a clock for `self.write`. + self.write.1 <= other[self.write.0] + } + + #[inline] + fn write(&self) -> VClock { + VClock::new_with_index(self.write.0, self.write.1) + } + /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { self.atomic_ops.as_deref() } - /// Load or create the internal atomic memory metadata - /// if it does not exist. + /// Load the internal atomic memory cells if they exist. #[inline] - fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { - self.atomic_ops.get_or_insert_with(Default::default) + fn atomic_mut_unwrap(&mut self) -> &mut AtomicMemoryCellClocks { + self.atomic_ops.as_deref_mut().unwrap() + } + + /// Load or create the internal atomic memory metadata if it does not exist. Also ensures we do + /// not do mixed-size atomic accesses, and updates the recorded atomic access size. + fn atomic_access( + &mut self, + thread_clocks: &ThreadClockSet, + size: Size, + ) -> Result<&mut AtomicMemoryCellClocks, DataRace> { + match self.atomic_ops { + Some(ref mut atomic) => { + // We are good if the size is the same or all atomic accesses are before our current time. + if atomic.size == size { + Ok(atomic) + } else if atomic.read_vector <= thread_clocks.clock + && atomic.write_vector <= thread_clocks.clock + { + // This is now the new size that must be used for accesses here. + atomic.size = size; + Ok(atomic) + } else { + Err(DataRace) + } + } + None => { + self.atomic_ops = Some(Box::new(AtomicMemoryCellClocks::new(size))); + Ok(self.atomic_ops.as_mut().unwrap()) + } + } } /// Update memory cell data-race tracking for atomic @@ -277,23 +330,15 @@ impl MemoryCellClocks { &mut self, thread_clocks: &mut ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { - self.atomic_read_detect(thread_clocks, index)?; + self.atomic_read_detect(thread_clocks, index, access_size)?; if let Some(atomic) = self.atomic() { thread_clocks.clock.join(&atomic.sync_vector); } Ok(()) } - /// Checks if the memory cell access is ordered with all prior atomic reads and writes - fn race_free_with_atomic(&self, thread_clocks: &ThreadClockSet) -> bool { - if let Some(atomic) = self.atomic() { - atomic.read_vector <= thread_clocks.clock && atomic.write_vector <= thread_clocks.clock - } else { - true - } - } - /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory. @@ -301,8 +346,9 @@ impl MemoryCellClocks { &mut self, thread_clocks: &mut ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { - self.atomic_read_detect(thread_clocks, index)?; + self.atomic_read_detect(thread_clocks, index, access_size)?; if let Some(atomic) = self.atomic() { thread_clocks.fence_acquire.join(&atomic.sync_vector); } @@ -315,9 +361,10 @@ impl MemoryCellClocks { &mut self, thread_clocks: &ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { - self.atomic_write_detect(thread_clocks, index)?; - let atomic = self.atomic_mut(); + self.atomic_write_detect(thread_clocks, index, access_size)?; + let atomic = self.atomic_mut_unwrap(); // initialized by `atomic_write_detect` atomic.sync_vector.clone_from(&thread_clocks.clock); Ok(()) } @@ -328,14 +375,15 @@ impl MemoryCellClocks { &mut self, thread_clocks: &ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { - self.atomic_write_detect(thread_clocks, index)?; + self.atomic_write_detect(thread_clocks, index, access_size)?; // The handling of release sequences was changed in C++20 and so // the code here is different to the paper since now all relaxed // stores block release sequences. The exception for same-thread // relaxed stores has been removed. - let atomic = self.atomic_mut(); + let atomic = self.atomic_mut_unwrap(); atomic.sync_vector.clone_from(&thread_clocks.fence_release); Ok(()) } @@ -346,9 +394,10 @@ impl MemoryCellClocks { &mut self, thread_clocks: &ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { - self.atomic_write_detect(thread_clocks, index)?; - let atomic = self.atomic_mut(); + self.atomic_write_detect(thread_clocks, index, access_size)?; + let atomic = self.atomic_mut_unwrap(); atomic.sync_vector.join(&thread_clocks.clock); Ok(()) } @@ -359,24 +408,31 @@ impl MemoryCellClocks { &mut self, thread_clocks: &ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { - self.atomic_write_detect(thread_clocks, index)?; - let atomic = self.atomic_mut(); + self.atomic_write_detect(thread_clocks, index, access_size)?; + let atomic = self.atomic_mut_unwrap(); atomic.sync_vector.join(&thread_clocks.fence_release); Ok(()) } - /// Detect data-races with an atomic read, caused by a non-atomic write that does + /// Detect data-races with an atomic read, caused by a non-atomic access that does /// not happen-before the atomic-read. fn atomic_read_detect( &mut self, thread_clocks: &ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, thread_clocks); - let atomic = self.atomic_mut(); + let atomic = self.atomic_access(thread_clocks, access_size)?; atomic.read_vector.set_at_index(&thread_clocks.clock, index); - if self.write <= thread_clocks.clock[self.write_index] { Ok(()) } else { Err(DataRace) } + // Make sure the last non-atomic write and all non-atomic reads were before this access. + if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock { + Ok(()) + } else { + Err(DataRace) + } } /// Detect data-races with an atomic write, either with a non-atomic read or with @@ -385,11 +441,13 @@ impl MemoryCellClocks { &mut self, thread_clocks: &ThreadClockSet, index: VectorIdx, + access_size: Size, ) -> Result<(), DataRace> { log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, thread_clocks); - let atomic = self.atomic_mut(); + let atomic = self.atomic_access(thread_clocks, access_size)?; atomic.write_vector.set_at_index(&thread_clocks.clock, index); - if self.write <= thread_clocks.clock[self.write_index] && self.read <= thread_clocks.clock { + // Make sure the last non-atomic write and all non-atomic reads were before this access. + if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock { Ok(()) } else { Err(DataRace) @@ -408,9 +466,12 @@ impl MemoryCellClocks { if !current_span.is_dummy() { thread_clocks.clock[index].span = current_span; } - if self.write <= thread_clocks.clock[self.write_index] { + if self.write_was_before(&thread_clocks.clock) { let race_free = if let Some(atomic) = self.atomic() { + // We must be ordered-after all atomic accesses, reads and writes. + // This ensures we don't mix atomic and non-atomic accesses. atomic.write_vector <= thread_clocks.clock + && atomic.read_vector <= thread_clocks.clock } else { true }; @@ -434,15 +495,14 @@ impl MemoryCellClocks { if !current_span.is_dummy() { thread_clocks.clock[index].span = current_span; } - if self.write <= thread_clocks.clock[self.write_index] && self.read <= thread_clocks.clock { + if self.write_was_before(&thread_clocks.clock) && self.read <= thread_clocks.clock { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= thread_clocks.clock && atomic.read_vector <= thread_clocks.clock } else { true }; - self.write = thread_clocks.clock[index]; - self.write_index = index; + self.write = (index, thread_clocks.clock[index]); self.write_type = write_type; if race_free { self.read.set_zero_vector(); @@ -473,7 +533,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place))?; - this.validate_overlapping_atomic(place)?; this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) }) @@ -489,7 +548,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(dest)?; - this.validate_overlapping_atomic(dest)?; this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause @@ -512,7 +570,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(place)?; - this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; // Atomics wrap around on overflow. @@ -537,7 +594,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(place)?; - this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(place))?; this.allow_data_races_mut(|this| this.write_scalar(new, place))?; @@ -559,10 +615,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(place)?; - this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; let lt = this.wrapping_binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; + #[rustfmt::skip] // rustfmt makes this unreadable let new_val = if min { if lt { &old } else { &rhs } } else { @@ -598,7 +654,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let this = self.eval_context_mut(); this.atomic_access_check(place)?; - this.validate_overlapping_atomic(place)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. @@ -785,41 +840,54 @@ impl VClockAlloc { mem_clocks: &MemoryCellClocks, action: &str, is_atomic: bool, + access_size: Size, ptr_dbg: Pointer<AllocId>, ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(thread_mgr); + let mut action = Cow::Borrowed(action); + let mut involves_non_atomic = true; let write_clock; - let (other_action, other_thread, other_clock) = if mem_clocks.write - > current_clocks.clock[mem_clocks.write_index] - { - // Convert the write action into the vector clock it - // represents for diagnostic purposes. - write_clock = VClock::new_with_index(mem_clocks.write_index, mem_clocks.write); - (mem_clocks.write_type.get_descriptor(), mem_clocks.write_index, &write_clock) - } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, ¤t_clocks.clock) { - ("Read", idx, &mem_clocks.read) - } else if !is_atomic { - if let Some(atomic) = mem_clocks.atomic() { + let (other_action, other_thread, other_clock) = + // First check the atomic-nonatomic cases. If it looks like multiple + // cases apply, this one should take precedence, else it might look like + // we are reporting races between two non-atomic reads. + if !is_atomic && + let Some(atomic) = mem_clocks.atomic() && + let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) + { + (format!("Atomic Store"), idx, &atomic.write_vector) + } else if !is_atomic && + let Some(atomic) = mem_clocks.atomic() && + let Some(idx) = Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + { + (format!("Atomic Load"), idx, &atomic.read_vector) + // Then check races with non-atomic writes/reads. + } else if mem_clocks.write.1 > current_clocks.clock[mem_clocks.write.0] { + write_clock = mem_clocks.write(); + (mem_clocks.write_type.get_descriptor().to_owned(), mem_clocks.write.0, &write_clock) + } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, ¤t_clocks.clock) { + (format!("Read"), idx, &mem_clocks.read) + // Finally, mixed-size races. + } else if is_atomic && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size { + // This is only a race if we are not synchronized with all atomic accesses, so find + // the one we are not synchronized with. + involves_non_atomic = false; + action = format!("{}-byte (different-size) {action}", access_size.bytes()).into(); if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) - { - ("Atomic Store", idx, &atomic.write_vector) - } else if let Some(idx) = - Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) - { - ("Atomic Load", idx, &atomic.read_vector) - } else { - unreachable!( - "Failed to report data-race for non-atomic operation: no race found" - ) - } + { + (format!("{}-byte Atomic Store", atomic.size.bytes()), idx, &atomic.write_vector) + } else if let Some(idx) = + Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + { + (format!("{}-byte Atomic Load", atomic.size.bytes()), idx, &atomic.read_vector) + } else { + unreachable!( + "Failed to report data-race for mixed-size access: no race found" + ) + } } else { - unreachable!( - "Failed to report data-race for non-atomic operation: no atomic component" - ) - } - } else { - unreachable!("Failed to report data-race for atomic operation") - }; + unreachable!("Failed to report data-race") + }; // Load elaborated thread information about the racing thread actions. let current_thread_info = global.print_thread_metadata(thread_mgr, current_index); @@ -827,6 +895,7 @@ impl VClockAlloc { // Throw the data-race detection. Err(err_machine_stop!(TerminationInfo::DataRace { + involves_non_atomic, ptr: ptr_dbg, op1: RacingOp { action: other_action.to_string(), @@ -841,26 +910,6 @@ impl VClockAlloc { }))? } - /// Detect racing atomic read and writes (not data races) - /// on every byte of the current access range - pub(super) fn race_free_with_atomic( - &self, - range: AllocRange, - global: &GlobalState, - thread_mgr: &ThreadManager<'_, '_>, - ) -> bool { - if global.race_detecting() { - let (_, thread_clocks) = global.current_thread_state(thread_mgr); - let alloc_ranges = self.alloc_ranges.borrow(); - for (_, mem_clocks) in alloc_ranges.iter(range.start, range.size) { - if !mem_clocks.race_free_with_atomic(&thread_clocks) { - return false; - } - } - } - true - } - /// Detect data-races for an unsynchronized read operation, will not perform /// data-race detection if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write @@ -890,7 +939,8 @@ impl VClockAlloc { &machine.threads, mem_clocks, "Read", - false, + /* is_atomic */ false, + access_range.size, Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ); } @@ -929,7 +979,8 @@ impl VClockAlloc { &machine.threads, mem_clocks, write_type.get_descriptor(), - false, + /* is_atomic */ false, + access_range.size, Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ); } @@ -1050,16 +1101,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - this.validate_overlapping_atomic(place)?; this.validate_atomic_op( place, atomic, "Atomic Load", move |memory, clocks, index, atomic| { if atomic == AtomicReadOrd::Relaxed { - memory.load_relaxed(&mut *clocks, index) + memory.load_relaxed(&mut *clocks, index, place.layout.size) } else { - memory.load_acquire(&mut *clocks, index) + memory.load_acquire(&mut *clocks, index, place.layout.size) } }, ) @@ -1073,16 +1123,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic(place)?; this.validate_atomic_op( place, atomic, "Atomic Store", move |memory, clocks, index, atomic| { if atomic == AtomicWriteOrd::Relaxed { - memory.store_relaxed(clocks, index) + memory.store_relaxed(clocks, index, place.layout.size) } else { - memory.store_release(clocks, index) + memory.store_release(clocks, index, place.layout.size) } }, ) @@ -1099,17 +1148,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); - this.validate_overlapping_atomic(place)?; this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { - memory.load_acquire(clocks, index)?; + memory.load_acquire(clocks, index, place.layout.size)?; } else { - memory.load_relaxed(clocks, index)?; + memory.load_relaxed(clocks, index, place.layout.size)?; } if release { - memory.rmw_release(clocks, index) + memory.rmw_release(clocks, index, place.layout.size) } else { - memory.rmw_relaxed(clocks, index) + memory.rmw_relaxed(clocks, index, place.layout.size) } }) } @@ -1160,7 +1208,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { &this.machine.threads, mem_clocks, description, - true, + /* is_atomic */ true, + place.layout.size, Pointer::new( alloc_id, Size::from_bytes(mem_clocks_range.start), diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 6781b1f6dd3..2ff344bb1a3 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -169,14 +169,6 @@ impl StoreBufferAlloc { Self { store_buffers: RefCell::new(RangeObjectMap::new()) } } - /// Checks if the range imperfectly overlaps with existing buffers - /// Used to determine if mixed-size atomic accesses - fn is_overlapping(&self, range: AllocRange) -> bool { - let buffers = self.store_buffers.borrow(); - let access_type = buffers.access_type(range); - matches!(access_type, AccessType::ImperfectlyOverlapping(_)) - } - /// When a non-atomic access happens on a location that has been atomically accessed /// before without data race, we can determine that the non-atomic access fully happens /// after all the prior atomic accesses so the location no longer needs to exhibit @@ -190,6 +182,8 @@ impl StoreBufferAlloc { buffers.remove_from_pos(pos); } AccessType::ImperfectlyOverlapping(pos_range) => { + // We rely on the data-race check making sure this is synchronized. + // Therefore we can forget about the old data here. buffers.remove_pos_range(pos_range); } AccessType::Empty(_) => { @@ -215,7 +209,7 @@ impl StoreBufferAlloc { pos } AccessType::ImperfectlyOverlapping(pos_range) => { - // Once we reach here we would've already checked that this access is not racy + // Once we reach here we would've already checked that this access is not racy. let mut buffers = self.store_buffers.borrow_mut(); buffers.remove_pos_range(pos_range.clone()); buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init)); @@ -240,6 +234,7 @@ impl StoreBufferAlloc { pos } AccessType::ImperfectlyOverlapping(pos_range) => { + // Once we reach here we would've already checked that this access is not racy. buffers.remove_pos_range(pos_range.clone()); buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init)); pos_range.start @@ -473,37 +468,6 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous - // atomic read or write. If it does, then we require it to be ordered (non-racy) with all previous atomic - // accesses on all the bytes in range - fn validate_overlapping_atomic( - &self, - place: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; - if let crate::AllocExtra { - weak_memory: Some(alloc_buffers), - data_race: Some(alloc_clocks), - .. - } = this.get_alloc_extra(alloc_id)? - { - let range = alloc_range(base_offset, place.layout.size); - if alloc_buffers.is_overlapping(range) - && !alloc_clocks.race_free_with_atomic( - range, - this.machine.data_race.as_ref().unwrap(), - &this.machine.threads, - ) - { - throw_unsup_format!( - "racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation" - ); - } - } - Ok(()) - } - fn buffered_atomic_rmw( &mut self, new_val: Scalar<Provenance>, diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index cb095f94f35..9b8f263b7ce 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -43,9 +43,10 @@ pub enum TerminationInfo { span: SpanData, }, DataRace { + involves_non_atomic: bool, + ptr: Pointer, op1: RacingOp, op2: RacingOp, - ptr: Pointer, }, } @@ -74,11 +75,15 @@ impl fmt::Display for TerminationInfo { write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",), - DataRace { ptr, op1, op2 } => + DataRace { involves_non_atomic, ptr, op1, op2 } => write!( f, - "Data race detected between (1) {} on {} and (2) {} on {} at {ptr:?}. (2) just happened here", - op1.action, op1.thread_info, op2.action, op2.thread_info + "{} detected between (1) {} on {} and (2) {} on {} at {ptr:?}. (2) just happened here", + if *involves_non_atomic { "Data race" } else { "Race condition" }, + op1.action, + op1.thread_info, + op2.action, + op2.thread_info ), } } diff --git a/src/tools/miri/src/intptrcast.rs b/src/tools/miri/src/intptrcast.rs index ab6a256f714..9966ee3fd91 100644 --- a/src/tools/miri/src/intptrcast.rs +++ b/src/tools/miri/src/intptrcast.rs @@ -27,9 +27,9 @@ pub type GlobalState = RefCell<GlobalStateInner>; #[derive(Clone, Debug)] pub struct GlobalStateInner { /// This is used as a map between the address of each allocation and its `AllocId`. It is always - /// sorted. We cannot use a `HashMap` since we can be given an address that is offset from the - /// base address, and we need to find the `AllocId` it belongs to. - /// This is not the *full* inverse of `base_addr`; dead allocations have been removed. + /// sorted by address. We cannot use a `HashMap` since we can be given an address that is offset + /// from the base address, and we need to find the `AllocId` it belongs to. This is not the + /// *full* inverse of `base_addr`; dead allocations have been removed. int_to_ptr_map: Vec<(u64, AllocId)>, /// The base address for each allocation. We cannot put that into /// `AllocExtra` because function pointers also have a base address, and @@ -285,7 +285,12 @@ impl GlobalStateInner { // However, we *can* remove it from `int_to_ptr_map`, since any wildcard pointers that exist // can no longer actually be accessing that address. This ensures `alloc_id_from_addr` never // returns a dead allocation. - self.int_to_ptr_map.retain(|&(_, id)| id != dead_id); + // To avoid a linear scan we first look up the address in `base_addr`, and then find it in + // `int_to_ptr_map`. + let addr = *self.base_addr.get(&dead_id).unwrap(); + let pos = self.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr).unwrap(); + let removed = self.int_to_ptr_map.remove(pos); + assert_eq!(removed, (addr, dead_id)); // double-check that we removed the right thing // We can also remove it from `exposed`, since this allocation can anyway not be returned by // `alloc_id_from_addr` any more. self.exposed.remove(&dead_id); diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index d6d0483f5e3..4918698c6b2 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -51,13 +51,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "macos" => { absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")]; relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")]; - // Some clocks only seem to exist in the aarch64 version of the target. - if this.tcx.sess.target.arch == "aarch64" { - // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but - // that's not really something a program running inside Miri can tell, anyway. - // We need to support it because std uses it. - relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW")); - } + // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but + // that's not really something a program running inside Miri can tell, anyway. + // We need to support it because std uses it. + relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW")); } target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"), } @@ -68,7 +65,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } else if relative_clocks.contains(&clk_id) { this.machine.clock.now().duration_since(this.machine.clock.anchor()) } else { - // Unsupported clock. let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; return Ok(Scalar::from_i32(-1)); diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index c887e18e97e..bddc30b8379 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -363,7 +363,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_target_isize(hModule)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; - if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name) { + if let Ok(name) = str::from_utf8(name) + && is_dyn_sym(name) + { let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); this.write_pointer(ptr, dest)?; } else { diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs new file mode 100644 index 00000000000..d530ed2f5a4 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.rs @@ -0,0 +1,25 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::thread; + +fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { + unsafe { std::mem::transmute(a) } +} + +// We can't allow mixed-size accesses; they are not possible in C++ and even +// Intel says you shouldn't do it. +fn main() { + let a = AtomicU16::new(0); + let a16 = &a; + let a8 = convert(a16); + + thread::scope(|s| { + s.spawn(|| { + a16.load(Ordering::SeqCst); + }); + s.spawn(|| { + a8[0].load(Ordering::SeqCst); + //~^ ERROR: Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` + }); + }); +} diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr new file mode 100644 index 00000000000..06944a11db8 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + --> $DIR/mixed_size_read.rs:LL:CC + | +LL | a8[0].load(Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte Atomic Load on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> $DIR/mixed_size_read.rs:LL:CC + | +LL | a16.load(Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): + = note: inside closure at $DIR/mixed_size_read.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs new file mode 100644 index 00000000000..df3551612c3 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.rs @@ -0,0 +1,25 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; +use std::thread; + +fn convert(a: &AtomicU16) -> &[AtomicU8; 2] { + unsafe { std::mem::transmute(a) } +} + +// We can't allow mixed-size accesses; they are not possible in C++ and even +// Intel says you shouldn't do it. +fn main() { + let a = AtomicU16::new(0); + let a16 = &a; + let a8 = convert(a16); + + thread::scope(|s| { + s.spawn(|| { + a16.store(1, Ordering::SeqCst); + }); + s.spawn(|| { + a8[0].store(1, Ordering::SeqCst); + //~^ ERROR: Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` + }); + }); +} diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr new file mode 100644 index 00000000000..4bb949175bf --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here + --> $DIR/mixed_size_write.rs:LL:CC + | +LL | a8[0].store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 2-byte Atomic Store on thread `<unnamed>` and (2) 1-byte (different-size) Atomic Store on thread `<unnamed>` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> $DIR/mixed_size_write.rs:LL:CC + | +LL | a16.store(1, Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): + = note: inside closure at $DIR/mixed_size_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.rs b/src/tools/miri/tests/fail/data_race/read_read_race1.rs new file mode 100644 index 00000000000..eebfbc74d40 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/read_read_race1.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 +use std::sync::atomic::{AtomicU16, Ordering}; +use std::thread; + +// Make sure races between atomic and non-atomic reads are detected. +// This seems harmless but C++ does not allow them, so we can't allow them for now either. +// This test coverse the case where the non-atomic access come first. +fn main() { + let a = AtomicU16::new(0); + + thread::scope(|s| { + s.spawn(|| { + let ptr = &a as *const AtomicU16 as *mut u16; + unsafe { ptr.read() }; + }); + s.spawn(|| { + thread::yield_now(); + + // We also put a non-atomic access here, but that should *not* be reported. + let ptr = &a as *const AtomicU16 as *mut u16; + unsafe { ptr.read() }; + // Then do the atomic access. + a.load(Ordering::SeqCst); + //~^ ERROR: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` + }); + }); +} diff --git a/src/tools/miri/tests/fail/data_race/read_read_race1.stderr b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr new file mode 100644 index 00000000000..158b438bd0d --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/read_read_race1.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + --> $DIR/read_read_race1.rs:LL:CC + | +LL | a.load(Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between (1) Read on thread `<unnamed>` and (2) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> $DIR/read_read_race1.rs:LL:CC + | +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): + = note: inside closure at $DIR/read_read_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.rs b/src/tools/miri/tests/fail/data_race/read_read_race2.rs new file mode 100644 index 00000000000..230b429e287 --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/read_read_race2.rs @@ -0,0 +1,27 @@ +//@compile-flags: -Zmiri-preemption-rate=0.0 +use std::sync::atomic::{AtomicU16, Ordering}; +use std::thread; + +// Make sure races between atomic and non-atomic reads are detected. +// This seems harmless but C++ does not allow them, so we can't allow them for now either. +// This test coverse the case where the atomic access come first. +fn main() { + let a = AtomicU16::new(0); + + thread::scope(|s| { + s.spawn(|| { + // We also put a non-atomic access here, but that should *not* be reported. + let ptr = &a as *const AtomicU16 as *mut u16; + unsafe { ptr.read() }; + // Then do the atomic access. + a.load(Ordering::SeqCst); + }); + s.spawn(|| { + thread::yield_now(); + + let ptr = &a as *const AtomicU16 as *mut u16; + unsafe { ptr.read() }; + //~^ ERROR: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` + }); + }); +} diff --git a/src/tools/miri/tests/fail/data_race/read_read_race2.stderr b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr new file mode 100644 index 00000000000..7f867b9edbb --- /dev/null +++ b/src/tools/miri/tests/fail/data_race/read_read_race2.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + --> $DIR/read_read_race2.rs:LL:CC + | +LL | unsafe { ptr.read() }; + | ^^^^^^^^^^ Data race detected between (1) Atomic Load on thread `<unnamed>` and (2) Read on thread `<unnamed>` at ALLOC. (2) just happened here + | +help: and (1) occurred earlier here + --> $DIR/read_read_race2.rs:LL:CC + | +LL | a.load(Ordering::SeqCst); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): + = note: inside closure at $DIR/read_read_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs index 7bbb7f9fe7c..36dc0d5f3f7 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.rs @@ -19,7 +19,7 @@ fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { // Wine's SRWLock implementation does this, which is definitely undefined in C++ memory model // https://github.com/wine-mirror/wine/blob/303f8042f9db508adaca02ef21f8de4992cb9c03/dlls/ntdll/sync.c#L543-L566 -// Though it probably works just fine on x86 +// It probably works just fine on x86, but Intel does document this as "don't do it!" pub fn main() { let x = static_atomic_u32(0); let j1 = spawn(move || { @@ -31,7 +31,7 @@ pub fn main() { let x_split = split_u32_ptr(x_ptr); unsafe { let hi = ptr::addr_of!((*x_split)[0]); - std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: different-size } }); diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr index dda22ac9ce2..055585ab96f 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size.stderr @@ -1,11 +1,17 @@ -error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation +error: Undefined Behavior: Race condition detected between (1) 4-byte Atomic Store on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/racing_mixed_size.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte Atomic Store on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: BACKTRACE: +help: and (1) occurred earlier here + --> $DIR/racing_mixed_size.rs:LL:CC + | +LL | x.store(1, Relaxed); + | ^^^^^^^^^^^^^^^^^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs index 73178980b7e..5cd14540ca3 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -16,7 +16,7 @@ fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { // Racing mixed size reads may cause two loads to read-from // the same store but observe different values, which doesn't make -// sense under the formal model so we forbade this. +// sense under the formal model so we forbid this. pub fn main() { let x = static_atomic(0); @@ -29,7 +29,7 @@ pub fn main() { let x_split = split_u32_ptr(x_ptr); unsafe { let hi = x_split as *const u16 as *const AtomicU16; - (*hi).load(Relaxed); //~ ERROR: imperfectly overlapping + (*hi).load(Relaxed); //~ ERROR: different-size } }); diff --git a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr index 59fa5c74102..2eefa0a87b4 100644 --- a/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/src/tools/miri/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,11 +1,17 @@ -error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation +error: Undefined Behavior: Race condition detected between (1) 4-byte Atomic Load on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here --> $DIR/racing_mixed_size_read.rs:LL:CC | LL | (*hi).load(Relaxed); - | ^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation + | ^^^^^^^^^^^^^^^^^^^ Race condition detected between (1) 4-byte Atomic Load on thread `<unnamed>` and (2) 2-byte (different-size) Atomic Load on thread `<unnamed>` at ALLOC. (2) just happened here | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: BACKTRACE: +help: and (1) occurred earlier here + --> $DIR/racing_mixed_size_read.rs:LL:CC + | +LL | x.load(Relaxed); + | ^^^^^^^^^^^^^^^ + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE (of the first span): = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs index a456528ec20..648c004c97c 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs @@ -2,7 +2,7 @@ //@compile-flags: -Zmiri-disable-isolation use std::mem::MaybeUninit; -use std::ptr; +use std::ptr::{self, addr_of}; use std::sync::atomic::AtomicI32; use std::sync::atomic::Ordering; use std::thread; @@ -13,7 +13,7 @@ fn wake_nobody() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1), 0); + assert_eq!(libc::syscall(libc::SYS_futex, addr_of!(futex), libc::FUTEX_WAKE, 1), 0); } // Same, but without omitting the unused arguments. @@ -21,7 +21,7 @@ fn wake_nobody() { assert_eq!( libc::syscall( libc::SYS_futex, - &futex as *const i32, + addr_of!(futex), libc::FUTEX_WAKE, 1, ptr::null::<libc::timespec>(), @@ -52,7 +52,7 @@ fn wait_wrong_val() { assert_eq!( libc::syscall( libc::SYS_futex, - &futex as *const i32, + addr_of!(futex), libc::FUTEX_WAIT, 456, ptr::null::<libc::timespec>(), @@ -73,7 +73,7 @@ fn wait_timeout() { assert_eq!( libc::syscall( libc::SYS_futex, - &futex as *const i32, + addr_of!(futex), libc::FUTEX_WAIT, 123, &libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 }, @@ -110,7 +110,7 @@ fn wait_absolute_timeout() { assert_eq!( libc::syscall( libc::SYS_futex, - &futex as *const i32, + addr_of!(futex), libc::FUTEX_WAIT_BITSET, 123, &timeout, @@ -136,7 +136,7 @@ fn wait_wake() { assert_eq!( libc::syscall( libc::SYS_futex, - &FUTEX as *const i32, + addr_of!(FUTEX), libc::FUTEX_WAKE, 10, // Wake up at most 10 threads. ), @@ -149,7 +149,7 @@ fn wait_wake() { assert_eq!( libc::syscall( libc::SYS_futex, - &FUTEX as *const i32, + addr_of!(FUTEX), libc::FUTEX_WAIT, 0, ptr::null::<libc::timespec>(), @@ -173,7 +173,7 @@ fn wait_wake_bitset() { assert_eq!( libc::syscall( libc::SYS_futex, - &FUTEX as *const i32, + addr_of!(FUTEX), libc::FUTEX_WAKE_BITSET, 10, // Wake up at most 10 threads. ptr::null::<libc::timespec>(), @@ -188,7 +188,7 @@ fn wait_wake_bitset() { assert_eq!( libc::syscall( libc::SYS_futex, - &FUTEX as *const i32, + addr_of!(FUTEX), libc::FUTEX_WAKE_BITSET, 10, // Wake up at most 10 threads. ptr::null::<libc::timespec>(), @@ -204,7 +204,7 @@ fn wait_wake_bitset() { assert_eq!( libc::syscall( libc::SYS_futex, - &FUTEX as *const i32, + addr_of!(FUTEX), libc::FUTEX_WAIT_BITSET, 0, ptr::null::<libc::timespec>(), @@ -244,7 +244,7 @@ fn concurrent_wait_wake() { unsafe { let ret = libc::syscall( libc::SYS_futex, - &FUTEX as *const AtomicI32, + addr_of!(FUTEX), libc::FUTEX_WAIT, HELD, ptr::null::<libc::timespec>(), @@ -267,7 +267,7 @@ fn concurrent_wait_wake() { FUTEX.store(FREE, Ordering::Relaxed); unsafe { DATA = 1; - libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1); + libc::syscall(libc::SYS_futex, addr_of!(FUTEX), libc::FUTEX_WAKE, 1); } t.join().unwrap(); diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs index 82c49cfb17c..40d3fa19e53 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs @@ -186,7 +186,7 @@ fn test_clocks() { unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); } - #[cfg(all(target_os = "macos", target_arch = "aarch64"))] + #[cfg(target_os = "macos")] { let is_error = unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); diff --git a/src/tools/miri/tests/pass/concurrency/simple.rs b/src/tools/miri/tests/pass/concurrency/simple.rs index 556e0a24769..ec549a998ba 100644 --- a/src/tools/miri/tests/pass/concurrency/simple.rs +++ b/src/tools/miri/tests/pass/concurrency/simple.rs @@ -62,6 +62,23 @@ fn panic_named() { .unwrap_err(); } +// This is not a data race! +fn shared_readonly() { + use std::sync::Arc; + + let x = Arc::new(42i32); + let h = thread::spawn({ + let x = Arc::clone(&x); + move || { + assert_eq!(*x, 42); + } + }); + + assert_eq!(*x, 42); + + h.join().unwrap(); +} + fn main() { create_and_detach(); create_and_join(); @@ -71,6 +88,7 @@ fn main() { create_nested_and_join(); create_move_in(); create_move_out(); + shared_readonly(); panic(); panic_named(); } diff --git a/src/tools/miri/tests/pass/intrinsics-math.rs b/src/tools/miri/tests/pass/intrinsics-math.rs index 5f7730a3e86..589864f4f4b 100644 --- a/src/tools/miri/tests/pass/intrinsics-math.rs +++ b/src/tools/miri/tests/pass/intrinsics-math.rs @@ -125,9 +125,8 @@ pub fn main() { assert_approx_eq!(5.0f32.gamma(), 24.0); assert_approx_eq!(5.0f64.gamma(), 24.0); - // These fail even on the host, precision seems to be terrible. - //assert_approx_eq!(-0.5f32.gamma(), -2.0 * f32::consts::PI.sqrt()); - //assert_approx_eq!(-0.5f64.gamma(), -2.0 * f64::consts::PI.sqrt()); + assert_approx_eq!((-0.5f32).gamma(), (-2.0) * f32::consts::PI.sqrt()); + assert_approx_eq!((-0.5f64).gamma(), (-2.0) * f64::consts::PI.sqrt()); assert_eq!(2.0f32.ln_gamma(), (0.0, 1)); assert_eq!(2.0f64.ln_gamma(), (0.0, 1)); diff --git a/src/tools/miri/tests/pass/weak_memory/extra_cpp_unsafe.rs b/src/tools/miri/tests/pass/weak_memory/extra_cpp_unsafe.rs deleted file mode 100644 index 48b15191b38..00000000000 --- a/src/tools/miri/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ /dev/null @@ -1,40 +0,0 @@ -//@compile-flags: -Zmiri-ignore-leaks - -// Tests operations not performable through C++'s atomic API -// but doable in unsafe Rust which we think *should* be fine. -// Nonetheless they may be determined as inconsistent with the -// memory model in the future. - -#![feature(atomic_from_mut)] - -use std::sync::atomic::AtomicU32; -use std::sync::atomic::Ordering::*; -use std::thread::spawn; - -fn static_atomic(val: u32) -> &'static AtomicU32 { - let ret = Box::leak(Box::new(AtomicU32::new(val))); - ret -} - -// We allow perfectly overlapping non-atomic and atomic reads to race -fn racing_mixed_atomicity_read() { - let x = static_atomic(0); - x.store(42, Relaxed); - - let j1 = spawn(move || x.load(Relaxed)); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { x_ptr.read() } - }); - - let r1 = j1.join().unwrap(); - let r2 = j2.join().unwrap(); - - assert_eq!(r1, 42); - assert_eq!(r2, 42); -} - -pub fn main() { - racing_mixed_atomicity_read(); -} diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 3c33cfe985d..8a8f98a5eda 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -24,10 +24,11 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> { let host_triple = env.host_triple(); let version = find_dist_version(&dist_dir)?; - // Extract rustc, libstd and src archives to create the optimized sysroot + // Extract rustc, libstd, cargo and src archives to create the optimized sysroot let rustc_dir = extract_dist_dir(&format!("rustc-{version}-{host_triple}"))?.join("rustc"); let libstd_dir = extract_dist_dir(&format!("rust-std-{version}-{host_triple}"))? .join(format!("rust-std-{host_triple}")); + let cargo_dir = extract_dist_dir(&format!("cargo-{version}-{host_triple}"))?.join("cargo"); let extracted_src_dir = extract_dist_dir(&format!("rust-src-{version}"))?.join("rust-src"); // We need to manually copy libstd to the extracted rustc sysroot @@ -46,6 +47,8 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> { let rustc_path = rustc_dir.join("bin").join(format!("rustc{}", executable_extension())); assert!(rustc_path.is_file()); + let cargo_path = cargo_dir.join("bin").join(format!("cargo{}", executable_extension())); + assert!(cargo_path.is_file()); // Specify path to a LLVM config so that LLVM is not rebuilt. // It doesn't really matter which LLVM config we choose, because no sysroot will be compiled. @@ -62,11 +65,13 @@ change-id = 115898 [build] rustc = "{rustc}" +cargo = "{cargo}" [target.{host_triple}] llvm-config = "{llvm_config}" "#, rustc = rustc_path.to_string().replace('\\', "/"), + cargo = cargo_path.to_string().replace('\\', "/"), llvm_config = llvm_config.to_string().replace('\\', "/") ); log::info!("Using following `config.toml` for running tests:\n{config_content}"); diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff index ed47baa67da..313e5dddbbb 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff @@ -41,7 +41,8 @@ + debug ((f: (bool, bool, u32)).2: u32) => const 123_u32; let _10: std::option::Option<u16>; scope 7 { - debug o => _10; +- debug o => _10; ++ debug o => const Option::<u16>::Some(99_u16); let _17: u32; let _18: u32; scope 8 { @@ -81,7 +82,7 @@ _15 = const false; _16 = const 123_u32; StorageLive(_10); - _10 = Option::<u16>::Some(const 99_u16); + _10 = const Option::<u16>::Some(99_u16); _17 = const 32_u32; _18 = const 32_u32; StorageLive(_11); @@ -97,3 +98,7 @@ } } + ALLOC0 (size: 4, align: 2) { + 01 00 63 00 │ ..c. + } + diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff index 2f1a70f32d0..4569ffe483b 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff @@ -43,7 +43,7 @@ - _6 = CheckedAdd(_4, _5); - assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind unreachable]; + _5 = const 2_i32; -+ _6 = CheckedAdd(const 1_i32, const 2_i32); ++ _6 = const (3_i32, false); + assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind unreachable]; } @@ -60,7 +60,7 @@ - _10 = CheckedAdd(_9, const 1_i32); - assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind unreachable]; + _9 = const i32::MAX; -+ _10 = CheckedAdd(const i32::MAX, const 1_i32); ++ _10 = const (i32::MIN, true); + assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind unreachable]; } @@ -76,5 +76,13 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 00 00 00 80 01 __ __ __ │ .....â–‘â–‘â–‘ ++ } ++ ++ ALLOC1 (size: 8, align: 4) { ++ 03 00 00 00 00 __ __ __ │ .....â–‘â–‘â–‘ } diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff index 0d8a9aca3d8..aa7e404eb9f 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff @@ -43,7 +43,7 @@ - _6 = CheckedAdd(_4, _5); - assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind continue]; + _5 = const 2_i32; -+ _6 = CheckedAdd(const 1_i32, const 2_i32); ++ _6 = const (3_i32, false); + assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind continue]; } @@ -60,7 +60,7 @@ - _10 = CheckedAdd(_9, const 1_i32); - assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind continue]; + _9 = const i32::MAX; -+ _10 = CheckedAdd(const i32::MAX, const 1_i32); ++ _10 = const (i32::MIN, true); + assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind continue]; } @@ -76,5 +76,13 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 00 00 00 80 01 __ __ __ │ .....â–‘â–‘â–‘ ++ } ++ ++ ALLOC1 (size: 8, align: 4) { ++ 03 00 00 00 00 __ __ __ │ .....â–‘â–‘â–‘ } diff --git a/tests/mir-opt/dataflow-const-prop/checked.rs b/tests/mir-opt/dataflow-const-prop/checked.rs index b41ac0b3d2a..f7fac8890a0 100644 --- a/tests/mir-opt/dataflow-const-prop/checked.rs +++ b/tests/mir-opt/dataflow-const-prop/checked.rs @@ -1,7 +1,7 @@ // skip-filecheck -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // unit-test: DataflowConstProp // compile-flags: -Coverflow-checks=on +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY // EMIT_MIR checked.main.DataflowConstProp.diff #[allow(arithmetic_overflow)] diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff index 3946e7c7d96..798b0c041b4 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.32bit.diff @@ -23,7 +23,8 @@ bb0: { StorageLive(_1); - _1 = E::V1(const 0_i32); +- _1 = E::V1(const 0_i32); ++ _1 = const E::V1(0_i32); StorageLive(_2); - _3 = discriminant(_1); - switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; @@ -59,5 +60,9 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 00 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff index 3946e7c7d96..798b0c041b4 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.simple.DataflowConstProp.64bit.diff @@ -23,7 +23,8 @@ bb0: { StorageLive(_1); - _1 = E::V1(const 0_i32); +- _1 = E::V1(const 0_i32); ++ _1 = const E::V1(0_i32); StorageLive(_2); - _3 = discriminant(_1); - switchInt(move _3) -> [0: bb3, 1: bb1, otherwise: bb2]; @@ -59,5 +60,9 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 00 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff index 1348b279330..d502b198239 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff @@ -44,7 +44,8 @@ StorageLive(_1); StorageLive(_2); _2 = const {ALLOC1: &E}; - _1 = (*_2); +- _1 = (*_2); ++ _1 = const E::V1(0_i32); StorageDead(_2); StorageLive(_3); - _4 = discriminant(_1); @@ -110,6 +111,10 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC3 (size: 8, align: 4) { ++ 00 00 00 00 00 00 00 00 │ ........ } ALLOC2 (static: RC, size: 4, align: 4) { diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff index 66929e886d3..5d69572b507 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff @@ -44,7 +44,8 @@ StorageLive(_1); StorageLive(_2); _2 = const {ALLOC1: &E}; - _1 = (*_2); +- _1 = (*_2); ++ _1 = const E::V1(0_i32); StorageDead(_2); StorageLive(_3); - _4 = discriminant(_1); @@ -110,6 +111,10 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC3 (size: 8, align: 4) { ++ 00 00 00 00 00 00 00 00 │ ........ } ALLOC2 (static: RC, size: 8, align: 8) { diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff index 87bb1454c96..2d4591ea2d3 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff @@ -23,7 +23,7 @@ StorageLive(_4); - _4 = CheckedAdd(_2, _3); - assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable]; -+ _4 = CheckedAdd(const u8::MAX, const 1_u8); ++ _4 = const (0_u8, true); + assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable]; } @@ -37,5 +37,9 @@ _0 = const (); return; } ++ } ++ ++ ALLOC0 (size: 2, align: 1) { ++ 00 01 │ .. } diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff index b2f13640a4c..e99ac782a2f 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff @@ -23,7 +23,7 @@ StorageLive(_4); - _4 = CheckedAdd(_2, _3); - assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue]; -+ _4 = CheckedAdd(const u8::MAX, const 1_u8); ++ _4 = const (0_u8, true); + assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue]; } @@ -37,5 +37,9 @@ _0 = const (); return; } ++ } ++ ++ ALLOC0 (size: 2, align: 1) { ++ 00 01 │ .. } diff --git a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff index 4b1a8d932c6..98bd40ab2c3 100644 --- a/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/repr_transparent.main.DataflowConstProp.diff @@ -17,7 +17,8 @@ bb0: { StorageLive(_1); - _1 = I32(const 0_i32); +- _1 = I32(const 0_i32); ++ _1 = const I32(0_i32); StorageLive(_2); StorageLive(_3); StorageLive(_4); @@ -31,12 +32,20 @@ StorageDead(_5); StorageDead(_4); - _2 = I32(move _3); -+ _2 = I32(const 0_i32); ++ _2 = const I32(0_i32); StorageDead(_3); _0 = const (); StorageDead(_2); StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 4, align: 4) { ++ 00 00 00 00 │ .... ++ } ++ ++ ALLOC1 (size: 4, align: 4) { ++ 00 00 00 00 │ .... } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index e80f31ca934..8499d0a89c3 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -7,13 +7,24 @@ let mut _3: i32; let mut _5: i32; let mut _6: i32; - let mut _11: BigStruct; - let mut _16: &&BigStruct; - let mut _17: &BigStruct; - let mut _18: &BigStruct; - let mut _19: &BigStruct; - let mut _20: &BigStruct; - let mut _21: &BigStruct; + let mut _10: SmallStruct; + let mut _14: &&SmallStruct; + let mut _16: f32; + let mut _17: std::option::Option<S>; + let mut _18: &[f32]; + let mut _22: BigStruct; + let mut _26: &&BigStruct; + let mut _28: f32; + let mut _29: std::option::Option<S>; + let mut _30: &[f32]; + let mut _31: &SmallStruct; + let mut _32: &SmallStruct; + let mut _33: &SmallStruct; + let mut _34: &SmallStruct; + let mut _35: &BigStruct; + let mut _36: &BigStruct; + let mut _37: &BigStruct; + let mut _38: &BigStruct; scope 1 { debug s => _1; let _2: i32; @@ -22,24 +33,44 @@ let _4: i32; scope 3 { debug b => _4; - let _7: S; - let _8: u8; - let _9: f32; - let _10: S; + let _7: f32; + let _8: std::option::Option<S>; + let _9: &[f32]; scope 4 { debug a => _7; debug b => _8; debug c => _9; - debug d => _10; - let _12: S; - let _13: u8; - let _14: f32; - let _15: S; + let _11: f32; + let _12: std::option::Option<S>; + let _13: &[f32]; scope 5 { - debug a => _12; - debug b => _13; - debug c => _14; - debug d => _15; + debug a => _11; + debug b => _12; + debug c => _13; + let _15: SmallStruct; + scope 6 { + debug ss => _15; + let _19: f32; + let _20: std::option::Option<S>; + let _21: &[f32]; + scope 7 { + debug a => _19; + debug b => _20; + debug c => _21; + let _23: f32; + let _24: std::option::Option<S>; + let _25: &[f32]; + scope 8 { + debug a => _23; + debug b => _24; + debug c => _25; + let _27: BigStruct; + scope 9 { + debug bs => _27; + } + } + } + } } } } @@ -48,7 +79,8 @@ bb0: { StorageLive(_1); - _1 = S(const 1_i32); +- _1 = S(const 1_i32); ++ _1 = const S(1_i32); StorageLive(_2); StorageLive(_3); - _3 = (_1.0: i32); @@ -68,47 +100,95 @@ + _4 = const 6_i32; StorageDead(_6); StorageDead(_5); - StorageLive(_11); - _11 = const _; + StorageLive(_10); + _10 = const _; StorageLive(_7); -- _7 = (_11.0: S); -+ _7 = const S(1_i32); +- _7 = (_10.0: f32); ++ _7 = const 4f32; StorageLive(_8); -- _8 = (_11.1: u8); -+ _8 = const 5_u8; +- _8 = (_10.1: std::option::Option<S>); ++ _8 = const Option::<S>::Some(S(1_i32)); StorageLive(_9); -- _9 = (_11.2: f32); -+ _9 = const 7f32; - StorageLive(_10); -- _10 = (_11.3: S); -+ _10 = const S(13_i32); - StorageDead(_11); - StorageLive(_16); - _16 = const {ALLOC1: &&BigStruct}; - _17 = deref_copy (*_16); + _9 = (_10.2: &[f32]); + StorageDead(_10); + StorageLive(_14); + _14 = const {ALLOC4: &&SmallStruct}; + _31 = deref_copy (*_14); + StorageLive(_11); + _32 = deref_copy (*_14); +- _11 = ((*_32).0: f32); ++ _11 = const 9f32; StorageLive(_12); - _18 = deref_copy (*_16); -- _12 = ((*_18).0: S); -+ _12 = const S(1_i32); + _33 = deref_copy (*_14); + _12 = ((*_33).1: std::option::Option<S>); StorageLive(_13); - _19 = deref_copy (*_16); -- _13 = ((*_19).1: u8); -+ _13 = const 5_u8; - StorageLive(_14); - _20 = deref_copy (*_16); -- _14 = ((*_20).2: f32); -+ _14 = const 7f32; + _34 = deref_copy (*_14); + _13 = ((*_34).2: &[f32]); + StorageDead(_14); StorageLive(_15); - _21 = deref_copy (*_16); -- _15 = ((*_21).3: S); -+ _15 = const S(13_i32); + StorageLive(_16); +- _16 = _11; ++ _16 = const 9f32; + StorageLive(_17); + _17 = _12; + StorageLive(_18); + _18 = _13; +- _15 = SmallStruct(move _16, move _17, move _18); ++ _15 = SmallStruct(const 9f32, move _17, move _18); + StorageDead(_18); + StorageDead(_17); StorageDead(_16); + StorageLive(_22); + _22 = const _; + StorageLive(_19); +- _19 = (_22.0: f32); ++ _19 = const 25f32; + StorageLive(_20); + _20 = (_22.1: std::option::Option<S>); + StorageLive(_21); + _21 = (_22.2: &[f32]); + StorageDead(_22); + StorageLive(_26); + _26 = const {ALLOC5: &&BigStruct}; + _35 = deref_copy (*_26); + StorageLive(_23); + _36 = deref_copy (*_26); +- _23 = ((*_36).0: f32); ++ _23 = const 82f32; + StorageLive(_24); + _37 = deref_copy (*_26); +- _24 = ((*_37).1: std::option::Option<S>); ++ _24 = const Option::<S>::Some(S(35_i32)); + StorageLive(_25); + _38 = deref_copy (*_26); + _25 = ((*_38).2: &[f32]); + StorageDead(_26); + StorageLive(_27); + StorageLive(_28); +- _28 = _23; ++ _28 = const 82f32; + StorageLive(_29); +- _29 = _24; ++ _29 = const Option::<S>::Some(S(35_i32)); + StorageLive(_30); + _30 = _25; +- _27 = BigStruct(move _28, move _29, move _30); ++ _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30); + StorageDead(_30); + StorageDead(_29); + StorageDead(_28); _0 = const (); + StorageDead(_27); + StorageDead(_25); + StorageDead(_24); + StorageDead(_23); + StorageDead(_21); + StorageDead(_20); + StorageDead(_19); StorageDead(_15); - StorageDead(_14); StorageDead(_13); StorageDead(_12); - StorageDead(_10); + StorageDead(_11); StorageDead(_9); StorageDead(_8); StorageDead(_7); @@ -117,13 +197,51 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC6 (size: 8, align: 4) { ++ 01 00 00 00 23 00 00 00 │ ....#... ++ } ++ ++ ALLOC7 (size: 8, align: 4) { ++ 01 00 00 00 23 00 00 00 │ ....#... ++ } ++ ++ ALLOC8 (size: 8, align: 4) { ++ 01 00 00 00 23 00 00 00 │ ....#... ++ } ++ ++ ALLOC9 (size: 8, align: 4) { ++ 01 00 00 00 01 00 00 00 │ ........ ++ } ++ ++ ALLOC10 (size: 4, align: 4) { ++ 01 00 00 00 │ .... } - ALLOC1 (static: STAT, size: 4, align: 4) { + ALLOC5 (static: BIG_STAT, size: 4, align: 4) { ╾ALLOC0╼ │ ╾──╼ } - ALLOC0 (size: 16, align: 4) { - 01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....â–‘â–‘â–‘ + ALLOC0 (size: 20, align: 4) { + 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼.... + 0x10 │ 00 00 a4 42 │ ...B + } + + ALLOC1 (size: 8, align: 4) { + 00 00 34 42 00 00 90 42 │ ..4B...B + } + + ALLOC4 (static: SMALL_STAT, size: 4, align: 4) { + ╾ALLOC2╼ │ ╾──╼ + } + + ALLOC2 (size: 20, align: 4) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼.... + 0x10 │ 00 00 10 41 │ ...A + } + + ALLOC3 (size: 4, align: 4) { + 00 00 50 41 │ ..PA } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index de9cf197199..01ec3f623d1 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -7,13 +7,24 @@ let mut _3: i32; let mut _5: i32; let mut _6: i32; - let mut _11: BigStruct; - let mut _16: &&BigStruct; - let mut _17: &BigStruct; - let mut _18: &BigStruct; - let mut _19: &BigStruct; - let mut _20: &BigStruct; - let mut _21: &BigStruct; + let mut _10: SmallStruct; + let mut _14: &&SmallStruct; + let mut _16: f32; + let mut _17: std::option::Option<S>; + let mut _18: &[f32]; + let mut _22: BigStruct; + let mut _26: &&BigStruct; + let mut _28: f32; + let mut _29: std::option::Option<S>; + let mut _30: &[f32]; + let mut _31: &SmallStruct; + let mut _32: &SmallStruct; + let mut _33: &SmallStruct; + let mut _34: &SmallStruct; + let mut _35: &BigStruct; + let mut _36: &BigStruct; + let mut _37: &BigStruct; + let mut _38: &BigStruct; scope 1 { debug s => _1; let _2: i32; @@ -22,24 +33,44 @@ let _4: i32; scope 3 { debug b => _4; - let _7: S; - let _8: u8; - let _9: f32; - let _10: S; + let _7: f32; + let _8: std::option::Option<S>; + let _9: &[f32]; scope 4 { debug a => _7; debug b => _8; debug c => _9; - debug d => _10; - let _12: S; - let _13: u8; - let _14: f32; - let _15: S; + let _11: f32; + let _12: std::option::Option<S>; + let _13: &[f32]; scope 5 { - debug a => _12; - debug b => _13; - debug c => _14; - debug d => _15; + debug a => _11; + debug b => _12; + debug c => _13; + let _15: SmallStruct; + scope 6 { + debug ss => _15; + let _19: f32; + let _20: std::option::Option<S>; + let _21: &[f32]; + scope 7 { + debug a => _19; + debug b => _20; + debug c => _21; + let _23: f32; + let _24: std::option::Option<S>; + let _25: &[f32]; + scope 8 { + debug a => _23; + debug b => _24; + debug c => _25; + let _27: BigStruct; + scope 9 { + debug bs => _27; + } + } + } + } } } } @@ -48,7 +79,8 @@ bb0: { StorageLive(_1); - _1 = S(const 1_i32); +- _1 = S(const 1_i32); ++ _1 = const S(1_i32); StorageLive(_2); StorageLive(_3); - _3 = (_1.0: i32); @@ -68,47 +100,95 @@ + _4 = const 6_i32; StorageDead(_6); StorageDead(_5); - StorageLive(_11); - _11 = const _; + StorageLive(_10); + _10 = const _; StorageLive(_7); -- _7 = (_11.0: S); -+ _7 = const S(1_i32); +- _7 = (_10.0: f32); ++ _7 = const 4f32; StorageLive(_8); -- _8 = (_11.1: u8); -+ _8 = const 5_u8; +- _8 = (_10.1: std::option::Option<S>); ++ _8 = const Option::<S>::Some(S(1_i32)); StorageLive(_9); -- _9 = (_11.2: f32); -+ _9 = const 7f32; - StorageLive(_10); -- _10 = (_11.3: S); -+ _10 = const S(13_i32); - StorageDead(_11); - StorageLive(_16); - _16 = const {ALLOC1: &&BigStruct}; - _17 = deref_copy (*_16); + _9 = (_10.2: &[f32]); + StorageDead(_10); + StorageLive(_14); + _14 = const {ALLOC4: &&SmallStruct}; + _31 = deref_copy (*_14); + StorageLive(_11); + _32 = deref_copy (*_14); +- _11 = ((*_32).0: f32); ++ _11 = const 9f32; StorageLive(_12); - _18 = deref_copy (*_16); -- _12 = ((*_18).0: S); -+ _12 = const S(1_i32); + _33 = deref_copy (*_14); + _12 = ((*_33).1: std::option::Option<S>); StorageLive(_13); - _19 = deref_copy (*_16); -- _13 = ((*_19).1: u8); -+ _13 = const 5_u8; - StorageLive(_14); - _20 = deref_copy (*_16); -- _14 = ((*_20).2: f32); -+ _14 = const 7f32; + _34 = deref_copy (*_14); + _13 = ((*_34).2: &[f32]); + StorageDead(_14); StorageLive(_15); - _21 = deref_copy (*_16); -- _15 = ((*_21).3: S); -+ _15 = const S(13_i32); + StorageLive(_16); +- _16 = _11; ++ _16 = const 9f32; + StorageLive(_17); + _17 = _12; + StorageLive(_18); + _18 = _13; +- _15 = SmallStruct(move _16, move _17, move _18); ++ _15 = SmallStruct(const 9f32, move _17, move _18); + StorageDead(_18); + StorageDead(_17); StorageDead(_16); + StorageLive(_22); + _22 = const _; + StorageLive(_19); +- _19 = (_22.0: f32); ++ _19 = const 25f32; + StorageLive(_20); + _20 = (_22.1: std::option::Option<S>); + StorageLive(_21); + _21 = (_22.2: &[f32]); + StorageDead(_22); + StorageLive(_26); + _26 = const {ALLOC5: &&BigStruct}; + _35 = deref_copy (*_26); + StorageLive(_23); + _36 = deref_copy (*_26); +- _23 = ((*_36).0: f32); ++ _23 = const 82f32; + StorageLive(_24); + _37 = deref_copy (*_26); +- _24 = ((*_37).1: std::option::Option<S>); ++ _24 = const Option::<S>::Some(S(35_i32)); + StorageLive(_25); + _38 = deref_copy (*_26); + _25 = ((*_38).2: &[f32]); + StorageDead(_26); + StorageLive(_27); + StorageLive(_28); +- _28 = _23; ++ _28 = const 82f32; + StorageLive(_29); +- _29 = _24; ++ _29 = const Option::<S>::Some(S(35_i32)); + StorageLive(_30); + _30 = _25; +- _27 = BigStruct(move _28, move _29, move _30); ++ _27 = BigStruct(const 82f32, const Option::<S>::Some(S(35_i32)), move _30); + StorageDead(_30); + StorageDead(_29); + StorageDead(_28); _0 = const (); + StorageDead(_27); + StorageDead(_25); + StorageDead(_24); + StorageDead(_23); + StorageDead(_21); + StorageDead(_20); + StorageDead(_19); StorageDead(_15); - StorageDead(_14); StorageDead(_13); StorageDead(_12); - StorageDead(_10); + StorageDead(_11); StorageDead(_9); StorageDead(_8); StorageDead(_7); @@ -117,13 +197,51 @@ StorageDead(_1); return; } ++ } ++ ++ ALLOC6 (size: 8, align: 4) { ++ 01 00 00 00 23 00 00 00 │ ....#... ++ } ++ ++ ALLOC7 (size: 8, align: 4) { ++ 01 00 00 00 23 00 00 00 │ ....#... ++ } ++ ++ ALLOC8 (size: 8, align: 4) { ++ 01 00 00 00 23 00 00 00 │ ....#... ++ } ++ ++ ALLOC9 (size: 8, align: 4) { ++ 01 00 00 00 01 00 00 00 │ ........ ++ } ++ ++ ALLOC10 (size: 4, align: 4) { ++ 01 00 00 00 │ .... } - ALLOC1 (static: STAT, size: 8, align: 8) { + ALLOC5 (static: BIG_STAT, size: 8, align: 8) { ╾ALLOC0╼ │ ╾──────╼ } - ALLOC0 (size: 16, align: 4) { - 01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....â–‘â–‘â–‘ + ALLOC0 (size: 32, align: 8) { + 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼ + 0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........Bâ–‘â–‘â–‘â–‘ + } + + ALLOC1 (size: 8, align: 4) { + 00 00 34 42 00 00 90 42 │ ..4B...B + } + + ALLOC4 (static: SMALL_STAT, size: 8, align: 8) { + ╾ALLOC2╼ │ ╾──────╼ + } + + ALLOC2 (size: 32, align: 8) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼ + 0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........Aâ–‘â–‘â–‘â–‘ + } + + ALLOC3 (size: 4, align: 4) { + 00 00 50 41 │ ..PA } diff --git a/tests/mir-opt/dataflow-const-prop/struct.rs b/tests/mir-opt/dataflow-const-prop/struct.rs index 7b0646a5356..043981a2954 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.rs +++ b/tests/mir-opt/dataflow-const-prop/struct.rs @@ -6,7 +6,10 @@ struct S(i32); #[derive(Copy, Clone)] -struct BigStruct(S, u8, f32, S); +struct SmallStruct(f32, Option<S>, &'static [f32]); + +#[derive(Copy, Clone)] +struct BigStruct(f32, Option<S>, &'static [f32]); // EMIT_MIR struct.main.DataflowConstProp.diff fn main() { @@ -15,9 +18,21 @@ fn main() { s.0 = 3; let b = a + s.0; - const VAL: BigStruct = BigStruct(S(1), 5, 7., S(13)); - let BigStruct(a, b, c, d) = VAL; + const SMALL_VAL: SmallStruct = SmallStruct(4., Some(S(1)), &[]); + let SmallStruct(a, b, c) = SMALL_VAL; + + static SMALL_STAT: &SmallStruct = &SmallStruct(9., None, &[13.]); + let SmallStruct(a, b, c) = *SMALL_STAT; + + let ss = SmallStruct(a, b, c); + + const BIG_VAL: BigStruct = BigStruct(25., None, &[]); + let BigStruct(a, b, c) = BIG_VAL; + + static BIG_STAT: &BigStruct = &BigStruct(82., Some(S(35)), &[45., 72.]); + let BigStruct(a, b, c) = *BIG_STAT; - static STAT: &BigStruct = &BigStruct(S(1), 5, 7., S(13)); - let BigStruct(a, b, c, d) = *STAT; + // We arbitrarily limit the size of synthetized values to 4 pointers. + // `BigStruct` can be read, but we will keep a MIR aggregate for this. + let bs = BigStruct(a, b, c); } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs index 02e4f1e5013..bb85e458678 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.rs +++ b/tests/mir-opt/dataflow-const-prop/transmute.rs @@ -52,8 +52,8 @@ pub unsafe fn undef_union_as_integer() -> u32 { // EMIT_MIR transmute.unreachable_direct.DataflowConstProp.diff pub unsafe fn unreachable_direct() -> ! { // CHECK-LABEL: fn unreachable_direct( - // CHECK: [[unit:_.*]] = (); - // CHECK: move [[unit]] as Never (Transmute); + // CHECK: = const (); + // CHECK: = const ZeroSized: Never; let x: Never = unsafe { transmute(()) }; match x {} } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff index fc0634b1f8f..fb28aa8f6d9 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.32bit.diff @@ -11,8 +11,10 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = (); - _1 = Union32 { value: move _2 }; +- _2 = (); +- _1 = Union32 { value: move _2 }; ++ _2 = const (); ++ _1 = Union32 { value: const () }; StorageDead(_2); _0 = move _1 as u32 (Transmute); StorageDead(_1); diff --git a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff index fc0634b1f8f..fb28aa8f6d9 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.undef_union_as_integer.DataflowConstProp.64bit.diff @@ -11,8 +11,10 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = (); - _1 = Union32 { value: move _2 }; +- _2 = (); +- _1 = Union32 { value: move _2 }; ++ _2 = const (); ++ _1 = Union32 { value: const () }; StorageDead(_2); _0 = move _1 as u32 (Transmute); StorageDead(_1); diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff index acbb5cd1bc7..c8d4d6edba1 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.32bit.diff @@ -14,8 +14,10 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = (); - _1 = move _2 as Never (Transmute); +- _2 = (); +- _1 = move _2 as Never (Transmute); ++ _2 = const (); ++ _1 = const ZeroSized: Never; unreachable; } } diff --git a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff index acbb5cd1bc7..c8d4d6edba1 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/transmute.unreachable_direct.DataflowConstProp.64bit.diff @@ -14,8 +14,10 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = (); - _1 = move _2 as Never (Transmute); +- _2 = (); +- _1 = move _2 as Never (Transmute); ++ _2 = const (); ++ _1 = const ZeroSized: Never; unreachable; } } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff index 5e385d21ec6..f5723cac7d9 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.32bit.diff @@ -11,6 +11,9 @@ let mut _8: i32; let mut _9: i32; let mut _10: i32; + let mut _12: i32; + let mut _13: (i32, i32); + let mut _14: i32; scope 1 { debug a => _1; let _2: i32; @@ -19,13 +22,18 @@ let _6: i32; scope 3 { debug c => _6; + let _11: (i32, (i32, i32), i32); + scope 4 { + debug d => _11; + } } } } bb0: { StorageLive(_1); - _1 = (const 1_i32, const 2_i32); +- _1 = (const 1_i32, const 2_i32); ++ _1 = const (1_i32, 2_i32); StorageLive(_2); StorageLive(_3); StorageLive(_4); @@ -41,7 +49,8 @@ - _2 = Add(move _3, const 3_i32); + _2 = const 6_i32; StorageDead(_3); - _1 = (const 2_i32, const 3_i32); +- _1 = (const 2_i32, const 3_i32); ++ _1 = const (2_i32, 3_i32); StorageLive(_6); StorageLive(_7); StorageLive(_8); @@ -61,11 +70,43 @@ + _6 = const 11_i32; StorageDead(_10); StorageDead(_7); + StorageLive(_11); + StorageLive(_12); +- _12 = _2; ++ _12 = const 6_i32; + StorageLive(_13); +- _13 = _1; ++ _13 = const (2_i32, 3_i32); + StorageLive(_14); +- _14 = _6; +- _11 = (move _12, move _13, move _14); ++ _14 = const 11_i32; ++ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32); + StorageDead(_14); + StorageDead(_13); + StorageDead(_12); _0 = const (); + StorageDead(_11); StorageDead(_6); StorageDead(_2); StorageDead(_1); return; } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 02 00 00 00 03 00 00 00 │ ........ ++ } ++ ++ ALLOC1 (size: 8, align: 4) { ++ 02 00 00 00 03 00 00 00 │ ........ ++ } ++ ++ ALLOC2 (size: 8, align: 4) { ++ 02 00 00 00 03 00 00 00 │ ........ ++ } ++ ++ ALLOC3 (size: 8, align: 4) { ++ 01 00 00 00 02 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff new file mode 100644 index 00000000000..f5723cac7d9 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/tuple.main.DataflowConstProp.64bit.diff @@ -0,0 +1,112 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let mut _1: (i32, i32); + let mut _3: i32; + let mut _4: i32; + let mut _5: i32; + let mut _7: i32; + let mut _8: i32; + let mut _9: i32; + let mut _10: i32; + let mut _12: i32; + let mut _13: (i32, i32); + let mut _14: i32; + scope 1 { + debug a => _1; + let _2: i32; + scope 2 { + debug b => _2; + let _6: i32; + scope 3 { + debug c => _6; + let _11: (i32, (i32, i32), i32); + scope 4 { + debug d => _11; + } + } + } + } + + bb0: { + StorageLive(_1); +- _1 = (const 1_i32, const 2_i32); ++ _1 = const (1_i32, 2_i32); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); +- _4 = (_1.0: i32); ++ _4 = const 1_i32; + StorageLive(_5); +- _5 = (_1.1: i32); +- _3 = Add(move _4, move _5); ++ _5 = const 2_i32; ++ _3 = const 3_i32; + StorageDead(_5); + StorageDead(_4); +- _2 = Add(move _3, const 3_i32); ++ _2 = const 6_i32; + StorageDead(_3); +- _1 = (const 2_i32, const 3_i32); ++ _1 = const (2_i32, 3_i32); + StorageLive(_6); + StorageLive(_7); + StorageLive(_8); +- _8 = (_1.0: i32); ++ _8 = const 2_i32; + StorageLive(_9); +- _9 = (_1.1: i32); +- _7 = Add(move _8, move _9); ++ _9 = const 3_i32; ++ _7 = const 5_i32; + StorageDead(_9); + StorageDead(_8); + StorageLive(_10); +- _10 = _2; +- _6 = Add(move _7, move _10); ++ _10 = const 6_i32; ++ _6 = const 11_i32; + StorageDead(_10); + StorageDead(_7); + StorageLive(_11); + StorageLive(_12); +- _12 = _2; ++ _12 = const 6_i32; + StorageLive(_13); +- _13 = _1; ++ _13 = const (2_i32, 3_i32); + StorageLive(_14); +- _14 = _6; +- _11 = (move _12, move _13, move _14); ++ _14 = const 11_i32; ++ _11 = (const 6_i32, const (2_i32, 3_i32), const 11_i32); + StorageDead(_14); + StorageDead(_13); + StorageDead(_12); + _0 = const (); + StorageDead(_11); + StorageDead(_6); + StorageDead(_2); + StorageDead(_1); + return; + } ++ } ++ ++ ALLOC0 (size: 8, align: 4) { ++ 02 00 00 00 03 00 00 00 │ ........ ++ } ++ ++ ALLOC1 (size: 8, align: 4) { ++ 02 00 00 00 03 00 00 00 │ ........ ++ } ++ ++ ALLOC2 (size: 8, align: 4) { ++ 02 00 00 00 03 00 00 00 │ ........ ++ } ++ ++ ALLOC3 (size: 8, align: 4) { ++ 01 00 00 00 02 00 00 00 │ ........ + } + diff --git a/tests/mir-opt/dataflow-const-prop/tuple.rs b/tests/mir-opt/dataflow-const-prop/tuple.rs index c63ce8b140f..bb706eafe88 100644 --- a/tests/mir-opt/dataflow-const-prop/tuple.rs +++ b/tests/mir-opt/dataflow-const-prop/tuple.rs @@ -1,5 +1,6 @@ // skip-filecheck // unit-test: DataflowConstProp +// EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR tuple.main.DataflowConstProp.diff fn main() { @@ -7,4 +8,6 @@ fn main() { let b = a.0 + a.1 + 3; a = (2, 3); let c = a.0 + a.1 + b; + + let d = (b, a, c); } diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-abort.diff deleted file mode 100644 index eac51000cac..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-abort.diff +++ /dev/null @@ -1,21 +0,0 @@ -- // MIR for `inlined_no_sanitize` before Inline -+ // MIR for `inlined_no_sanitize` after Inline - - fn inlined_no_sanitize() -> () { - let mut _0: (); - let _1: (); -+ scope 1 (inlined no_sanitize) { -+ } - - bb0: { - StorageLive(_1); -- _1 = no_sanitize() -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff deleted file mode 100644 index eba5ad9cf26..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff +++ /dev/null @@ -1,21 +0,0 @@ -- // MIR for `inlined_no_sanitize` before Inline -+ // MIR for `inlined_no_sanitize` after Inline - - fn inlined_no_sanitize() -> () { - let mut _0: (); - let _1: (); -+ scope 1 (inlined no_sanitize) { -+ } - - bb0: { - StorageLive(_1); -- _1 = no_sanitize() -> [return: bb1, unwind continue]; -- } -- -- bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-abort.diff deleted file mode 100644 index c2a81b9804e..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-abort.diff +++ /dev/null @@ -1,21 +0,0 @@ -- // MIR for `inlined_target_feature` before Inline -+ // MIR for `inlined_target_feature` after Inline - - fn inlined_target_feature() -> () { - let mut _0: (); - let _1: (); -+ scope 1 (inlined target_feature) { -+ } - - bb0: { - StorageLive(_1); -- _1 = target_feature() -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff deleted file mode 100644 index 24457819b2c..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff +++ /dev/null @@ -1,21 +0,0 @@ -- // MIR for `inlined_target_feature` before Inline -+ // MIR for `inlined_target_feature` after Inline - - fn inlined_target_feature() -> () { - let mut _0: (); - let _1: (); -+ scope 1 (inlined target_feature) { -+ } - - bb0: { - StorageLive(_1); -- _1 = target_feature() -> [return: bb1, unwind continue]; -- } -- -- bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-abort.diff deleted file mode 100644 index 791c5a0f29f..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-abort.diff +++ /dev/null @@ -1,22 +0,0 @@ -- // MIR for `not_inlined_c_variadic` before Inline -+ // MIR for `not_inlined_c_variadic` after Inline - - fn not_inlined_c_variadic() -> () { - let mut _0: (); - let _1: u32; - scope 1 { - debug s => _1; - } - - bb0: { - StorageLive(_1); - _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> [return: bb1, unwind unreachable]; - } - - bb1: { - _0 = const (); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff deleted file mode 100644 index 364acab6d93..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff +++ /dev/null @@ -1,22 +0,0 @@ -- // MIR for `not_inlined_c_variadic` before Inline -+ // MIR for `not_inlined_c_variadic` after Inline - - fn not_inlined_c_variadic() -> () { - let mut _0: (); - let _1: u32; - scope 1 { - debug s => _1; - } - - bb0: { - StorageLive(_1); - _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> [return: bb1, unwind continue]; - } - - bb1: { - _0 = const (); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-abort.diff deleted file mode 100644 index b9d0946b7c3..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-abort.diff +++ /dev/null @@ -1,19 +0,0 @@ -- // MIR for `not_inlined_no_sanitize` before Inline -+ // MIR for `not_inlined_no_sanitize` after Inline - - fn not_inlined_no_sanitize() -> () { - let mut _0: (); - let _1: (); - - bb0: { - StorageLive(_1); - _1 = no_sanitize() -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff deleted file mode 100644 index 965b7ddca32..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff +++ /dev/null @@ -1,19 +0,0 @@ -- // MIR for `not_inlined_no_sanitize` before Inline -+ // MIR for `not_inlined_no_sanitize` after Inline - - fn not_inlined_no_sanitize() -> () { - let mut _0: (); - let _1: (); - - bb0: { - StorageLive(_1); - _1 = no_sanitize() -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-abort.diff deleted file mode 100644 index 7c689a73482..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-abort.diff +++ /dev/null @@ -1,19 +0,0 @@ -- // MIR for `not_inlined_target_feature` before Inline -+ // MIR for `not_inlined_target_feature` after Inline - - fn not_inlined_target_feature() -> () { - let mut _0: (); - let _1: (); - - bb0: { - StorageLive(_1); - _1 = target_feature() -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff deleted file mode 100644 index bcdbd6e3314..00000000000 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff +++ /dev/null @@ -1,19 +0,0 @@ -- // MIR for `not_inlined_target_feature` before Inline -+ // MIR for `not_inlined_target_feature` after Inline - - fn not_inlined_target_feature() -> () { - let mut _0: (); - let _1: (); - - bb0: { - StorageLive(_1); - _1 = target_feature() -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_1); - _0 = const (); - return; - } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.rs b/tests/mir-opt/inline/inline_compatibility.rs index 52f4debf5db..3ad880715fe 100644 --- a/tests/mir-opt/inline/inline_compatibility.rs +++ b/tests/mir-opt/inline/inline_compatibility.rs @@ -1,51 +1,71 @@ -// skip-filecheck // Checks that only functions with compatible attributes are inlined. -// // only-x86_64 -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +// compile-flags: -Cpanic=abort #![crate_type = "lib"] #![feature(no_sanitize)] #![feature(target_feature_11)] #![feature(c_variadic)] -// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff +#[inline] +#[target_feature(enable = "sse2")] +unsafe fn sse2() {} + +#[inline] +fn nop() {} + +// CHECK-LABEL: fn f0() +// CHECK: bb0: { +// CHECK-NEXT: return; #[target_feature(enable = "sse2")] -pub unsafe fn inlined_target_feature() { - target_feature(); +pub unsafe fn f0() { + sse2(); } -// EMIT_MIR inline_compatibility.not_inlined_target_feature.Inline.diff -pub unsafe fn not_inlined_target_feature() { - target_feature(); +// CHECK-LABEL: fn f1() +// CHECK: bb0: { +// CHECK-NEXT: sse2() +pub unsafe fn f1() { + sse2(); } -// EMIT_MIR inline_compatibility.inlined_no_sanitize.Inline.diff +// CHECK-LABEL: fn f2() +// CHECK: bb0: { +// CHECK-NEXT: nop() +#[target_feature(enable = "avx")] +pub unsafe fn f2() { + nop(); +} + +#[inline] +#[no_sanitize(address)] +pub unsafe fn no_sanitize() {} + +// CHECK-LABEL: fn inlined_no_sanitize() +// CHECK: bb0: { +// CHECK-NEXT: return; #[no_sanitize(address)] pub unsafe fn inlined_no_sanitize() { no_sanitize(); } -// EMIT_MIR inline_compatibility.not_inlined_no_sanitize.Inline.diff +// CHECK-LABEL: fn not_inlined_no_sanitize() +// CHECK: bb0: { +// CHECK-NEXT: no_sanitize() pub unsafe fn not_inlined_no_sanitize() { no_sanitize(); } -#[inline] -#[target_feature(enable = "sse2")] -pub unsafe fn target_feature() {} - -#[inline] -#[no_sanitize(address)] -pub unsafe fn no_sanitize() {} - -// EMIT_MIR inline_compatibility.not_inlined_c_variadic.Inline.diff +// CHECK-LABEL: fn not_inlined_c_variadic() +// CHECK: bb0: { +// CHECK-NEXT: StorageLive(_1) +// CHECK-NEXT: _1 = sum pub unsafe fn not_inlined_c_variadic() { - let s = sum(4u32, 4u32, 30u32, 200u32, 1000u32); + let _ = sum(4u32, 4u32, 30u32, 200u32, 1000u32); } -#[no_mangle] #[inline(always)] +#[no_mangle] unsafe extern "C" fn sum(n: u32, mut vs: ...) -> u32 { let mut s = 0; let mut i = 0; diff --git a/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff b/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff index 1c417d4346d..9e1bce1ee20 100644 --- a/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff +++ b/tests/mir-opt/instsimplify/casts.redundant.InstSimplify.diff @@ -6,22 +6,27 @@ let mut _0: *const &u8; let mut _2: *const &u8; let mut _3: *const &u8; + let mut _4: *const &u8; scope 1 (inlined generic_cast::<&u8, &u8>) { - debug x => _3; - let mut _4: *const &u8; + debug x => _4; + let mut _5: *const &u8; } bb0: { StorageLive(_2); StorageLive(_3); - _3 = _1; StorageLive(_4); - _4 = _3; -- _2 = move _4 as *const &u8 (PtrToPtr); -+ _2 = move _4; + _4 = _1; + StorageLive(_5); + _5 = _4; +- _3 = move _5 as *const &u8 (PtrToPtr); ++ _3 = move _5; + StorageDead(_5); StorageDead(_4); - StorageDead(_3); +- _2 = move _3 as *const &u8 (PtrToPtr); ++ _2 = move _3; _0 = _2; + StorageDead(_3); StorageDead(_2); return; } diff --git a/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff b/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff index 1ae9d45e66c..a6d68cd4e4b 100644 --- a/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff +++ b/tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff @@ -4,16 +4,21 @@ fn roundtrip(_1: *const u8) -> *const u8 { debug x => _1; let mut _0: *const u8; - let mut _2: *mut u8; - let mut _3: *const u8; + let mut _2: *const u8; + let mut _3: *mut u8; + let mut _4: *const u8; bb0: { StorageLive(_2); StorageLive(_3); - _3 = _1; - _2 = move _3 as *mut u8 (PtrToPtr); - _0 = move _2 as *const u8 (PointerCoercion(MutToConstPointer)); + StorageLive(_4); + _4 = _1; + _3 = move _4 as *mut u8 (PtrToPtr); + _2 = move _3 as *const u8 (PointerCoercion(MutToConstPointer)); + StorageDead(_4); StorageDead(_3); +- _0 = move _2 as *const u8 (PtrToPtr); ++ _0 = move _2; StorageDead(_2); return; } diff --git a/tests/mir-opt/instsimplify/casts.rs b/tests/mir-opt/instsimplify/casts.rs index 18bab524c64..86f9b34ea04 100644 --- a/tests/mir-opt/instsimplify/casts.rs +++ b/tests/mir-opt/instsimplify/casts.rs @@ -18,8 +18,8 @@ pub fn redundant<'a, 'b: 'a>(x: *const &'a u8) -> *const &'a u8 { // EMIT_MIR casts.roundtrip.InstSimplify.diff pub fn roundtrip(x: *const u8) -> *const u8 { // CHECK-LABEL: fn roundtrip( - // CHECK: _3 = _1; - // CHECK: _2 = move _3 as *mut u8 (PtrToPtr); - // CHECK: _0 = move _2 as *const u8 (PointerCoercion(MutToConstPointer)); + // CHECK: _4 = _1; + // CHECK: _3 = move _4 as *mut u8 (PtrToPtr); + // CHECK: _2 = move _3 as *const u8 (PointerCoercion(MutToConstPointer)); x as *mut u8 as *const u8 } diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 7ee46e1520a..71009d32477 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -62,6 +62,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), + using_internal_features: std::sync::Arc::default(), expanded_args: Default::default(), }; diff --git a/tests/run-make/issue-96498/Makefile b/tests/run-make/issue-96498/Makefile deleted file mode 100644 index efdd328c671..00000000000 --- a/tests/run-make/issue-96498/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# only-windows -# needs-rust-lld - -include ../tools.mk - -# Ensure that LLD can link -all: - $(RUSTC) -C linker=rust-lld foo.rs diff --git a/tests/run-make/windows-safeseh/Makefile b/tests/run-make/windows-safeseh/Makefile new file mode 100644 index 00000000000..d6a403961d7 --- /dev/null +++ b/tests/run-make/windows-safeseh/Makefile @@ -0,0 +1,19 @@ +# only-windows +# needs-rust-lld + +include ../tools.mk + +all: foo bar + +# Ensure that LLD can link when an .rlib contains a synthetic object +# file referencing exported or used symbols. +foo: + $(RUSTC) -C linker=rust-lld foo.rs + +# Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib. +# Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware. +bar: baz + $(RUSTC) -C linker=rust-lld -C link-arg=/WHOLEARCHIVE:libbaz.rlib bar.rs + +baz: + $(RUSTC) baz.rs diff --git a/tests/run-make/windows-safeseh/bar.rs b/tests/run-make/windows-safeseh/bar.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/windows-safeseh/bar.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/windows-safeseh/baz.rs b/tests/run-make/windows-safeseh/baz.rs new file mode 100644 index 00000000000..8d5b9dc5aea --- /dev/null +++ b/tests/run-make/windows-safeseh/baz.rs @@ -0,0 +1,4 @@ +#![crate_type = "rlib"] + +#[no_mangle] +extern "C" fn baz() {} diff --git a/tests/run-make/issue-96498/foo.rs b/tests/run-make/windows-safeseh/foo.rs index 93ac3641b09..93ac3641b09 100644 --- a/tests/run-make/issue-96498/foo.rs +++ b/tests/run-make/windows-safeseh/foo.rs diff --git a/tests/rustdoc/deprecated-future-staged-api.rs b/tests/rustdoc/deprecated-future-staged-api.rs index 2670e7f5d04..09120b8d411 100644 --- a/tests/rustdoc/deprecated-future-staged-api.rs +++ b/tests/rustdoc/deprecated-future-staged-api.rs @@ -1,12 +1,12 @@ #![feature(staged_api)] -#![stable(feature = "deprecated-future-staged-api", since = "1.0.0")] +#![stable(feature = "deprecated_future_staged_api", since = "1.0.0")] // @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \ // 'Deprecation planned' // @has deprecated_future_staged_api/struct.S1.html '//*[@class="stab deprecated"]' \ // 'Deprecating in 99.99.99: effectively never' #[deprecated(since = "99.99.99", note = "effectively never")] -#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")] +#[stable(feature = "deprecated_future_staged_api", since = "1.0.0")] pub struct S1; // @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \ @@ -14,5 +14,5 @@ pub struct S1; // @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \ // 'Deprecating in a future Rust version: literally never' #[deprecated(since = "TBD", note = "literally never")] -#[stable(feature = "deprecated-future-staged-api", since = "1.0.0")] +#[stable(feature = "deprecated_future_staged_api", since = "1.0.0")] pub struct S2; diff --git a/tests/rustdoc/html-no-source.rs b/tests/rustdoc/html-no-source.rs index 25615a73c3f..b91aa41207a 100644 --- a/tests/rustdoc/html-no-source.rs +++ b/tests/rustdoc/html-no-source.rs @@ -11,20 +11,20 @@ // @files 'src/foo' '[]' // @has foo/fn.foo.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' -// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' #[stable(feature = "bar", since = "1.0")] pub fn foo() {} // @has foo/struct.Bar.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' -// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' #[stable(feature = "bar", since = "1.0")] pub struct Bar; impl Bar { - // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0' - // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·' + // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0.0' + // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0.0 ·' #[stable(feature = "foobar", since = "2.0")] pub fn bar() {} } diff --git a/tests/rustdoc/implementor-stable-version.rs b/tests/rustdoc/implementor-stable-version.rs index a1f3fd5a8c5..9c5b9b7e303 100644 --- a/tests/rustdoc/implementor-stable-version.rs +++ b/tests/rustdoc/implementor-stable-version.rs @@ -1,21 +1,21 @@ -#![stable(feature = "bar", since = "OLD 1.0")] +#![stable(feature = "bar", since = "3.3.3")] #![crate_name = "foo"] #![feature(staged_api)] -#[stable(feature = "bar", since = "OLD 1.0")] +#[stable(feature = "bar", since = "3.3.3")] pub trait Bar {} -#[stable(feature = "baz", since = "OLD 1.0")] +#[stable(feature = "baz", since = "3.3.3")] pub trait Baz {} -#[stable(feature = "baz", since = "OLD 1.0")] +#[stable(feature = "baz", since = "3.3.3")] pub struct Foo; -// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0' -#[stable(feature = "foobar", since = "NEW 2.0")] +// @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' '4.4.4' +#[stable(feature = "foobar", since = "4.4.4")] impl Bar for Foo {} -// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' 'OLD 1.0' -#[stable(feature = "foobaz", since = "OLD 1.0")] +// @!has foo/trait.Baz.html '//div[@id="implementors-list"]//span[@class="since"]' '3.3.3' +#[stable(feature = "foobaz", since = "3.3.3")] impl Baz for Foo {} diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-version-separator.rs index 14580373b3b..7256f731573 100644 --- a/tests/rustdoc/source-version-separator.rs +++ b/tests/rustdoc/source-version-separator.rs @@ -3,23 +3,23 @@ #![feature(staged_api)] // @has foo/trait.Bar.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' #[stable(feature = "bar", since = "1.0")] pub trait Bar { - // @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source' + // @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source' #[stable(feature = "foobar", since = "3.0")] fn foo(); } -// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source' +// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source' // @has foo/struct.Foo.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' #[stable(feature = "baz", since = "1.0")] pub struct Foo; impl Foo { - // @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source' + // @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · source' #[stable(feature = "foobar", since = "3.0")] pub fn foofoo() {} } diff --git a/tests/rustdoc/version-separator-without-source.rs b/tests/rustdoc/version-separator-without-source.rs index 04ea46a7f3a..4a855b7bb29 100644 --- a/tests/rustdoc/version-separator-without-source.rs +++ b/tests/rustdoc/version-separator-without-source.rs @@ -4,20 +4,20 @@ #![crate_name = "foo"] // @has foo/fn.foo.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' -// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' #[stable(feature = "bar", since = "1.0")] pub fn foo() {} // @has foo/struct.Bar.html -// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · ' -// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · ' +// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · ' +// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · ' #[stable(feature = "bar", since = "1.0")] pub struct Bar; impl Bar { - // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0' - // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·' + // @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0.0' + // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0.0 ·' #[stable(feature = "foobar", since = "2.0")] pub fn bar() {} } diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index c6a9e08ed02..a340877752d 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -1,5 +1,5 @@ // run-pass -// Test that users are able to use stable mir APIs to retrieve monomorphized instances +//! Test that users are able to use stable mir APIs to retrieve monomorphized instances // ignore-stage1 // ignore-cross-compile @@ -14,15 +14,15 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_smir; -extern crate stable_mir; extern crate rustc_driver; extern crate rustc_interface; +extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use mir::{mono::Instance, TerminatorKind::*}; -use stable_mir::ty::{TyKind, RigidTy}; -use stable_mir::*; +use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; +use stable_mir::ty::{RigidTy, TyKind}; +use stable_mir::*; use std::io::Write; use std::ops::ControlFlow; @@ -33,16 +33,16 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { let items = stable_mir::all_local_items(); // Get all items and split generic vs monomorphic items. - let (generic, mono) : (Vec<_>, Vec<_>) = items.into_iter().partition(|item| { - item.requires_monomorphization() - }); + let (generic, mono): (Vec<_>, Vec<_>) = + items.into_iter().partition(|item| item.requires_monomorphization()); assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant"); assert_eq!(generic.len(), 2, "Expected 2 generic functions"); // For all monomorphic items, get the correspondent instances. - let instances = mono.iter().filter_map(|item| { - mir::mono::Instance::try_from(*item).ok() - }).collect::<Vec<mir::mono::Instance>>(); + let instances = mono + .iter() + .filter_map(|item| mir::mono::Instance::try_from(*item).ok()) + .collect::<Vec<mir::mono::Instance>>(); assert_eq!(instances.len(), mono.len()); // For all generic items, try_from should fail. @@ -58,19 +58,22 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { fn test_body(body: mir::Body) { for term in body.blocks.iter().map(|bb| &bb.terminator) { match &term.kind { - Call{ func, .. } => { - let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() }; + Call { func, .. } => { + let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() }; let RigidTy::FnDef(def, args) = ty else { unreachable!() }; let result = Instance::resolve(def, &args); assert!(result.is_ok()); } - Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */} - _ => { unreachable!("Unexpected terminator {term:?}") } + Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => { + /* Do nothing */ + } + _ => { + unreachable!("Unexpected terminator {term:?}") + } } } } - /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. /// Then it will create a `StableMir` using custom arguments and then diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 3cb71b5a025..ed6b786f5e1 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -22,8 +22,8 @@ extern crate stable_mir; use rustc_hir::def::DefKind; use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; - -use stable_mir::fold::Foldable; +use stable_mir::mir::mono::Instance; +use stable_mir::ty::{RigidTy, TyKind}; use std::assert_matches::assert_matches; use std::io::Write; use std::ops::ControlFlow; @@ -47,7 +47,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { let bar = get_item(&items, (DefKind::Fn, "bar")).unwrap(); let body = bar.body(); - assert_eq!(body.locals.len(), 2); + assert_eq!(body.locals().len(), 2); assert_eq!(body.blocks.len(), 1); let block = &body.blocks[0]; assert_eq!(block.statements.len(), 1); @@ -62,7 +62,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap(); let body = foo_bar.body(); - assert_eq!(body.locals.len(), 5); + assert_eq!(body.locals().len(), 5); assert_eq!(body.blocks.len(), 4); let block = &body.blocks[0]; match &block.terminator.kind { @@ -72,29 +72,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { let types = get_item(&items, (DefKind::Fn, "types")).unwrap(); let body = types.body(); - assert_eq!(body.locals.len(), 6); + assert_eq!(body.locals().len(), 6); assert_matches!( - body.locals[0].ty.kind(), + body.locals()[0].ty.kind(), stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool) ); assert_matches!( - body.locals[1].ty.kind(), + body.locals()[1].ty.kind(), stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool) ); assert_matches!( - body.locals[2].ty.kind(), + body.locals()[2].ty.kind(), stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char) ); assert_matches!( - body.locals[3].ty.kind(), + body.locals()[3].ty.kind(), stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32)) ); assert_matches!( - body.locals[4].ty.kind(), + body.locals()[4].ty.kind(), stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64)) ); assert_matches!( - body.locals[5].ty.kind(), + body.locals()[5].ty.kind(), stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Float( stable_mir::ty::FloatTy::F64 )) @@ -119,40 +119,18 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { } let monomorphic = get_item(&items, (DefKind::Fn, "monomorphic")).unwrap(); - for block in monomorphic.body().blocks { + let instance = Instance::try_from(monomorphic.clone()).unwrap(); + for block in instance.body().blocks { match &block.terminator.kind { - stable_mir::mir::TerminatorKind::Call { func, .. } => match func { - stable_mir::mir::Operand::Constant(c) => match &c.literal.literal { - stable_mir::ty::ConstantKind::Allocated(alloc) => { - assert!(alloc.bytes.is_empty()); - match c.literal.ty.kind() { - stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::FnDef( - def, - mut args, - )) => { - let func = def.body(); - match func.locals[1].ty - .fold(&mut args) - .continue_value() - .unwrap() - .kind() - { - stable_mir::ty::TyKind::RigidTy( - stable_mir::ty::RigidTy::Uint(_), - ) => {} - stable_mir::ty::TyKind::RigidTy( - stable_mir::ty::RigidTy::Tuple(_), - ) => {} - other => panic!("{other:?}"), - } - } - other => panic!("{other:?}"), - } - } + stable_mir::mir::TerminatorKind::Call { func, .. } => { + let TyKind::RigidTy(ty) = func.ty(&body.locals()).kind() else { unreachable!() }; + let RigidTy::FnDef(def, args) = ty else { unreachable!() }; + let next_func = Instance::resolve(def, &args).unwrap(); + match next_func.body().locals()[1].ty.kind() { + TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {} other => panic!("{other:?}"), - }, - other => panic!("{other:?}"), - }, + } + } stable_mir::mir::TerminatorKind::Return => {} other => panic!("{other:?}"), } @@ -162,6 +140,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { // Ensure we don't panic trying to get the body of a constant. foo_const.body(); + let locals_fn = get_item(&items, (DefKind::Fn, "locals")).unwrap(); + let body = locals_fn.body(); + assert_eq!(body.locals().len(), 4); + assert_matches!( + body.ret_local().ty.kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char) + ); + assert_eq!(body.arg_locals().len(), 2); + assert_matches!( + body.arg_locals()[0].ty.kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32)) + ); + assert_matches!( + body.arg_locals()[1].ty.kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64)) + ); + assert_eq!(body.inner_locals().len(), 1); + // If conditions have an extra inner local to hold their results + assert_matches!( + body.inner_locals()[0].ty.kind(), + stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool) + ); + ControlFlow::Continue(()) } @@ -233,6 +234,14 @@ fn generate_input(path: &str) -> std::io::Result<()> { pub fn assert(x: i32) -> i32 {{ x + 1 + }} + + pub fn locals(a: i32, _: u64) -> char {{ + if a > 5 {{ + 'a' + }} else {{ + 'b' + }} }}"# )?; Ok(()) diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs new file mode 100644 index 00000000000..b0596b18823 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -0,0 +1,64 @@ +// run-pass +//! Test that users are able to use retrieve internal constructs from stable ones to help with +//! the migration. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate rustc_middle; +extern crate stable_mir; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + let main_fn = stable_mir::entry_fn().unwrap(); + let body = main_fn.body(); + let orig_ty = body.locals()[0].ty; + let rustc_ty = rustc_internal::internal(&orig_ty); + assert!(rustc_ty.is_unit()); + ControlFlow::Continue(()) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "internal_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_translation(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + pub fn main() {{ + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 1f049b1785a..0cdf229711a 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -30,6 +30,7 @@ // revisions: loongarch64 //[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //[loongarch64] needs-llvm-components: loongarch +//[loongarch64] min-llvm-version: 17 // revisions: wasm //[wasm] compile-flags: --target wasm32-unknown-unknown //[wasm] needs-llvm-components: webassembly diff --git a/tests/ui/associated-consts/issue-105330.rs b/tests/ui/associated-consts/issue-105330.rs index 285e89cce49..6c6dae864f3 100644 --- a/tests/ui/associated-consts/issue-105330.rs +++ b/tests/ui/associated-consts/issue-105330.rs @@ -14,5 +14,6 @@ fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658 fn main<A: TraitWAssocConst<A=32>>() { //~^ ERROR E0658 + //~| ERROR E0131 foo::<Demo>(); } diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr index 55207909f7a..aeedf6b1949 100644 --- a/tests/ui/associated-consts/issue-105330.stderr +++ b/tests/ui/associated-consts/issue-105330.stderr @@ -39,7 +39,13 @@ error[E0562]: `impl Trait` only allowed in function and inherent method argument LL | impl TraitWAssocConst for impl Demo { | ^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0131]: `main` function is not allowed to have generic parameters + --> $DIR/issue-105330.rs:15:8 + | +LL | fn main<A: TraitWAssocConst<A=32>>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters + +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0404, E0562, E0658. -For more information about an error, try `rustc --explain E0404`. +Some errors have detailed explanations: E0131, E0404, E0562, E0658. +For more information about an error, try `rustc --explain E0131`. diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr b/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr index 464b59c249f..0620725ca33 100644 --- a/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr +++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.item.stderr @@ -10,6 +10,18 @@ note: required by a bound in `Ty::Pr` LL | type Pr<T: Copy> = T; | ^^^^ required by this bound in `Ty::Pr` -error: aborting due to previous error +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/generic-associated-types-bad.rs:16:27 + | +LL | const _: Ty::Pr<String> = String::new(); + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | +note: required by a bound in `Ty::Pr` + --> $DIR/generic-associated-types-bad.rs:10:16 + | +LL | type Pr<T: Copy> = T; + | ^^^^ required by this bound in `Ty::Pr` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr b/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr index 4f371b24e80..fcf828c21c7 100644 --- a/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr +++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.local.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Vec<()>: Copy` is not satisfied - --> $DIR/generic-associated-types-bad.rs:20:12 + --> $DIR/generic-associated-types-bad.rs:21:12 | LL | let _: Ty::Pr<Vec<()>>; | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Vec<()>` diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr b/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr index 74ec39424ed..94c20521857 100644 --- a/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr +++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.region.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/generic-associated-types-bad.rs:25:12 + --> $DIR/generic-associated-types-bad.rs:26:12 | LL | fn user<'a>() { | -- lifetime `'a` defined here diff --git a/tests/ui/associated-inherent-types/generic-associated-types-bad.rs b/tests/ui/associated-inherent-types/generic-associated-types-bad.rs index e66392a0a94..f5deec422f5 100644 --- a/tests/ui/associated-inherent-types/generic-associated-types-bad.rs +++ b/tests/ui/associated-inherent-types/generic-associated-types-bad.rs @@ -14,6 +14,7 @@ impl Ty { #[cfg(item)] const _: Ty::Pr<String> = String::new(); //[item]~ the trait bound `String: Copy` is not satisfied +//[item]~^ the trait bound `String: Copy` is not satisfied fn main() { #[cfg(local)] diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs b/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs index c373c5855cd..cc0101d63cf 100644 --- a/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs +++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait.rs @@ -21,6 +21,7 @@ trait Other { impl<T:Get> Other for T { fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {} //~^ ERROR the trait bound `(T, U): Get` is not satisfied + //~| ERROR the trait bound `(T, U): Get` is not satisfied } fn main() { } diff --git a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr index b3f2e16ba0d..9ebc45387e8 100644 --- a/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr +++ b/tests/ui/associated-types/associated-types-no-suitable-supertrait.stderr @@ -21,6 +21,18 @@ help: consider further restricting `Self` LL | fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Get {} | +++++++++++++++ -error: aborting due to 2 previous errors +error[E0277]: the trait bound `(T, U): Get` is not satisfied + --> $DIR/associated-types-no-suitable-supertrait.rs:22:5 + | +LL | fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)` + | +help: this trait has no implementations, consider adding one + --> $DIR/associated-types-no-suitable-supertrait.rs:12:1 + | +LL | trait Get { + | ^^^^^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr index c3b4e761824..b360aab6b59 100644 --- a/tests/ui/async-await/async-await-let-else.stderr +++ b/tests/ui/async-await/async-await-let-else.stderr @@ -30,7 +30,7 @@ LL | is_send(foo2(Some(true))); | required by a bound introduced by this call | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/async-await-let-else.rs:24:29 | LL | async fn bar2<T>(_: T) -> ! { @@ -39,7 +39,7 @@ LL | | panic!() LL | | } | |_^ = note: required because it captures the following types: `impl Future<Output = !>` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/async-await-let-else.rs:18:32 | LL | async fn foo2(x: Option<bool>) { diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr b/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr index 2114fb59ba3..f9e5bf675cb 100644 --- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr +++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.mir.stderr @@ -23,7 +23,7 @@ LL | S::f(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/async-unsafe-fn-call-in-safe.rs:24:5 + --> $DIR/async-unsafe-fn-call-in-safe.rs:26:5 | LL | f(); | ^^^ call to unsafe function diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs b/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs index c941dc27aa3..14cc0dc614f 100644 --- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs +++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.rs @@ -20,6 +20,10 @@ async fn g() { } fn main() { - S::f(); //[mir]~ ERROR call to unsafe function is unsafe - f(); //[mir]~ ERROR call to unsafe function is unsafe + S::f(); + //[mir]~^ ERROR call to unsafe function is unsafe + //[thir]~^^ ERROR call to unsafe function `S::f` is unsafe + f(); + //[mir]~^ ERROR call to unsafe function is unsafe + //[thir]~^^ ERROR call to unsafe function `f` is unsafe } diff --git a/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr b/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr index 68d97d3fd7d..ba3303fe793 100644 --- a/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr +++ b/tests/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr @@ -14,6 +14,22 @@ LL | f(); | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 2 previous errors +error[E0133]: call to unsafe function `S::f` is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:23:5 + | +LL | S::f(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `f` is unsafe and requires unsafe function or block + --> $DIR/async-unsafe-fn-call-in-safe.rs:26:5 + | +LL | f(); + | ^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs index 3cc11d241f7..c26f6625f00 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![allow(incomplete_features)] - use std::future::Future; use std::pin::Pin; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr index e6dd83b6b0a..b70b36adb4a 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr @@ -1,11 +1,11 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/async-example-desugared-boxed-in-trait.rs:13:5 + --> $DIR/async-example-desugared-boxed-in-trait.rs:11:5 | LL | async fn foo(&self) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future | note: type in trait - --> $DIR/async-example-desugared-boxed-in-trait.rs:9:22 + --> $DIR/async-example-desugared-boxed-in-trait.rs:7:22 | LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs index 81d25ce27ae..c5a9841029e 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![allow(incomplete_features)] - use std::future::Future; use std::pin::Pin; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr index cd18790fdfb..6392ce86e4a 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr @@ -1,5 +1,5 @@ error: method `foo` should be async because the method from the trait is async - --> $DIR/async-example-desugared-boxed.rs:13:5 + --> $DIR/async-example-desugared-boxed.rs:11:5 | LL | async fn foo(&self) -> i32; | --------------------------- required because the trait method is async diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs index f0c59180fb5..ce93bd62608 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs @@ -2,7 +2,6 @@ // edition: 2021 #![feature(lint_reasons)] -#![allow(incomplete_features)] use std::future::Future; use std::pin::Pin; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs index deca28af853..f7a351efff5 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs @@ -1,8 +1,6 @@ // check-pass // edition: 2021 -#![allow(incomplete_features)] - use std::future::Future; trait MyTrait { diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs index fdba4d93c77..c287b9a5b84 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![allow(incomplete_features)] - use std::future::Future; use std::task::Poll; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr index 463892f21bf..1eda6fe6532 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr @@ -1,5 +1,5 @@ error: method `foo` should be async because the method from the trait is async - --> $DIR/async-example-desugared-manual.rs:21:5 + --> $DIR/async-example-desugared-manual.rs:19:5 | LL | async fn foo(&self) -> i32; | --------------------------- required because the trait method is async diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs index 7fc78f7da6d..78904d87abc 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared.rs @@ -1,8 +1,6 @@ // check-pass // edition: 2021 -#![allow(incomplete_features)] - use std::future::Future; trait MyTrait { diff --git a/tests/ui/async-await/in-trait/async-example.rs b/tests/ui/async-await/in-trait/async-example.rs index 62ed490bf05..a32f979df6b 100644 --- a/tests/ui/async-await/in-trait/async-example.rs +++ b/tests/ui/async-await/in-trait/async-example.rs @@ -1,8 +1,6 @@ // check-pass // edition: 2021 -#![allow(incomplete_features)] - trait MyTrait { #[allow(async_fn_in_trait)] async fn foo(&self) -> i32; diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs index 4e859fb27a9..8dc0574c757 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs @@ -2,8 +2,6 @@ // known-bug: #102682 // edition: 2021 -#![allow(incomplete_features)] - use std::fmt::Debug; use std::hash::Hash; diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr index d7251a52863..3cc35b21409 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics-and-bounds.rs:11:5 + --> $DIR/async-generics-and-bounds.rs:9:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Has | ++++ ++ ++ +++++++ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics-and-bounds.rs:11:5 + --> $DIR/async-generics-and-bounds.rs:9:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs index 2d342592848..6004916a4e5 100644 --- a/tests/ui/async-await/in-trait/async-generics.rs +++ b/tests/ui/async-await/in-trait/async-generics.rs @@ -2,8 +2,6 @@ // known-bug: #102682 // edition: 2021 -#![allow(incomplete_features)] - trait MyTrait<T, U> { async fn foo(&self) -> &(T, U); } diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr index aec62d12201..3b27f8fe2f0 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics.rs:8:5 + --> $DIR/async-generics.rs:6:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a; | ++++ ++ ++ +++++++++++ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics.rs:8:5 + --> $DIR/async-generics.rs:6:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs index ea8330a4b52..3721b01350d 100644 --- a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs @@ -1,8 +1,6 @@ // check-pass // edition: 2021 -#![allow(incomplete_features)] - use std::fmt::Debug; trait MyTrait<'a, 'b, T> { diff --git a/tests/ui/async-await/in-trait/async-lifetimes.rs b/tests/ui/async-await/in-trait/async-lifetimes.rs index 6e573b9cc8b..cb4b871cbe1 100644 --- a/tests/ui/async-await/in-trait/async-lifetimes.rs +++ b/tests/ui/async-await/in-trait/async-lifetimes.rs @@ -1,8 +1,6 @@ // check-pass // edition: 2021 -#![allow(incomplete_features)] - trait MyTrait<'a, 'b, T> { #[allow(async_fn_in_trait)] async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T); diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.rs b/tests/ui/async-await/in-trait/async-recursive-generic.rs index 34f1b09756e..c6031ce28d1 100644 --- a/tests/ui/async-await/in-trait/async-recursive-generic.rs +++ b/tests/ui/async-await/in-trait/async-recursive-generic.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![allow(incomplete_features)] - trait MyTrait<T> { async fn foo_recursive(&self, n: usize) -> T; } diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.stderr index 7c2df6683f0..cf0bcd741fc 100644 --- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr +++ b/tests/ui/async-await/in-trait/async-recursive-generic.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/async-recursive-generic.rs:10:5 + --> $DIR/async-recursive-generic.rs:8:5 | LL | async fn foo_recursive(&self, n: usize) -> T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` diff --git a/tests/ui/async-await/in-trait/async-recursive.rs b/tests/ui/async-await/in-trait/async-recursive.rs index ddf119b252f..09f1ffe499e 100644 --- a/tests/ui/async-await/in-trait/async-recursive.rs +++ b/tests/ui/async-await/in-trait/async-recursive.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![allow(incomplete_features)] - trait MyTrait { async fn foo_recursive(&self, n: usize) -> i32; } diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.stderr index 1253252cc40..b959652ea16 100644 --- a/tests/ui/async-await/in-trait/async-recursive.stderr +++ b/tests/ui/async-await/in-trait/async-recursive.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/async-recursive.rs:10:5 + --> $DIR/async-recursive.rs:8:5 | LL | async fn foo_recursive(&self, n: usize) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` diff --git a/tests/ui/async-await/in-trait/coherence-constrained.rs b/tests/ui/async-await/in-trait/coherence-constrained.rs new file mode 100644 index 00000000000..8e62b3e0e90 --- /dev/null +++ b/tests/ui/async-await/in-trait/coherence-constrained.rs @@ -0,0 +1,26 @@ +// edition: 2021 + +trait Foo { + type T; + + async fn foo(&self) -> Self::T; +} + +struct Bar; + +impl Foo for Bar { + type T = (); + + async fn foo(&self) {} + //~^ ERROR type annotations needed: cannot satisfy `<Bar as Foo>::T == ()` +} + +impl Foo for Bar { + //~^ ERROR conflicting implementations of trait `Foo` for type `Bar` + type T = (); + + async fn foo(&self) {} + //~^ ERROR type annotations needed: cannot satisfy `<Bar as Foo>::T == ()` +} + +fn main() {} diff --git a/tests/ui/async-await/in-trait/coherence-constrained.stderr b/tests/ui/async-await/in-trait/coherence-constrained.stderr new file mode 100644 index 00000000000..570a357ca8f --- /dev/null +++ b/tests/ui/async-await/in-trait/coherence-constrained.stderr @@ -0,0 +1,25 @@ +error[E0284]: type annotations needed: cannot satisfy `<Bar as Foo>::T == ()` + --> $DIR/coherence-constrained.rs:14:5 + | +LL | async fn foo(&self) {} + | ^^^^^^^^^^^^^^^^^^^ cannot satisfy `<Bar as Foo>::T == ()` + +error[E0284]: type annotations needed: cannot satisfy `<Bar as Foo>::T == ()` + --> $DIR/coherence-constrained.rs:22:5 + | +LL | async fn foo(&self) {} + | ^^^^^^^^^^^^^^^^^^^ cannot satisfy `<Bar as Foo>::T == ()` + +error[E0119]: conflicting implementations of trait `Foo` for type `Bar` + --> $DIR/coherence-constrained.rs:18:1 + | +LL | impl Foo for Bar { + | ---------------- first implementation here +... +LL | impl Foo for Bar { + | ^^^^^^^^^^^^^^^^ conflicting implementation for `Bar` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0119, E0284. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/async-await/in-trait/early-bound-1.rs b/tests/ui/async-await/in-trait/early-bound-1.rs index f79d6f23c93..ddcb477a1dc 100644 --- a/tests/ui/async-await/in-trait/early-bound-1.rs +++ b/tests/ui/async-await/in-trait/early-bound-1.rs @@ -1,8 +1,6 @@ // check-pass // edition:2021 -#![allow(incomplete_features)] - pub trait Foo { #[allow(async_fn_in_trait)] async fn foo(&mut self); diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr index 17b619ebee3..1cd8beac260 100644 --- a/tests/ui/async-await/issue-68112.stderr +++ b/tests/ui/async-await/issue-68112.stderr @@ -45,7 +45,7 @@ LL | require_send(send_fut); = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc<RefCell<i32>>` to implement `Send` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/issue-68112.rs:47:31 | LL | async fn ready2<T>(t: T) -> T { diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr index ab834daa85d..d0605d7e1a6 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.stderr @@ -18,7 +18,7 @@ note: required because it's used within this closure | LL | baz(|| async { | ^^ -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/issue-70935-complex-spans.rs:12:67 | LL | async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> { diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr index 3d6d1fb5c09..2a712aee9c4 100644 --- a/tests/ui/async-await/issues/issue-67893.stderr +++ b/tests/ui/async-await/issues/issue-67893.stderr @@ -13,7 +13,7 @@ LL | pub async fn run() { | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` = note: required because it captures the following types: `Arc<Mutex<()>>`, `MutexGuard<'_, ()>`, `impl Future<Output = ()>` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/auxiliary/issue_67893.rs:9:20 | LL | pub async fn run() { diff --git a/tests/ui/async-await/partial-drop-partial-reinit.rs b/tests/ui/async-await/partial-drop-partial-reinit.rs index 75acb442e7a..815cc916b41 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.rs +++ b/tests/ui/async-await/partial-drop-partial-reinit.rs @@ -26,7 +26,7 @@ impl Drop for NotSend { impl !Send for NotSend {} async fn foo() { - //~^ NOTE used within this `async fn` body + //~^ NOTE used within this `async` fn body //~| NOTE within this `impl Future let mut x = (NotSend {},); drop(x.0); diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr index d115c1b1cc4..310a2923955 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.stderr +++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr @@ -12,7 +12,7 @@ LL | async fn foo() { = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend` = note: required because it appears within the type `(NotSend,)` = note: required because it captures the following types: `(NotSend,)`, `impl Future<Output = ()>` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/partial-drop-partial-reinit.rs:28:16 | LL | async fn foo() { diff --git a/tests/ui/attributes/const-stability-on-macro.rs b/tests/ui/attributes/const-stability-on-macro.rs index 412af195d7a..af268ccd536 100644 --- a/tests/ui/attributes/const-stability-on-macro.rs +++ b/tests/ui/attributes/const-stability-on-macro.rs @@ -1,7 +1,7 @@ #![feature(staged_api)] #![stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "foo", since = "0")] +#[rustc_const_stable(feature = "foo", since = "3.3.3")] //~^ ERROR macros cannot have const stability attributes macro_rules! foo { () => {}; diff --git a/tests/ui/attributes/const-stability-on-macro.stderr b/tests/ui/attributes/const-stability-on-macro.stderr index c3da02c79cb..28f31e3d4f6 100644 --- a/tests/ui/attributes/const-stability-on-macro.stderr +++ b/tests/ui/attributes/const-stability-on-macro.stderr @@ -1,8 +1,8 @@ error: macros cannot have const stability attributes --> $DIR/const-stability-on-macro.rs:4:1 | -LL | #[rustc_const_stable(feature = "foo", since = "0")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute +LL | #[rustc_const_stable(feature = "foo", since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid const stability attribute LL | LL | macro_rules! foo { | ---------------- const stability attribute affects this macro diff --git a/tests/ui/attributes/statement-attribute-validation.rs b/tests/ui/attributes/statement-attribute-validation.rs new file mode 100644 index 00000000000..31407364acf --- /dev/null +++ b/tests/ui/attributes/statement-attribute-validation.rs @@ -0,0 +1,39 @@ +// test for #117058 - check that attributes are validated on various kinds of statements. + +struct A; + +fn func() {} + +fn main() { + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + if true { + } else { + } + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + (1); + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + match 1 { + _ => {} + } + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + while false {} + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + {} + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + A {}; + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + func(); + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + A; + #[allow(two-words)] + //~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` + loop {} +} diff --git a/tests/ui/attributes/statement-attribute-validation.stderr b/tests/ui/attributes/statement-attribute-validation.stderr new file mode 100644 index 00000000000..06f447be562 --- /dev/null +++ b/tests/ui/attributes/statement-attribute-validation.stderr @@ -0,0 +1,56 @@ +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:8:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:13:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:16:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:21:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:24:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:27:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:30:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:33:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/statement-attribute-validation.rs:36:16 + | +LL | #[allow(two-words)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/cast/ptr-to-ptr-different-regions.rs b/tests/ui/cast/ptr-to-ptr-different-regions.rs new file mode 100644 index 00000000000..5592e613ac1 --- /dev/null +++ b/tests/ui/cast/ptr-to-ptr-different-regions.rs @@ -0,0 +1,24 @@ +// check-pass + +// https://github.com/rust-lang/rust/issues/113257 + +#![deny(trivial_casts)] // The casts here are not trivial. + +struct Foo<'a> { a: &'a () } + +fn extend_lifetime_very_very_safely<'a>(v: *const Foo<'a>) -> *const Foo<'static> { + // This should pass because raw pointer casts can do anything they want. + v as *const Foo<'static> +} + +trait Trait {} + +fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) { + ptr as _ +} + +fn main() { + let unit = (); + let foo = Foo { a: &unit }; + let _long: *const Foo<'static> = extend_lifetime_very_very_safely(&foo); +} diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs index 20ff875491f..bce3b0fd729 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs +++ b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.rs @@ -6,5 +6,6 @@ trait NotObjectSafe { fn eq(&self, other: Self); } impl NotObjectSafe for dyn NotObjectSafe { } //~^ ERROR E0038 +//~| ERROR E0046 fn main() { } diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr index e9090c1b6bc..1dcc30ee652 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-trait-object-safe.stderr @@ -13,6 +13,15 @@ LL | trait NotObjectSafe { fn eq(&self, other: Self); } | this trait cannot be made into an object... = help: consider moving `eq` to another trait -error: aborting due to previous error +error[E0046]: not all trait items implemented, missing: `eq` + --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:1 + | +LL | trait NotObjectSafe { fn eq(&self, other: Self); } + | -------------------------- `eq` from trait +LL | impl NotObjectSafe for dyn NotObjectSafe { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `eq` in implementation + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0038`. +Some errors have detailed explanations: E0038, E0046. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs b/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs index 3acf0d8d39a..0e16d12a181 100644 --- a/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs +++ b/tests/ui/coherence/coherence-negative-outlives-lifetimes.rs @@ -1,5 +1,5 @@ // revisions: stock with_negative_coherence -//[with_negative_coherence] check-pass +//[with_negative_coherence] known-bug: unknown #![feature(negative_impls)] #![cfg_attr(with_negative_coherence, feature(with_negative_coherence))] diff --git a/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr b/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr new file mode 100644 index 00000000000..097cc4e0fe3 --- /dev/null +++ b/tests/ui/coherence/coherence-negative-outlives-lifetimes.with_negative_coherence.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_` + --> $DIR/coherence-negative-outlives-lifetimes.rs:14:1 + | +LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {} + | ---------------------------------------------- first implementation here +LL | impl<'a, T> MyTrait<'a> for &'a T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-overlap-trait-alias.rs b/tests/ui/coherence/coherence-overlap-trait-alias.rs index 9d9c76af91d..d42a666c54f 100644 --- a/tests/ui/coherence/coherence-overlap-trait-alias.rs +++ b/tests/ui/coherence/coherence-overlap-trait-alias.rs @@ -13,8 +13,6 @@ impl B for u32 {} trait C {} impl<T: AB> C for T {} impl C for u32 {} -//~^ ERROR -// FIXME it's giving an ungreat error but unsure if we care given that it's using an internal rustc -// attribute and an artificial code path for testing purposes +//~^ ERROR conflicting implementations of trait `C` for type `u32` fn main() {} diff --git a/tests/ui/coherence/coherence-overlap-trait-alias.stderr b/tests/ui/coherence/coherence-overlap-trait-alias.stderr index 668b8319b38..687f3af0040 100644 --- a/tests/ui/coherence/coherence-overlap-trait-alias.stderr +++ b/tests/ui/coherence/coherence-overlap-trait-alias.stderr @@ -1,17 +1,11 @@ -error[E0283]: type annotations needed: cannot satisfy `u32: C` - --> $DIR/coherence-overlap-trait-alias.rs:15:12 - | -LL | impl C for u32 {} - | ^^^ - | -note: multiple `impl`s satisfying `u32: C` found - --> $DIR/coherence-overlap-trait-alias.rs:14:1 +error[E0119]: conflicting implementations of trait `C` for type `u32` + --> $DIR/coherence-overlap-trait-alias.rs:15:1 | LL | impl<T: AB> C for T {} - | ^^^^^^^^^^^^^^^^^^^ + | ------------------- first implementation here LL | impl C for u32 {} - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ conflicting implementation for `u32` error: aborting due to previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/coherence-overlap-with-regions.rs b/tests/ui/coherence/coherence-overlap-with-regions.rs index 32f01f41801..9945c8e6cfd 100644 --- a/tests/ui/coherence/coherence-overlap-with-regions.rs +++ b/tests/ui/coherence/coherence-overlap-with-regions.rs @@ -1,4 +1,10 @@ -// check-pass +// known-bug: unknown + +// This fails because we currently perform negative coherence in coherence mode. +// This means that when looking for a negative predicate, we also assemble a +// coherence-unknowable predicate. Since confirming the negative impl has region +// obligations, we don't prefer the impl over the unknowable predicate +// unconditionally and instead flounder. #![feature(negative_impls)] #![feature(rustc_attrs)] diff --git a/tests/ui/coherence/coherence-overlap-with-regions.stderr b/tests/ui/coherence/coherence-overlap-with-regions.stderr new file mode 100644 index 00000000000..fd25f0978ba --- /dev/null +++ b/tests/ui/coherence/coherence-overlap-with-regions.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Bar` for type `&_` + --> $DIR/coherence-overlap-with-regions.rs:20:1 + | +LL | impl<T: Foo> Bar for T {} + | ---------------------- first implementation here +LL | impl<T> Bar for &T where T: 'static {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr b/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr new file mode 100644 index 00000000000..4cf50b4f208 --- /dev/null +++ b/tests/ui/coherence/negative-coherence-considering-regions.any_lt.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Bar` for type `&_` + --> $DIR/negative-coherence-considering-regions.rs:22:1 + | +LL | impl<T> Bar for T where T: Foo {} + | ------------------------------ first implementation here +... +LL | impl<T> Bar for &T {} + | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/negative-coherence-considering-regions.rs b/tests/ui/coherence/negative-coherence-considering-regions.rs new file mode 100644 index 00000000000..597a5972628 --- /dev/null +++ b/tests/ui/coherence/negative-coherence-considering-regions.rs @@ -0,0 +1,29 @@ +// revisions: any_lt static_lt +//[static_lt] known-bug: unknown + +// This fails because we currently perform negative coherence in coherence mode. +// This means that when looking for a negative predicate, we also assemble a +// coherence-unknowable predicate. Since confirming the negative impl has region +// obligations, we don't prefer the impl over the unknowable predicate +// unconditionally and instead flounder. + +#![feature(negative_impls)] +#![feature(with_negative_coherence)] + +trait Foo {} + +impl<T> !Foo for &'static T {} + +trait Bar {} + +impl<T> Bar for T where T: Foo {} + +#[cfg(any_lt)] +impl<T> Bar for &T {} +//[any_lt]~^ ERROR conflicting implementations of trait `Bar` for type `&_` + +#[cfg(static_lt)] +impl<T> Bar for &'static T {} + + +fn main() {} diff --git a/tests/ui/coherence/negative-coherence-considering-regions.static_lt.stderr b/tests/ui/coherence/negative-coherence-considering-regions.static_lt.stderr new file mode 100644 index 00000000000..87e7be2aa44 --- /dev/null +++ b/tests/ui/coherence/negative-coherence-considering-regions.static_lt.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `Bar` for type `&'static _` + --> $DIR/negative-coherence-considering-regions.rs:26:1 + | +LL | impl<T> Bar for T where T: Foo {} + | ------------------------------ first implementation here +... +LL | impl<T> Bar for &'static T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&'static _` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/const-arg-in-const-arg.rs b/tests/ui/const-generics/const-arg-in-const-arg.rs index 9eaa54347f1..c1a4c3dc348 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.rs +++ b/tests/ui/const-generics/const-arg-in-const-arg.rs @@ -1,5 +1,5 @@ // revisions: min -// we use a single revision because t his shoudl have a `full` revision +// we use a single revision because this should have a `full` revision // but right now that ICEs and I(@BoxyUwU) could not get stderr normalization to work #![cfg_attr(full, feature(generic_const_exprs))] diff --git a/tests/ui/const-generics/defaults/default-annotation.rs b/tests/ui/const-generics/defaults/default-annotation.rs index 7a9f5732f7f..587ad78e298 100644 --- a/tests/ui/const-generics/defaults/default-annotation.rs +++ b/tests/ui/const-generics/defaults/default-annotation.rs @@ -4,12 +4,12 @@ // FIXME(const_generics_defaults): It seems like we aren't testing the right thing here, // I would assume that we want the attributes to apply to the const parameter defaults // themselves. -#![stable(feature = "const_default_test", since="none")] +#![stable(feature = "const_default_test", since = "3.3.3")] -#[unstable(feature = "const_default_stable", issue="none")] +#[unstable(feature = "const_default_stable", issue = "none")] pub struct ConstDefaultUnstable<const N: usize = 3>; -#[stable(feature = "const_default_unstable", since="none")] +#[stable(feature = "const_default_unstable", since = "3.3.3")] pub struct ConstDefaultStable<const N: usize = { 3 }>; diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr index 4e1d71f1545..7ce2b9ac95a 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr @@ -5,12 +5,15 @@ LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` 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> - --> $DIR/object-safety-err-ret.rs:8:23 + --> $DIR/object-safety-err-ret.rs:8:8 | LL | trait Foo { | --- this trait cannot be made into an object... LL | fn test(&self) -> [u8; bar::<Self>()]; - | ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type + | ^^^^ ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type + | | + | ...because method `test` references the `Self` type in its `where` clause + = help: consider moving `test` to another trait = help: consider moving `test` to another trait error: aborting due to previous error diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs new file mode 100644 index 00000000000..5813f098184 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs @@ -0,0 +1,13 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Q { + const ASSOC: usize; +} + +impl<const N: u64> Q for [u8; N] {} +//~^ ERROR not all trait items implemented + +pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} + +pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr new file mode 100644 index 00000000000..0314d7ed23d --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `ASSOC` + --> $DIR/type_mismatch.rs:8:1 + | +LL | const ASSOC: usize; + | ------------------ `ASSOC` from trait +... +LL | impl<const N: u64> Q for [u8; N] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `ASSOC` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs index afe645ae881..6c4f0a5accf 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs @@ -11,4 +11,5 @@ fn main() { //[thir]~^^ call to unsafe function `foo` is unsafe and requires unsafe function or block foo(); //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block + //[thir]~^^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block } diff --git a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr index b313f06539f..e6b8173eb05 100644 --- a/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr +++ b/tests/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr @@ -1,4 +1,12 @@ error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block + --> $DIR/const-extern-fn-requires-unsafe.rs:12:5 + | +LL | foo(); + | ^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block --> $DIR/const-extern-fn-requires-unsafe.rs:9:17 | LL | let a: [u8; foo()]; @@ -6,6 +14,6 @@ LL | let a: [u8; foo()]; | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/consts/const-unsized.rs b/tests/ui/consts/const-unsized.rs index 319b8ef97de..e0b06a27109 100644 --- a/tests/ui/consts/const-unsized.rs +++ b/tests/ui/consts/const-unsized.rs @@ -2,15 +2,19 @@ use std::fmt::Debug; const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); //~^ ERROR the size for values of type +//~| ERROR the size for values of type const CONST_FOO: str = *"foo"; //~^ ERROR the size for values of type +//~| ERROR the size for values of type static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); //~^ ERROR the size for values of type +//~| ERROR the size for values of type static STATIC_BAR: str = *"bar"; //~^ ERROR the size for values of type +//~| ERROR the size for values of type fn main() { println!("{:?} {:?} {:?} {:?}", &CONST_0, &CONST_FOO, &STATIC_1, &STATIC_BAR); diff --git a/tests/ui/consts/const-unsized.stderr b/tests/ui/consts/const-unsized.stderr index 27b200648eb..674f0cb99e7 100644 --- a/tests/ui/consts/const-unsized.stderr +++ b/tests/ui/consts/const-unsized.stderr @@ -7,7 +7,7 @@ LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/const-unsized.rs:6:18 + --> $DIR/const-unsized.rs:7:18 | LL | const CONST_FOO: str = *"foo"; | ^^^ doesn't have a size known at compile-time @@ -15,7 +15,7 @@ LL | const CONST_FOO: str = *"foo"; = help: the trait `Sized` is not implemented for `str` error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time - --> $DIR/const-unsized.rs:9:18 + --> $DIR/const-unsized.rs:11:18 | LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -23,13 +23,49 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/const-unsized.rs:12:20 + --> $DIR/const-unsized.rs:15:20 | LL | static STATIC_BAR: str = *"bar"; | ^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` -error: aborting due to 4 previous errors +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time + --> $DIR/const-unsized.rs:3:35 + | +LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` + = note: constant expressions must have a statically known size + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/const-unsized.rs:7:24 + | +LL | const CONST_FOO: str = *"foo"; + | ^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: constant expressions must have a statically known size + +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time + --> $DIR/const-unsized.rs:11:37 + | +LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` + = note: constant expressions must have a statically known size + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/const-unsized.rs:15:26 + | +LL | static STATIC_BAR: str = *"bar"; + | ^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: constant expressions must have a statically known size + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/deprecation/staged-deprecation-in-future.rs b/tests/ui/deprecation/staged-deprecation-in-future.rs index 87b15ec303c..49ee60b9bd0 100644 --- a/tests/ui/deprecation/staged-deprecation-in-future.rs +++ b/tests/ui/deprecation/staged-deprecation-in-future.rs @@ -2,14 +2,14 @@ #![feature(staged_api)] -#![stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] +#![stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")] #[deprecated(since = "99.99.99", note = "effectively never")] -#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] +#[stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")] pub struct S1; #[deprecated(since = "TBD", note = "literally never")] -#[stable(feature = "rustc_deprecation-in-future-test", since = "1.0.0")] +#[stable(feature = "rustc_deprecation_in_future_test", since = "1.0.0")] pub struct S2; fn main() { diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index 00fb59d14d7..346d8373f73 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -23,9 +23,15 @@ trait Boom {} //~^WARN malformed `on_unimplemented` attribute trait Doom {} +#[diagnostic::on_unimplemented] +//~^WARN missing options for `on_unimplemented` attribute +//~|WARN missing options for `on_unimplemented` attribute +trait Whatever {} + fn take_foo(_: impl Foo) {} fn take_baz(_: impl Baz) {} fn take_boom(_: impl Boom) {} +fn take_whatever(_: impl Whatever) {} fn main() { take_foo(1_i32); @@ -34,4 +40,6 @@ fn main() { //~^ERROR Boom take_boom(1_i32); //~^ERROR Boom + take_whatever(1_i32); + //~^ERROR the trait bound `i32: Whatever` is not satisfied } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index bd39c91ffe8..162ddd79fbb 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -10,36 +10,53 @@ warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32 | LL | #[diagnostic::on_unimplemented = "boom"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + +warning: missing options for `on_unimplemented` attribute + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + | +LL | #[diagnostic::on_unimplemented] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:14 | LL | take_foo(1_i32); | -------- ^^^^^ the trait `Foo` is not implemented for `i32` @@ -52,7 +69,7 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `take_foo` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` @@ -61,12 +78,13 @@ warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:14 | LL | take_baz(1_i32); | -------- ^^^^^ the trait `Baz` is not implemented for `i32` @@ -79,7 +97,7 @@ help: this trait has no implementations, consider adding one LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `take_baz` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:21 | LL | fn take_baz(_: impl Baz) {} | ^^^ required by this bound in `take_baz` @@ -88,12 +106,13 @@ warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:15 | LL | take_boom(1_i32); | --------- ^^^^^ the trait `Boom` is not implemented for `i32` @@ -106,11 +125,39 @@ help: this trait has no implementations, consider adding one LL | trait Boom {} | ^^^^^^^^^^ note: required by a bound in `take_boom` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:28:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:22 | LL | fn take_boom(_: impl Boom) {} | ^^^^ required by this bound in `take_boom` -error: aborting due to 3 previous errors; 8 warnings emitted +warning: missing options for `on_unimplemented` attribute + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + | +LL | #[diagnostic::on_unimplemented] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `i32: Whatever` is not satisfied + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:19 + | +LL | take_whatever(1_i32); + | ------------- ^^^^^ the trait `Whatever` is not implemented for `i32` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1 + | +LL | trait Whatever {} + | ^^^^^^^^^^^^^^ +note: required by a bound in `take_whatever` + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:26 + | +LL | fn take_whatever(_: impl Whatever) {} + | ^^^^^^^^ required by this bound in `take_whatever` + +error: aborting due to 4 previous errors; 10 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs index 35307586391..8410b3eb105 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -1,22 +1,20 @@ #![feature(diagnostic_namespace)] #[diagnostic::on_unimplemented( + if(Self = "()"), //~^WARN malformed `on_unimplemented` attribute //~|WARN malformed `on_unimplemented` attribute - if(Self = ()), - message = "not used yet", - label = "not used yet", - note = "not used yet" + message = "custom message", + note = "custom note" )] #[diagnostic::on_unimplemented(message = "fallback!!")] #[diagnostic::on_unimplemented(label = "fallback label")] #[diagnostic::on_unimplemented(note = "fallback note")] -#[diagnostic::on_unimplemented(message = "fallback2!!")] trait Foo {} fn takes_foo(_: impl Foo) {} fn main() { takes_foo(()); - //~^ERROR fallback!! + //~^ERROR custom message } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr index 6a83d8e39c6..7860e540589 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -1,33 +1,23 @@ warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | -LL | / #[diagnostic::on_unimplemented( -LL | | -LL | | -LL | | if(Self = ()), -... | -LL | | note = "not used yet" -LL | | )] - | |__^ +LL | if(Self = "()"), + | ^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | -LL | / #[diagnostic::on_unimplemented( -LL | | -LL | | -LL | | if(Self = ()), -... | -LL | | note = "not used yet" -LL | | )] - | |__^ +LL | if(Self = "()"), + | ^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: fallback!! - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15 +error[E0277]: custom message + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15 | LL | takes_foo(()); | --------- ^^ fallback label @@ -35,14 +25,14 @@ LL | takes_foo(()); | required by a bound introduced by this call | = help: the trait `Foo` is not implemented for `()` - = note: fallback note + = note: custom note help: this trait has no implementations, consider adding one - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` diff --git a/tests/ui/feature-gates/feature-gate-staged_api.rs b/tests/ui/feature-gates/feature-gate-staged_api.rs index 2571ab5d1b4..ce6b218dd7d 100644 --- a/tests/ui/feature-gates/feature-gate-staged_api.rs +++ b/tests/ui/feature-gates/feature-gate-staged_api.rs @@ -1,11 +1,11 @@ -#![stable(feature = "a", since = "b")] +#![stable(feature = "a", since = "3.3.3")] //~^ ERROR stability attributes may not be used outside of the standard library mod inner_private_module { // UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here pub type UnnameableTypeAlias = u8; } -#[stable(feature = "a", since = "b")] +#[stable(feature = "a", since = "3.3.3")] //~^ ERROR stability attributes may not be used outside of the standard library pub fn f() -> inner_private_module::UnnameableTypeAlias { 0 diff --git a/tests/ui/feature-gates/feature-gate-staged_api.stderr b/tests/ui/feature-gates/feature-gate-staged_api.stderr index 951bb5a1740..1a9fcb02b0d 100644 --- a/tests/ui/feature-gates/feature-gate-staged_api.stderr +++ b/tests/ui/feature-gates/feature-gate-staged_api.stderr @@ -1,14 +1,14 @@ error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/feature-gate-staged_api.rs:8:1 | -LL | #[stable(feature = "a", since = "b")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[stable(feature = "a", since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0734]: stability attributes may not be used outside of the standard library --> $DIR/feature-gate-staged_api.rs:1:1 | -LL | #![stable(feature = "a", since = "b")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![stable(feature = "a", since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/issue-84931.rs b/tests/ui/generic-associated-types/issue-84931.rs index 4123ce9d4d9..2ef990a7a90 100644 --- a/tests/ui/generic-associated-types/issue-84931.rs +++ b/tests/ui/generic-associated-types/issue-84931.rs @@ -12,7 +12,8 @@ struct StreamingSliceIter<'a, T> { impl<'b, T: 'b> StreamingIter for StreamingSliceIter<'b, T> { type Item<'a> = &'a mut T; - //~^ the parameter type + //~^ ERROR: the parameter type + //~| ERROR: does not fulfill the required lifetime fn next(&mut self) -> Option<&mut T> { loop {} } diff --git a/tests/ui/generic-associated-types/issue-84931.stderr b/tests/ui/generic-associated-types/issue-84931.stderr index fe9932c205a..04e14b9c746 100644 --- a/tests/ui/generic-associated-types/issue-84931.stderr +++ b/tests/ui/generic-associated-types/issue-84931.stderr @@ -11,6 +11,26 @@ help: consider adding an explicit lifetime bound LL | type Item<'a> = &'a mut T where T: 'a; | +++++++++++ -error: aborting due to previous error +error[E0477]: the type `StreamingSliceIter<'b, T>` does not fulfill the required lifetime + --> $DIR/issue-84931.rs:14:21 + | +LL | type Item<'a> where Self: 'a; + | ------------- definition of `Item` from trait +... +LL | type Item<'a> = &'a mut T; + | ^^^^^^^^^ + | +note: type must outlive the lifetime `'a` as defined here + --> $DIR/issue-84931.rs:14:15 + | +LL | type Item<'a> = &'a mut T; + | ^^ +help: copy the `where` clause predicates from the trait + | +LL | type Item<'a> = &'a mut T where Self: 'a; + | ++++++++++++++ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0309`. +Some errors have detailed explanations: E0309, E0477. +For more information about an error, try `rustc --explain E0309`. diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs index 060ee8821d8..a3f3b1a6d4d 100644 --- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs +++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs @@ -7,6 +7,7 @@ pub trait X { impl X for () { type Y<'a> = &'a (); + //~^ ERROR lifetime bound not satisfied } struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> { diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr index a69cd0028c1..f73ed5956da 100644 --- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr +++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr @@ -12,44 +12,64 @@ LL | #![warn(unused_lifetimes)] | ^^^^^^^^^^^^^^^^ error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:13:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:14:8 | LL | f: <T as X>::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:12:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:13:10 | LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:18:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:19:8 | LL | f: <T as X>::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:17:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:18:10 | LL | struct C<'a, T: X> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:23:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:24:8 | LL | f: <() as X>::Y<'a>, | ^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:22:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:23:10 | LL | struct D<'a> { | ^^ = note: but lifetime parameter must outlive the static lifetime -error: aborting due to 3 previous errors; 1 warning emitted +error[E0478]: lifetime bound not satisfied + --> $DIR/unsatisfied-item-lifetime-bound.rs:9:18 + | +LL | type Y<'a: 'static>; + | ------------------- definition of `Y` from trait +... +LL | type Y<'a> = &'a (); + | ^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'a` as defined here + --> $DIR/unsatisfied-item-lifetime-bound.rs:9:12 + | +LL | type Y<'a> = &'a (); + | ^^ + = note: but lifetime parameter must outlive the static lifetime +help: copy the `where` clause predicates from the trait + | +LL | type Y<'a> = &'a () where 'a: 'static; + | +++++++++++++++++ + +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0478`. diff --git a/tests/ui/impl-trait/in-trait/deep-match.rs b/tests/ui/impl-trait/in-trait/deep-match.rs index 02889347ba4..82eac7760fc 100644 --- a/tests/ui/impl-trait/in-trait/deep-match.rs +++ b/tests/ui/impl-trait/in-trait/deep-match.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - struct Wrapper<T>(T); trait Foo { diff --git a/tests/ui/impl-trait/in-trait/deep-match.stderr b/tests/ui/impl-trait/in-trait/deep-match.stderr index 9cfc54f5094..a658d8fa078 100644 --- a/tests/ui/impl-trait/in-trait/deep-match.stderr +++ b/tests/ui/impl-trait/in-trait/deep-match.stderr @@ -1,5 +1,5 @@ error[E0053]: method `bar` has an incompatible return type for trait - --> $DIR/deep-match.rs:10:17 + --> $DIR/deep-match.rs:8:17 | LL | fn bar() -> i32 { | ^^^ diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs index 977ff8111dd..ac7a50a365e 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - use std::ops::Deref; pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr index 3d9ca62b0db..596ff101155 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String` - --> $DIR/default-body-type-err.rs:6:22 + --> $DIR/default-body-type-err.rs:4:22 | LL | fn lol(&self) -> impl Deref<Target = String> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String` diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs index 5a53c9a19b5..0ac60918b67 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - trait Foo { fn bar() -> impl std::fmt::Display; } diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr index cb9ecc7fa48..cd45c6a9c6d 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr @@ -1,5 +1,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` - --> $DIR/doesnt-satisfy.rs:8:17 + --> $DIR/doesnt-satisfy.rs:6:17 | LL | fn bar() -> () {} | ^^ `()` cannot be formatted with the default formatter @@ -7,7 +7,7 @@ LL | fn bar() -> () {} = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Foo::{opaque#0}` - --> $DIR/doesnt-satisfy.rs:4:22 + --> $DIR/doesnt-satisfy.rs:2:22 | LL | fn bar() -> impl std::fmt::Display; | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::{opaque#0}` diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs index 2e5373dbd5d..3ea31cc9347 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - struct U; trait Foo { diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr index 3dbf2235c5e..043dbc8db5d 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/generics-mismatch.rs:10:12 + --> $DIR/generics-mismatch.rs:8:12 | LL | fn bar(&self) -> impl Sized; | - expected 0 type parameters diff --git a/tests/ui/impl-trait/in-trait/issue-102140.rs b/tests/ui/impl-trait/in-trait/issue-102140.rs index 1132bd25f81..7960018482f 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.rs +++ b/tests/ui/impl-trait/in-trait/issue-102140.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - trait Marker {} impl Marker for u32 {} diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr index 6d50d2f3a24..9cd2cdfd1a5 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/issue-102140.rs:22:22 + --> $DIR/issue-102140.rs:20:22 | LL | MyTrait::foo(&self) | ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` @@ -13,7 +13,7 @@ LL + MyTrait::foo(self) | error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/issue-102140.rs:22:9 + --> $DIR/issue-102140.rs:20:9 | LL | MyTrait::foo(&self) | ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` @@ -21,7 +21,7 @@ LL | MyTrait::foo(&self) = help: the trait `MyTrait` is implemented for `Outer` error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/issue-102140.rs:22:9 + --> $DIR/issue-102140.rs:20:9 | LL | MyTrait::foo(&self) | ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs index 4534753f0d2..4fa3fdd31b5 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.rs +++ b/tests/ui/impl-trait/in-trait/issue-102571.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - use std::fmt::Display; use std::ops::Deref; diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr index 4d1a0feb22b..872988faf7a 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-102571.rs:11:9 + --> $DIR/issue-102571.rs:9:9 | LL | let () = t.bar(); | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs index 15634537dae..5cca4ad839c 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - use std::fmt::Debug; trait Foo { diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr index 8d882391251..3271cb18d9f 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:16:33 + --> $DIR/object-safety.rs:14:33 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^ `Foo` 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> - --> $DIR/object-safety.rs:6:22 + --> $DIR/object-safety.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -14,13 +14,13 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:19:15 + --> $DIR/object-safety.rs:17:15 | LL | let s = i.baz(); | ^^^ `Foo` 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> - --> $DIR/object-safety.rs:6:22 + --> $DIR/object-safety.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -29,13 +29,13 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:19:13 + --> $DIR/object-safety.rs:17:13 | LL | let s = i.baz(); | ^^^^^^^ `Foo` 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> - --> $DIR/object-safety.rs:6:22 + --> $DIR/object-safety.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -44,13 +44,13 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:16:13 + --> $DIR/object-safety.rs:14:13 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^^^^^ `Foo` 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> - --> $DIR/object-safety.rs:6:22 + --> $DIR/object-safety.rs:4:22 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs index fc708536b0f..1f18bb3b774 100644 --- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - use std::fmt::Display; trait Foo { diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr index 99b62e80acd..e260762d89f 100644 --- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/opaque-in-impl-is-opaque.rs:16:19 + --> $DIR/opaque-in-impl-is-opaque.rs:14:19 | LL | fn bar(&self) -> impl Display { | ------------ the found opaque type diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs index c905bfce852..d9fac0238e1 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] - struct S; trait Foo { diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr index e904548742d..2836e9c7821 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/trait-more-generics-than-impl.rs:10:11 + --> $DIR/trait-more-generics-than-impl.rs:8:11 | LL | fn bar<T>() -> impl Sized; | - expected 1 type parameter diff --git a/tests/ui/impl-trait/negative-reasoning.stderr b/tests/ui/impl-trait/negative-reasoning.stderr index 6b8cc9e7374..ddce5e7ece2 100644 --- a/tests/ui/impl-trait/negative-reasoning.stderr +++ b/tests/ui/impl-trait/negative-reasoning.stderr @@ -7,7 +7,7 @@ LL | impl<T: std::fmt::Debug> AnotherTrait for T {} LL | impl AnotherTrait for D<OpaqueType> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` | - = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions + = note: upstream crates may add a new impl of trait `std::marker::FnPtr` for type `OpaqueType` in future versions error: aborting due to previous error diff --git a/tests/ui/impl-unused-tps.rs b/tests/ui/impl-unused-tps.rs index 7cc1ae613bc..3eb9daedf76 100644 --- a/tests/ui/impl-unused-tps.rs +++ b/tests/ui/impl-unused-tps.rs @@ -1,3 +1,5 @@ +//~ ERROR overflow evaluating the requirement `([isize; 0], _): Sized + trait Foo<A> { fn get(&self, A: &A) { } } @@ -23,8 +25,7 @@ impl<T:Bar<Out=U>,U> Foo<T> for [isize;3] { } impl<T,U> Foo<T> for U { - // OK, T, U are used everywhere. Note that the coherence check - // hasn't executed yet, so no errors about overlap. + //~^ ERROR conflicting implementations of trait `Foo<_>` for type `[isize; 0]` } impl<T,U> Bar for T { diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/impl-unused-tps.stderr index 053ab91c893..93215326c2f 100644 --- a/tests/ui/impl-unused-tps.stderr +++ b/tests/ui/impl-unused-tps.stderr @@ -1,33 +1,56 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:13:8 + --> $DIR/impl-unused-tps.rs:15:8 | LL | impl<T,U> Foo<T> for [isize;1] { | ^ unconstrained type parameter error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:30:8 + --> $DIR/impl-unused-tps.rs:31:8 | LL | impl<T,U> Bar for T { | ^ unconstrained type parameter error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:38:8 + --> $DIR/impl-unused-tps.rs:39:8 | LL | impl<T,U> Bar for T | ^ unconstrained type parameter error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:46:8 + --> $DIR/impl-unused-tps.rs:47:8 | LL | impl<T,U,V> Foo<T> for T | ^ unconstrained type parameter error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates - --> $DIR/impl-unused-tps.rs:46:10 + --> $DIR/impl-unused-tps.rs:47:10 | LL | impl<T,U,V> Foo<T> for T | ^ unconstrained type parameter -error: aborting due to 5 previous errors +error[E0119]: conflicting implementations of trait `Foo<_>` for type `[isize; 0]` + --> $DIR/impl-unused-tps.rs:27:1 + | +LL | impl<T> Foo<T> for [isize;0] { + | ---------------------------- first implementation here +... +LL | impl<T,U> Foo<T> for U { + | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]` + +error[E0275]: overflow evaluating the requirement `([isize; 0], _): Sized` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`impl_unused_tps`) +note: required for `([isize; 0], _)` to implement `Bar` + --> $DIR/impl-unused-tps.rs:31:11 + | +LL | impl<T,U> Bar for T { + | - ^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: 126 redundant requirements hidden + = note: required for `([isize; 0], _)` to implement `Bar` + +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0207`. +Some errors have detailed explanations: E0119, E0207, E0275. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index 15477fb6f10..d2a0f436c42 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -6,14 +6,14 @@ LL | use empty::issue_56125; | help: consider importing one of these items instead | +LL | use ::issue_56125::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use ::issue_56125::last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use ::issue_56125::non_last_segment::non_last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use crate::m3::last_segment::issue_56125; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use crate::m3::non_last_segment::non_last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use issue_56125::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use issue_56125::last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ and 1 other candidate error[E0659]: `issue_56125` is ambiguous diff --git a/tests/ui/inline-const/expr-unsafe.thir.stderr b/tests/ui/inline-const/expr-unsafe.thir.stderr index 4737444fb61..1ab6e42fba0 100644 --- a/tests/ui/inline-const/expr-unsafe.thir.stderr +++ b/tests/ui/inline-const/expr-unsafe.thir.stderr @@ -1,9 +1,6 @@ warning: unnecessary `unsafe` block --> $DIR/expr-unsafe.rs:12:13 | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block | diff --git a/tests/ui/inline-const/pat-unsafe-err.rs b/tests/ui/inline-const/pat-unsafe-err.rs index e290b438c51..6df281c6d94 100644 --- a/tests/ui/inline-const/pat-unsafe-err.rs +++ b/tests/ui/inline-const/pat-unsafe-err.rs @@ -1,11 +1,13 @@ -// ignore-test This is currently broken // revisions: mir thir +// [mir]ignore-test This is currently broken // [thir]compile-flags: -Z thir-unsafeck #![allow(incomplete_features)] #![feature(inline_const_pat)] -const unsafe fn require_unsafe() -> usize { 1 } +const unsafe fn require_unsafe() -> usize { + 1 +} fn main() { match () { @@ -14,4 +16,12 @@ fn main() { //~^ ERROR [E0133] } => (), } + + match 1 { + const { + require_unsafe() + //~^ ERROR [E0133] + }..=4 => (), + _ => (), + } } diff --git a/tests/ui/inline-const/pat-unsafe-err.thir.stderr b/tests/ui/inline-const/pat-unsafe-err.thir.stderr new file mode 100644 index 00000000000..48a2cb4c704 --- /dev/null +++ b/tests/ui/inline-const/pat-unsafe-err.thir.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block + --> $DIR/pat-unsafe-err.rs:15:13 + | +LL | require_unsafe(); + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block + --> $DIR/pat-unsafe-err.rs:22:13 + | +LL | require_unsafe() + | ^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/inline-const/pat-unsafe.rs b/tests/ui/inline-const/pat-unsafe.rs index bcf7f6e0180..36f8632af67 100644 --- a/tests/ui/inline-const/pat-unsafe.rs +++ b/tests/ui/inline-const/pat-unsafe.rs @@ -1,13 +1,15 @@ -// ignore-test This is currently broken // check-pass // revisions: mir thir +// [mir]ignore-test This is currently broken // [thir]compile-flags: -Z thir-unsafeck #![allow(incomplete_features)] #![warn(unused_unsafe)] #![feature(inline_const_pat)] -const unsafe fn require_unsafe() -> usize { 1 } +const unsafe fn require_unsafe() -> usize { + 1 +} fn main() { unsafe { @@ -18,5 +20,14 @@ fn main() { //~^ WARNING unnecessary `unsafe` block } => (), } + + match 1 { + const { + unsafe {} + //~^ WARNING unnecessary `unsafe` block + require_unsafe() + }..=4 => (), + _ => (), + } } } diff --git a/tests/ui/inline-const/pat-unsafe.thir.stderr b/tests/ui/inline-const/pat-unsafe.thir.stderr new file mode 100644 index 00000000000..0318b3ff2cc --- /dev/null +++ b/tests/ui/inline-const/pat-unsafe.thir.stderr @@ -0,0 +1,20 @@ +warning: unnecessary `unsafe` block + --> $DIR/pat-unsafe.rs:19:17 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/pat-unsafe.rs:7:9 + | +LL | #![warn(unused_unsafe)] + | ^^^^^^^^^^^^^ + +warning: unnecessary `unsafe` block + --> $DIR/pat-unsafe.rs:26:17 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +warning: 2 warnings emitted + diff --git a/tests/ui/instrument-coverage/bad-value.bad.stderr b/tests/ui/instrument-coverage/bad-value.bad.stderr index 246c4f31a4b..b867d169dae 100644 --- a/tests/ui/instrument-coverage/bad-value.bad.stderr +++ b/tests/ui/instrument-coverage/bad-value.bad.stderr @@ -1,2 +1,2 @@ -error: incorrect value `bad-value` for codegen option `instrument-coverage` - `all` (default), `except-unused-generics`, `except-unused-functions`, or `off` was expected +error: incorrect value `bad-value` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected diff --git a/tests/ui/instrument-coverage/bad-value.blank.stderr b/tests/ui/instrument-coverage/bad-value.blank.stderr index b539c558d9b..e7122fb61cd 100644 --- a/tests/ui/instrument-coverage/bad-value.blank.stderr +++ b/tests/ui/instrument-coverage/bad-value.blank.stderr @@ -1,2 +1,2 @@ -error: incorrect value `` for codegen option `instrument-coverage` - `all` (default), `except-unused-generics`, `except-unused-functions`, or `off` was expected +error: incorrect value `` for codegen option `instrument-coverage` - `all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off` was expected diff --git a/tests/ui/instrument-coverage/except-unused-functions.rs b/tests/ui/instrument-coverage/except-unused-functions.rs deleted file mode 100644 index 5a0b7d4fef9..00000000000 --- a/tests/ui/instrument-coverage/except-unused-functions.rs +++ /dev/null @@ -1,3 +0,0 @@ -// compile-flags: -Cinstrument-coverage=except-unused-functions - -fn main() {} diff --git a/tests/ui/instrument-coverage/except-unused-functions.stderr b/tests/ui/instrument-coverage/except-unused-functions.stderr deleted file mode 100644 index 82c1c630cbf..00000000000 --- a/tests/ui/instrument-coverage/except-unused-functions.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: `-C instrument-coverage=except-*` requires `-Z unstable-options` - diff --git a/tests/ui/instrument-coverage/except-unused-generics.rs b/tests/ui/instrument-coverage/except-unused-generics.rs deleted file mode 100644 index 4b1ddf29026..00000000000 --- a/tests/ui/instrument-coverage/except-unused-generics.rs +++ /dev/null @@ -1,3 +0,0 @@ -// compile-flags: -Cinstrument-coverage=except-unused-generics - -fn main() {} diff --git a/tests/ui/instrument-coverage/except-unused-generics.stderr b/tests/ui/instrument-coverage/except-unused-generics.stderr deleted file mode 100644 index 82c1c630cbf..00000000000 --- a/tests/ui/instrument-coverage/except-unused-generics.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: `-C instrument-coverage=except-*` requires `-Z unstable-options` - diff --git a/tests/ui/instrument-coverage/unstable.branch.stderr b/tests/ui/instrument-coverage/unstable.branch.stderr new file mode 100644 index 00000000000..acc633a2a6d --- /dev/null +++ b/tests/ui/instrument-coverage/unstable.branch.stderr @@ -0,0 +1,2 @@ +error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options` + diff --git a/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr b/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr new file mode 100644 index 00000000000..acc633a2a6d --- /dev/null +++ b/tests/ui/instrument-coverage/unstable.except-unused-functions.stderr @@ -0,0 +1,2 @@ +error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options` + diff --git a/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr b/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr new file mode 100644 index 00000000000..acc633a2a6d --- /dev/null +++ b/tests/ui/instrument-coverage/unstable.except-unused-generics.stderr @@ -0,0 +1,2 @@ +error: `-C instrument-coverage=branch` and `-C instrument-coverage=except-*` require `-Z unstable-options` + diff --git a/tests/ui/instrument-coverage/unstable.rs b/tests/ui/instrument-coverage/unstable.rs new file mode 100644 index 00000000000..c16bcd0bf6d --- /dev/null +++ b/tests/ui/instrument-coverage/unstable.rs @@ -0,0 +1,6 @@ +// revisions: branch except-unused-functions except-unused-generics +// [branch] compile-flags: -Cinstrument-coverage=branch +// [except-unused-functions] compile-flags: -Cinstrument-coverage=except-unused-functions +// [except-unused-generics] compile-flags: -Cinstrument-coverage=except-unused-generics + +fn main() {} diff --git a/tests/ui/issues/issue-19380.rs b/tests/ui/issues/issue-19380.rs index 5c10e2067e4..fce737cba18 100644 --- a/tests/ui/issues/issue-19380.rs +++ b/tests/ui/issues/issue-19380.rs @@ -14,5 +14,6 @@ struct Bar { const FOO : Foo = Foo; const BAR : Bar = Bar { foos: &[&FOO]}; +//~^ ERROR E0038 fn main() { } diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr index b2aeb5edf29..37e280fbcc7 100644 --- a/tests/ui/issues/issue-19380.stderr +++ b/tests/ui/issues/issue-19380.stderr @@ -20,6 +20,29 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o LL | fn qiz() where Self: Sized; | +++++++++++++++++ -error: aborting due to previous error +error[E0038]: the trait `Qiz` cannot be made into an object + --> $DIR/issue-19380.rs:16:33 + | +LL | const BAR : Bar = Bar { foos: &[&FOO]}; + | ^^^^ `Qiz` 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> + --> $DIR/issue-19380.rs:2:6 + | +LL | trait Qiz { + | --- this trait cannot be made into an object... +LL | fn qiz(); + | ^^^ ...because associated function `qiz` has no `self` parameter + = note: required for the cast from `&Foo` to `&'static (dyn Qiz + 'static)` +help: consider turning `qiz` into a method by giving it a `&self` argument + | +LL | fn qiz(&self); + | +++++ +help: alternatively, consider constraining `qiz` so it does not apply to trait objects + | +LL | fn qiz() where Self: Sized; + | +++++++++++++++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-24446.rs b/tests/ui/issues/issue-24446.rs index 9ab952ade9c..6cf8846506d 100644 --- a/tests/ui/issues/issue-24446.rs +++ b/tests/ui/issues/issue-24446.rs @@ -2,6 +2,8 @@ fn main() { static foo: dyn Fn() -> u32 = || -> u32 { //~^ ERROR the size for values of type //~| ERROR cannot be shared between threads safely + //~| ERROR the size for values of type + //~| ERROR mismatched types 0 }; } diff --git a/tests/ui/issues/issue-24446.stderr b/tests/ui/issues/issue-24446.stderr index 72d528f1619..9c206e5ef3c 100644 --- a/tests/ui/issues/issue-24446.stderr +++ b/tests/ui/issues/issue-24446.stderr @@ -15,6 +15,39 @@ LL | static foo: dyn Fn() -> u32 = || -> u32 { | = help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)` -error: aborting due to 2 previous errors +error[E0277]: the size for values of type `(dyn Fn() -> u32 + 'static)` cannot be known at compilation time + --> $DIR/issue-24446.rs:2:35 + | +LL | static foo: dyn Fn() -> u32 = || -> u32 { + | ___________________________________^ +LL | | +LL | | +LL | | +LL | | +LL | | 0 +LL | | }; + | |_____^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)` + = note: constant expressions must have a statically known size + +error[E0308]: mismatched types + --> $DIR/issue-24446.rs:2:35 + | +LL | static foo: dyn Fn() -> u32 = || -> u32 { + | ___________________________________^ +LL | | +LL | | +LL | | +LL | | +LL | | 0 +LL | | }; + | |_____^ expected `dyn Fn`, found closure + | + = note: expected trait object `(dyn Fn() -> u32 + 'static)` + found closure `{closure@$DIR/issue-24446.rs:2:35: 2:44}` + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-77919.rs b/tests/ui/issues/issue-77919.rs index 3cbf493afb8..bf603314977 100644 --- a/tests/ui/issues/issue-77919.rs +++ b/tests/ui/issues/issue-77919.rs @@ -10,3 +10,4 @@ struct Multiply<N, M> { } impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} //~^ ERROR cannot find type `VAL` in this scope +//~| ERROR not all trait items implemented diff --git a/tests/ui/issues/issue-77919.stderr b/tests/ui/issues/issue-77919.stderr index 9d2f859e05a..dbbe70ff069 100644 --- a/tests/ui/issues/issue-77919.stderr +++ b/tests/ui/issues/issue-77919.stderr @@ -20,6 +20,16 @@ help: you might be missing a type parameter LL | impl<N, M, VAL> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} | +++++ -error: aborting due to 2 previous errors +error[E0046]: not all trait items implemented, missing: `VAL` + --> $DIR/issue-77919.rs:11:1 + | +LL | const VAL: T; + | ------------ `VAL` from trait +... +LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0046, E0412. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/layout/issue-84108.rs b/tests/ui/layout/issue-84108.rs index dd025c9b443..af21d1d6210 100644 --- a/tests/ui/layout/issue-84108.rs +++ b/tests/ui/layout/issue-84108.rs @@ -9,6 +9,8 @@ static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42); const BAR: (&Path, [u8], usize) = ("hello", [], 42); //~^ ERROR cannot find type `Path` in this scope //~| ERROR the size for values of type `[u8]` cannot be known at compilation time +//~| ERROR mismatched types static BAZ: ([u8], usize) = ([], 0); //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time +//~| ERROR mismatched types diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr index 5ad450bed07..3a02e73f96b 100644 --- a/tests/ui/layout/issue-84108.stderr +++ b/tests/ui/layout/issue-84108.stderr @@ -30,7 +30,7 @@ LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/issue-84108.rs:13:13 + --> $DIR/issue-84108.rs:14:13 | LL | static BAZ: ([u8], usize) = ([], 0); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -38,7 +38,25 @@ LL | static BAZ: ([u8], usize) = ([], 0); = help: the trait `Sized` is not implemented for `[u8]` = note: only the last element of a tuple may have a dynamically sized type -error: aborting due to 4 previous errors +error[E0308]: mismatched types + --> $DIR/issue-84108.rs:9:45 + | +LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); + | ^^ expected `[u8]`, found `[_; 0]` + | + = note: expected slice `[u8]` + found array `[_; 0]` + +error[E0308]: mismatched types + --> $DIR/issue-84108.rs:14:30 + | +LL | static BAZ: ([u8], usize) = ([], 0); + | ^^ expected `[u8]`, found `[_; 0]` + | + = note: expected slice `[u8]` + found array `[_; 0]` + +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0277, E0412. +Some errors have detailed explanations: E0277, E0308, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr index 30afcecf827..e61158a5d4d 100644 --- a/tests/ui/lifetimes/issue-26638.stderr +++ b/tests/ui/lifetimes/issue-26638.stderr @@ -44,6 +44,10 @@ LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.ne | = note: expected reference `&str` found enum `Option<&str>` +help: consider using `Option::expect` to unwrap the `Option<&str>` value, panicking if the value is an `Option::None` + | +LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next().expect("REASON") } + | +++++++++++++++++ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-26638.rs:5:47 diff --git a/tests/ui/mismatched_types/async-unwrap-suggestion.rs b/tests/ui/mismatched_types/async-unwrap-suggestion.rs new file mode 100644 index 00000000000..9698cc29ffd --- /dev/null +++ b/tests/ui/mismatched_types/async-unwrap-suggestion.rs @@ -0,0 +1,22 @@ +// edition: 2021 + +async fn dont_suggest() -> i32 { + if false { + return Ok(6); + //~^ ERROR mismatched types + } + + 5 +} + +async fn do_suggest() -> i32 { + if false { + let s = Ok(6); + return s; + //~^ ERROR mismatched types + } + + 5 +} + +fn main() {} diff --git a/tests/ui/mismatched_types/async-unwrap-suggestion.stderr b/tests/ui/mismatched_types/async-unwrap-suggestion.stderr new file mode 100644 index 00000000000..80ca76a4b86 --- /dev/null +++ b/tests/ui/mismatched_types/async-unwrap-suggestion.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/async-unwrap-suggestion.rs:5:16 + | +LL | return Ok(6); + | ^^^^^ expected `i32`, found `Result<{integer}, _>` + | + = note: expected type `i32` + found enum `Result<{integer}, _>` + +error[E0308]: mismatched types + --> $DIR/async-unwrap-suggestion.rs:15:16 + | +LL | return s; + | ^ expected `i32`, found `Result<{integer}, _>` + | + = note: expected type `i32` + found enum `Result<{integer}, _>` +help: consider using `Result::expect` to unwrap the `Result<{integer}, _>` value, panicking if the value is a `Result::Err` + | +LL | return s.expect("REASON"); + | +++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs new file mode 100644 index 00000000000..b288a9b05ef --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.rs @@ -0,0 +1,23 @@ +#![allow(unused, dead_code)] + +fn test_unwrap() -> Option<i32> { + let b: Result<i32, ()> = Ok(1); + let v: i32 = b; // return type is not `Result`, we don't suggest ? here + //~^ ERROR mismatched types + Some(v) +} + +fn test_unwrap_option() -> Result<i32, ()> { + let b = Some(1); + let v: i32 = b; // return type is not `Option`, we don't suggest ? here + //~^ ERROR mismatched types + Ok(v) +} + +fn main() { + let v: i32 = Some(0); //~ ERROR mismatched types + + let c = Ok(false); + let v: i32 = c; //~ ERROR mismatched types + +} diff --git a/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr new file mode 100644 index 00000000000..4f8f9b1a8a5 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-ty-dont-suggest.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/mismatch-ty-dont-suggest.rs:5:18 + | +LL | let v: i32 = b; // return type is not `Result`, we don't suggest ? here + | --- ^ expected `i32`, found `Result<i32, ()>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Result<i32, ()>` +help: consider using `Result::expect` to unwrap the `Result<i32, ()>` value, panicking if the value is a `Result::Err` + | +LL | let v: i32 = b.expect("REASON"); // return type is not `Result`, we don't suggest ? here + | +++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-dont-suggest.rs:12:18 + | +LL | let v: i32 = b; // return type is not `Option`, we don't suggest ? here + | --- ^ expected `i32`, found `Option<{integer}>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Option<{integer}>` +help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None` + | +LL | let v: i32 = b.expect("REASON"); // return type is not `Option`, we don't suggest ? here + | +++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-dont-suggest.rs:18:18 + | +LL | let v: i32 = Some(0); + | --- ^^^^^^^ expected `i32`, found `Option<{integer}>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Option<{integer}>` + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-dont-suggest.rs:21:18 + | +LL | let v: i32 = c; + | --- ^ expected `i32`, found `Result<bool, _>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Result<bool, _>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed new file mode 100644 index 00000000000..f3f560fe530 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.fixed @@ -0,0 +1,31 @@ +// run-rustfix +#![allow(unused, dead_code)] + +fn func() -> Option<i32> { + Some(1) +} + +fn test_unwrap() -> Result<i32, ()> { + let b: Result<i32, ()> = Ok(1); + let v: i32 = b?; //~ ERROR mismatched types + Ok(v) +} + +fn test_unwrap_option() -> Option<i32> { + let b = Some(1); + let v: i32 = b?; //~ ERROR mismatched types + Some(v) +} + +fn main() { + let a = Some(1); + let v: i32 = a.expect("REASON"); //~ ERROR mismatched types + + let b: Result<i32, ()> = Ok(1); + let v: i32 = b.expect("REASON"); //~ ERROR mismatched types + + let v: i32 = func().expect("REASON"); //~ ERROR mismatched types + + let a = None; + let v: i32 = a.expect("REASON"); //~ ERROR mismatched types +} diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs new file mode 100644 index 00000000000..14020e872ff --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.rs @@ -0,0 +1,31 @@ +// run-rustfix +#![allow(unused, dead_code)] + +fn func() -> Option<i32> { + Some(1) +} + +fn test_unwrap() -> Result<i32, ()> { + let b: Result<i32, ()> = Ok(1); + let v: i32 = b; //~ ERROR mismatched types + Ok(v) +} + +fn test_unwrap_option() -> Option<i32> { + let b = Some(1); + let v: i32 = b; //~ ERROR mismatched types + Some(v) +} + +fn main() { + let a = Some(1); + let v: i32 = a; //~ ERROR mismatched types + + let b: Result<i32, ()> = Ok(1); + let v: i32 = b; //~ ERROR mismatched types + + let v: i32 = func(); //~ ERROR mismatched types + + let a = None; + let v: i32 = a; //~ ERROR mismatched types +} diff --git a/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr new file mode 100644 index 00000000000..9de23447fed --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-ty-unwrap-expect.stderr @@ -0,0 +1,93 @@ +error[E0308]: mismatched types + --> $DIR/mismatch-ty-unwrap-expect.rs:10:18 + | +LL | let v: i32 = b; + | --- ^ expected `i32`, found `Result<i32, ()>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Result<i32, ()>` +help: use the `?` operator to extract the `Result<i32, ()>` value, propagating a `Result::Err` value to the caller + | +LL | let v: i32 = b?; + | + + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-unwrap-expect.rs:16:18 + | +LL | let v: i32 = b; + | --- ^ expected `i32`, found `Option<{integer}>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Option<{integer}>` +help: use the `?` operator to extract the `Option<{integer}>` value, propagating an `Option::None` value to the caller + | +LL | let v: i32 = b?; + | + + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-unwrap-expect.rs:22:18 + | +LL | let v: i32 = a; + | --- ^ expected `i32`, found `Option<{integer}>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Option<{integer}>` +help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None` + | +LL | let v: i32 = a.expect("REASON"); + | +++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-unwrap-expect.rs:25:18 + | +LL | let v: i32 = b; + | --- ^ expected `i32`, found `Result<i32, ()>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Result<i32, ()>` +help: consider using `Result::expect` to unwrap the `Result<i32, ()>` value, panicking if the value is a `Result::Err` + | +LL | let v: i32 = b.expect("REASON"); + | +++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-unwrap-expect.rs:27:18 + | +LL | let v: i32 = func(); + | --- ^^^^^^ expected `i32`, found `Option<i32>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Option<i32>` +help: consider using `Option::expect` to unwrap the `Option<i32>` value, panicking if the value is an `Option::None` + | +LL | let v: i32 = func().expect("REASON"); + | +++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-ty-unwrap-expect.rs:30:18 + | +LL | let v: i32 = a; + | --- ^ expected `i32`, found `Option<_>` + | | + | expected due to this + | + = note: expected type `i32` + found enum `Option<_>` +help: consider using `Option::expect` to unwrap the `Option<_>` value, panicking if the value is an `Option::None` + | +LL | let v: i32 = a.expect("REASON"); + | +++++++++++++++++ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/noexporttypeexe.stderr b/tests/ui/noexporttypeexe.stderr index 26bafd31d01..bf88ceaa5d2 100644 --- a/tests/ui/noexporttypeexe.stderr +++ b/tests/ui/noexporttypeexe.stderr @@ -8,6 +8,10 @@ LL | let x: isize = noexporttypelib::foo(); | = note: expected type `isize` found enum `Option<isize>` +help: consider using `Option::expect` to unwrap the `Option<isize>` value, panicking if the value is an `Option::None` + | +LL | let x: isize = noexporttypelib::foo().expect("REASON"); + | +++++++++++++++++ error: aborting due to previous error diff --git a/tests/ui/pattern/non-structural-match-types.mir.stderr b/tests/ui/pattern/non-structural-match-types.mir.stderr new file mode 100644 index 00000000000..7a9e5b7e02e --- /dev/null +++ b/tests/ui/pattern/non-structural-match-types.mir.stderr @@ -0,0 +1,14 @@ +error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:12:9 + | +LL | const { || {} } => {} + | ^^^^^^^^^^^^^^^ + +error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:15:9 + | +LL | const { async {} } => {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs index fc52ee3d013..fb7779fa808 100644 --- a/tests/ui/pattern/non-structural-match-types.rs +++ b/tests/ui/pattern/non-structural-match-types.rs @@ -1,4 +1,7 @@ // edition:2021 +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![allow(incomplete_features)] #![allow(unreachable_code)] #![feature(const_async_blocks)] diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr deleted file mode 100644 index f3e0665fef5..00000000000 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns - --> $DIR/non-structural-match-types.rs:9:9 - | -LL | const { || {} } => {} - | ^^^^^^^^^^^^^^^ - -error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns - --> $DIR/non-structural-match-types.rs:12:9 - | -LL | const { async {} } => {} - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/pattern/non-structural-match-types.thir.stderr b/tests/ui/pattern/non-structural-match-types.thir.stderr new file mode 100644 index 00000000000..7a9e5b7e02e --- /dev/null +++ b/tests/ui/pattern/non-structural-match-types.thir.stderr @@ -0,0 +1,14 @@ +error: `{closure@$DIR/non-structural-match-types.rs:12:17: 12:19}` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:12:9 + | +LL | const { || {} } => {} + | ^^^^^^^^^^^^^^^ + +error: `{async block@$DIR/non-structural-match-types.rs:15:17: 15:25}` cannot be used in patterns + --> $DIR/non-structural-match-types.rs:15:9 + | +LL | const { async {} } => {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/privacy/associated-item-privacy-trait.rs b/tests/ui/privacy/associated-item-privacy-trait.rs index db77a6a7258..f038ae9e261 100644 --- a/tests/ui/privacy/associated-item-privacy-trait.rs +++ b/tests/ui/privacy/associated-item-privacy-trait.rs @@ -23,7 +23,7 @@ mod priv_trait { let _: <Pub as PrivTr>::AssocTy; //~^ ERROR associated type `PrivTr::AssocTy` is private pub type InSignatureTy = <Pub as PrivTr>::AssocTy; - //~^ ERROR trait `PrivTr` is private + //~^ ERROR associated type `PrivTr::AssocTy` is private pub trait InSignatureTr: PrivTr {} //~^ ERROR trait `PrivTr` is private impl PrivTr for u8 {} diff --git a/tests/ui/privacy/associated-item-privacy-trait.stderr b/tests/ui/privacy/associated-item-privacy-trait.stderr index eb905bf7ef8..4e9dfa4a835 100644 --- a/tests/ui/privacy/associated-item-privacy-trait.stderr +++ b/tests/ui/privacy/associated-item-privacy-trait.stderr @@ -53,11 +53,11 @@ LL | priv_trait::mac!(); | = note: this error originates in the macro `priv_trait::mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `PrivTr` is private +error: associated type `PrivTr::AssocTy` is private --> $DIR/associated-item-privacy-trait.rs:25:34 | LL | pub type InSignatureTy = <Pub as PrivTr>::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^ private trait + | ^^^^^^^^^^^^^^^^^^^^^^^^ private associated type ... LL | priv_trait::mac!(); | ------------------ in this macro invocation diff --git a/tests/ui/privacy/private-in-public.rs b/tests/ui/privacy/private-in-public.rs index f54f9e38faa..3fff2d51710 100644 --- a/tests/ui/privacy/private-in-public.rs +++ b/tests/ui/privacy/private-in-public.rs @@ -104,8 +104,8 @@ mod aliases_pub { // This should be OK, but associated type aliases are not substituted yet pub fn f3(arg: <Priv as PrivTr>::Assoc) {} - //~^ WARNING trait `aliases_pub::PrivTr` is more private than the item `aliases_pub::f3` - //~| WARNING type `aliases_pub::Priv` is more private than the item `aliases_pub::f3` + //~^ WARNING type `aliases_pub::Priv` is more private than the item `aliases_pub::f3` + //~| WARNING associated type `aliases_pub::PrivTr::Assoc` is more private than the item `aliases_pub::f3` impl PrivUseAlias { pub fn f(arg: Priv) {} @@ -133,8 +133,8 @@ mod aliases_priv { pub fn f1(arg: PrivUseAlias) {} //~ WARNING type `Priv1` is more private than the item `aliases_priv::f1` pub fn f2(arg: PrivAlias) {} //~ WARNING type `Priv2` is more private than the item `aliases_priv::f2` pub fn f3(arg: <Priv as PrivTr>::Assoc) {} - //~^ WARNING trait `aliases_priv::PrivTr` is more private than the item `aliases_priv::f3` - //~| WARNING type `aliases_priv::Priv` is more private than the item `aliases_priv::f3` + //~^ WARNING type `aliases_priv::Priv` is more private than the item `aliases_priv::f3` + //~| WARNING associated type `aliases_priv::PrivTr::Assoc` is more private than the item `aliases_priv::f3` } mod aliases_params { diff --git a/tests/ui/privacy/private-in-public.stderr b/tests/ui/privacy/private-in-public.stderr index d3f7f0f637f..49cc2e19bf0 100644 --- a/tests/ui/privacy/private-in-public.stderr +++ b/tests/ui/privacy/private-in-public.stderr @@ -276,17 +276,17 @@ note: but type `impls::Priv` is only usable at visibility `pub(self)` LL | struct Priv; | ^^^^^^^^^^^ -warning: trait `aliases_pub::PrivTr` is more private than the item `aliases_pub::f3` +warning: associated type `aliases_pub::PrivTr::Assoc` is more private than the item `aliases_pub::f3` --> $DIR/private-in-public.rs:106:5 | LL | pub fn f3(arg: <Priv as PrivTr>::Assoc) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function `aliases_pub::f3` is reachable at visibility `pub(crate)` | -note: but trait `aliases_pub::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public.rs:100:5 +note: but associated type `aliases_pub::PrivTr::Assoc` is only usable at visibility `pub(self)` + --> $DIR/private-in-public.rs:101:9 | -LL | trait PrivTr { - | ^^^^^^^^^^^^ +LL | type Assoc = m::Pub3; + | ^^^^^^^^^^ warning: type `aliases_pub::Priv` is more private than the item `aliases_pub::f3` --> $DIR/private-in-public.rs:106:5 @@ -324,17 +324,17 @@ note: but type `Priv2` is only usable at visibility `pub(self)` LL | struct Priv2; | ^^^^^^^^^^^^ -warning: trait `aliases_priv::PrivTr` is more private than the item `aliases_priv::f3` +warning: associated type `aliases_priv::PrivTr::Assoc` is more private than the item `aliases_priv::f3` --> $DIR/private-in-public.rs:135:5 | LL | pub fn f3(arg: <Priv as PrivTr>::Assoc) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function `aliases_priv::f3` is reachable at visibility `pub(crate)` | -note: but trait `aliases_priv::PrivTr` is only usable at visibility `pub(self)` - --> $DIR/private-in-public.rs:128:5 +note: but associated type `aliases_priv::PrivTr::Assoc` is only usable at visibility `pub(self)` + --> $DIR/private-in-public.rs:129:9 | -LL | trait PrivTr { - | ^^^^^^^^^^^^ +LL | type Assoc = Priv3; + | ^^^^^^^^^^ warning: type `aliases_priv::Priv` is more private than the item `aliases_priv::f3` --> $DIR/private-in-public.rs:135:5 diff --git a/tests/ui/proc-macro/bad-projection.rs b/tests/ui/proc-macro/bad-projection.rs index d214c7ac8b2..c7cffdc9b47 100644 --- a/tests/ui/proc-macro/bad-projection.rs +++ b/tests/ui/proc-macro/bad-projection.rs @@ -13,3 +13,5 @@ trait Project { #[proc_macro] pub fn uwu() -> <() as Project>::Assoc {} //~^ ERROR the trait bound `(): Project` is not satisfied +//~| ERROR the trait bound `(): Project` is not satisfied +//~| ERROR function is expected to take 1 argument, but it takes 0 arguments diff --git a/tests/ui/proc-macro/bad-projection.stderr b/tests/ui/proc-macro/bad-projection.stderr index 8716defa17a..aea5d6d7c84 100644 --- a/tests/ui/proc-macro/bad-projection.stderr +++ b/tests/ui/proc-macro/bad-projection.stderr @@ -10,6 +10,32 @@ help: this trait has no implementations, consider adding one LL | trait Project { | ^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0593]: function is expected to take 1 argument, but it takes 0 arguments + --> $DIR/bad-projection.rs:14:1 + | +LL | pub fn uwu() -> <() as Project>::Assoc {} + | --------------------------------------^^^ + | | + | expected function that takes 1 argument + | takes 0 arguments + | required by a bound introduced by this call + | +note: required by a bound in `ProcMacro::bang` + --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL + +error[E0277]: the trait bound `(): Project` is not satisfied + --> $DIR/bad-projection.rs:14:1 + | +LL | pub fn uwu() -> <() as Project>::Assoc {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Project` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/bad-projection.rs:9:1 + | +LL | trait Project { + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0593. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/reachable/reachable-unnameable-type-alias.rs b/tests/ui/reachable/reachable-unnameable-type-alias.rs index 461355f87cf..ce830d2d4b4 100644 --- a/tests/ui/reachable/reachable-unnameable-type-alias.rs +++ b/tests/ui/reachable/reachable-unnameable-type-alias.rs @@ -1,14 +1,14 @@ // run-pass #![feature(staged_api)] -#![stable(feature = "a", since = "b")] +#![stable(feature = "a", since = "3.3.3")] mod inner_private_module { // UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here pub type UnnameableTypeAlias = u8; } -#[stable(feature = "a", since = "b")] +#[stable(feature = "a", since = "3.3.3")] pub fn f() -> inner_private_module::UnnameableTypeAlias { 0 } diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs index d4fea2b192b..987fd455fcc 100644 --- a/tests/ui/repr/16-bit-repr-c-enum.rs +++ b/tests/ui/repr/16-bit-repr-c-enum.rs @@ -8,7 +8,7 @@ #![feature(no_core, lang_items, intrinsics, staged_api, rustc_attrs)] #![no_core] #![crate_type = "lib"] -#![stable(feature = "", since = "")] +#![stable(feature = "intrinsics_for_test", since = "3.3.3")] #![allow(dead_code)] // Test that the repr(C) attribute doesn't break compilation @@ -22,8 +22,8 @@ enum Foo { } extern "rust-intrinsic" { - #[stable(feature = "", since = "")] - #[rustc_const_stable(feature = "", since = "")] + #[stable(feature = "intrinsics_for_test", since = "3.3.3")] + #[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")] #[rustc_safe_intrinsic] fn size_of<T>() -> usize; } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs index 1b45cd9aab9..13881e042a3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/default-method-body-is-const-with-staged-api.rs @@ -7,7 +7,7 @@ #![feature(staged_api)] #![feature(const_trait_impl)] -#![stable(since = "1", feature = "foo")] +#![stable(feature = "foo", since = "3.3.3")] #[const_trait] trait Tr { diff --git a/tests/ui/simd/array-trait.rs b/tests/ui/simd/array-trait.rs index 45c10b37816..883d718c49b 100644 --- a/tests/ui/simd/array-trait.rs +++ b/tests/ui/simd/array-trait.rs @@ -22,6 +22,7 @@ impl Simd for i32x4 { #[derive(Copy, Clone)] pub struct T<S: Simd>([S::Lane; S::SIZE]); //~^ ERROR unconstrained generic constant +//~| ERROR SIMD vector element type should be a primitive scalar extern "platform-intrinsic" { fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T; diff --git a/tests/ui/simd/array-trait.stderr b/tests/ui/simd/array-trait.stderr index 765215c3939..cf6026912aa 100644 --- a/tests/ui/simd/array-trait.stderr +++ b/tests/ui/simd/array-trait.stderr @@ -6,5 +6,12 @@ LL | pub struct T<S: Simd>([S::Lane; S::SIZE]); | = help: try adding a `where` bound using this expression: `where [(); S::SIZE]:` -error: aborting due to previous error +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/array-trait.rs:23:1 + | +LL | pub struct T<S: Simd>([S::Lane; S::SIZE]); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0077`. diff --git a/tests/ui/span/lint-unused-unsafe-thir.rs b/tests/ui/span/lint-unused-unsafe-thir.rs deleted file mode 100644 index adb72c26bba..00000000000 --- a/tests/ui/span/lint-unused-unsafe-thir.rs +++ /dev/null @@ -1,61 +0,0 @@ -// FIXME: This file is tracking old lint behavior that's still unchanged in the -// unstable -Zthir-unsafeck implementation. See lint-unused-unsafe.rs for more details. -// -// Exercise the unused_unsafe attribute in some positive and negative cases - -// compile-flags: -Zthir-unsafeck - -#![allow(dead_code)] -#![deny(unused_unsafe)] - - -mod foo { - extern "C" { - pub fn bar(); - } -} - -fn callback<T, F>(_f: F) -> T where F: FnOnce() -> T { panic!() } -unsafe fn unsf() {} - -fn bad1() { unsafe {} } //~ ERROR: unnecessary `unsafe` block -fn bad2() { unsafe { bad1() } } //~ ERROR: unnecessary `unsafe` block -unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block -fn bad4() { unsafe { callback(||{}) } } //~ ERROR: unnecessary `unsafe` block -unsafe fn bad5() { unsafe { unsf() } } -fn bad6() { - unsafe { // don't put the warning here - unsafe { //~ ERROR: unnecessary `unsafe` block - unsf() - } - } -} -unsafe fn bad7() { - unsafe { - unsafe { //~ ERROR: unnecessary `unsafe` block - unsf() - } - } -} - -unsafe fn good0() { unsf() } -fn good1() { unsafe { unsf() } } -fn good2() { - /* bug uncovered when implementing warning about unused unsafe blocks. Be - sure that when purity is inherited that the source of the unsafe-ness - is tracked correctly */ - unsafe { - unsafe fn what() -> Vec<String> { panic!() } - - callback(|| { - what(); - }); - } -} - -unsafe fn good3() { foo::bar() } -fn good4() { unsafe { foo::bar() } } - -#[allow(unused_unsafe)] fn allowed() { unsafe {} } - -fn main() {} diff --git a/tests/ui/span/lint-unused-unsafe-thir.stderr b/tests/ui/span/lint-unused-unsafe-thir.stderr deleted file mode 100644 index 3bcbb759775..00000000000 --- a/tests/ui/span/lint-unused-unsafe-thir.stderr +++ /dev/null @@ -1,50 +0,0 @@ -error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe-thir.rs:21:13 - | -LL | fn bad1() { unsafe {} } - | ^^^^^^ unnecessary `unsafe` block - | -note: the lint level is defined here - --> $DIR/lint-unused-unsafe-thir.rs:9:9 - | -LL | #![deny(unused_unsafe)] - | ^^^^^^^^^^^^^ - -error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe-thir.rs:22:13 - | -LL | fn bad2() { unsafe { bad1() } } - | ^^^^^^ unnecessary `unsafe` block - -error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe-thir.rs:23:20 - | -LL | unsafe fn bad3() { unsafe {} } - | ---------------- ^^^^^^ unnecessary `unsafe` block - | | - | because it's nested under this `unsafe` fn - -error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe-thir.rs:24:13 - | -LL | fn bad4() { unsafe { callback(||{}) } } - | ^^^^^^ unnecessary `unsafe` block - -error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe-thir.rs:28:9 - | -LL | unsafe { // don't put the warning here - | ------ because it's nested under this `unsafe` block -LL | unsafe { - | ^^^^^^ unnecessary `unsafe` block - -error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe-thir.rs:35:9 - | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -LL | unsafe { - | ^^^^^^ unnecessary `unsafe` block - -error: aborting due to 6 previous errors - diff --git a/tests/ui/span/lint-unused-unsafe.mir.stderr b/tests/ui/span/lint-unused-unsafe.mir.stderr index d8412908c73..9e8d3359242 100644 --- a/tests/ui/span/lint-unused-unsafe.mir.stderr +++ b/tests/ui/span/lint-unused-unsafe.mir.stderr @@ -1,77 +1,77 @@ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:26:13 + --> $DIR/lint-unused-unsafe.rs:22:13 | LL | fn bad1() { unsafe {} } | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:14:9 + --> $DIR/lint-unused-unsafe.rs:10:9 | LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:27:13 + --> $DIR/lint-unused-unsafe.rs:23:13 | LL | fn bad2() { unsafe { bad1() } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:28:20 + --> $DIR/lint-unused-unsafe.rs:24:20 | LL | unsafe fn bad3() { unsafe {} } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:29:13 + --> $DIR/lint-unused-unsafe.rs:25:13 | LL | fn bad4() { unsafe { callback(||{}) } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:32:5 + --> $DIR/lint-unused-unsafe.rs:28:5 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:39:5 + --> $DIR/lint-unused-unsafe.rs:35:5 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:74:9 + --> $DIR/lint-unused-unsafe.rs:70:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:83:9 + --> $DIR/lint-unused-unsafe.rs:79:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:84:13 + --> $DIR/lint-unused-unsafe.rs:80:13 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:85:13 + --> $DIR/lint-unused-unsafe.rs:81:13 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:90:9 + --> $DIR/lint-unused-unsafe.rs:86:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:100:13 + --> $DIR/lint-unused-unsafe.rs:96:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -80,7 +80,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:101:13 + --> $DIR/lint-unused-unsafe.rs:97:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -89,7 +89,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:102:13 + --> $DIR/lint-unused-unsafe.rs:98:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -98,7 +98,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:112:17 + --> $DIR/lint-unused-unsafe.rs:108:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -107,13 +107,13 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:110:20 + --> $DIR/lint-unused-unsafe.rs:106:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:113:17 + --> $DIR/lint-unused-unsafe.rs:109:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -122,7 +122,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:114:17 + --> $DIR/lint-unused-unsafe.rs:110:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -131,37 +131,37 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:124:9 + --> $DIR/lint-unused-unsafe.rs:120:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:134:9 + --> $DIR/lint-unused-unsafe.rs:130:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:135:13 + --> $DIR/lint-unused-unsafe.rs:131:13 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:136:13 + --> $DIR/lint-unused-unsafe.rs:132:13 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:142:9 + --> $DIR/lint-unused-unsafe.rs:138:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:153:13 + --> $DIR/lint-unused-unsafe.rs:149:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -170,7 +170,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:154:13 + --> $DIR/lint-unused-unsafe.rs:150:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -179,7 +179,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:155:13 + --> $DIR/lint-unused-unsafe.rs:151:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -188,7 +188,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:166:17 + --> $DIR/lint-unused-unsafe.rs:162:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -197,13 +197,13 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:164:20 + --> $DIR/lint-unused-unsafe.rs:160:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:167:17 + --> $DIR/lint-unused-unsafe.rs:163:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -212,7 +212,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:168:17 + --> $DIR/lint-unused-unsafe.rs:164:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -221,37 +221,37 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:178:9 + --> $DIR/lint-unused-unsafe.rs:174:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:188:9 + --> $DIR/lint-unused-unsafe.rs:184:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:189:13 + --> $DIR/lint-unused-unsafe.rs:185:13 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:190:13 + --> $DIR/lint-unused-unsafe.rs:186:13 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:196:9 + --> $DIR/lint-unused-unsafe.rs:192:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:207:13 + --> $DIR/lint-unused-unsafe.rs:203:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -260,7 +260,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:208:13 + --> $DIR/lint-unused-unsafe.rs:204:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -269,7 +269,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:209:13 + --> $DIR/lint-unused-unsafe.rs:205:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -278,7 +278,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:220:17 + --> $DIR/lint-unused-unsafe.rs:216:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -287,13 +287,13 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:218:20 + --> $DIR/lint-unused-unsafe.rs:214:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:221:17 + --> $DIR/lint-unused-unsafe.rs:217:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -302,7 +302,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:222:17 + --> $DIR/lint-unused-unsafe.rs:218:17 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -311,13 +311,13 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:242:9 + --> $DIR/lint-unused-unsafe.rs:238:9 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:255:13 + --> $DIR/lint-unused-unsafe.rs:251:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -325,7 +325,7 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:268:13 + --> $DIR/lint-unused-unsafe.rs:264:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -333,37 +333,37 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:286:20 + --> $DIR/lint-unused-unsafe.rs:282:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:295:20 + --> $DIR/lint-unused-unsafe.rs:291:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:296:24 + --> $DIR/lint-unused-unsafe.rs:292:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:297:24 + --> $DIR/lint-unused-unsafe.rs:293:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:302:20 + --> $DIR/lint-unused-unsafe.rs:298:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:312:24 + --> $DIR/lint-unused-unsafe.rs:308:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -372,7 +372,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:313:24 + --> $DIR/lint-unused-unsafe.rs:309:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -381,7 +381,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:314:24 + --> $DIR/lint-unused-unsafe.rs:310:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -390,7 +390,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:324:28 + --> $DIR/lint-unused-unsafe.rs:320:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -399,13 +399,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:322:20 + --> $DIR/lint-unused-unsafe.rs:318:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:325:28 + --> $DIR/lint-unused-unsafe.rs:321:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -414,7 +414,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:326:28 + --> $DIR/lint-unused-unsafe.rs:322:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -423,37 +423,37 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:336:20 + --> $DIR/lint-unused-unsafe.rs:332:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:346:20 + --> $DIR/lint-unused-unsafe.rs:342:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:347:24 + --> $DIR/lint-unused-unsafe.rs:343:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:348:24 + --> $DIR/lint-unused-unsafe.rs:344:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:354:20 + --> $DIR/lint-unused-unsafe.rs:350:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:365:24 + --> $DIR/lint-unused-unsafe.rs:361:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -462,7 +462,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:366:24 + --> $DIR/lint-unused-unsafe.rs:362:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -471,7 +471,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:367:24 + --> $DIR/lint-unused-unsafe.rs:363:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -480,7 +480,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:378:28 + --> $DIR/lint-unused-unsafe.rs:374:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -489,13 +489,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:376:20 + --> $DIR/lint-unused-unsafe.rs:372:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:379:28 + --> $DIR/lint-unused-unsafe.rs:375:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -504,7 +504,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:380:28 + --> $DIR/lint-unused-unsafe.rs:376:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -513,37 +513,37 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:390:20 + --> $DIR/lint-unused-unsafe.rs:386:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:400:20 + --> $DIR/lint-unused-unsafe.rs:396:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:401:24 + --> $DIR/lint-unused-unsafe.rs:397:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:402:24 + --> $DIR/lint-unused-unsafe.rs:398:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:408:20 + --> $DIR/lint-unused-unsafe.rs:404:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:419:24 + --> $DIR/lint-unused-unsafe.rs:415:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -552,7 +552,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:420:24 + --> $DIR/lint-unused-unsafe.rs:416:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -561,7 +561,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:421:24 + --> $DIR/lint-unused-unsafe.rs:417:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -570,7 +570,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:432:28 + --> $DIR/lint-unused-unsafe.rs:428:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -579,13 +579,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:430:20 + --> $DIR/lint-unused-unsafe.rs:426:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:433:28 + --> $DIR/lint-unused-unsafe.rs:429:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -594,7 +594,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:434:28 + --> $DIR/lint-unused-unsafe.rs:430:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -603,13 +603,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:454:20 + --> $DIR/lint-unused-unsafe.rs:450:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:467:24 + --> $DIR/lint-unused-unsafe.rs:463:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -617,7 +617,7 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:480:24 + --> $DIR/lint-unused-unsafe.rs:476:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -625,37 +625,37 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:499:20 + --> $DIR/lint-unused-unsafe.rs:495:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:508:20 + --> $DIR/lint-unused-unsafe.rs:504:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:509:24 + --> $DIR/lint-unused-unsafe.rs:505:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:510:24 + --> $DIR/lint-unused-unsafe.rs:506:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:515:20 + --> $DIR/lint-unused-unsafe.rs:511:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:525:24 + --> $DIR/lint-unused-unsafe.rs:521:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -664,7 +664,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:526:24 + --> $DIR/lint-unused-unsafe.rs:522:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -673,7 +673,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:527:24 + --> $DIR/lint-unused-unsafe.rs:523:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -682,7 +682,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:537:28 + --> $DIR/lint-unused-unsafe.rs:533:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -691,13 +691,13 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:535:20 + --> $DIR/lint-unused-unsafe.rs:531:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:538:28 + --> $DIR/lint-unused-unsafe.rs:534:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -706,7 +706,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:539:28 + --> $DIR/lint-unused-unsafe.rs:535:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -715,37 +715,37 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:549:20 + --> $DIR/lint-unused-unsafe.rs:545:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:559:20 + --> $DIR/lint-unused-unsafe.rs:555:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:560:24 + --> $DIR/lint-unused-unsafe.rs:556:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:561:24 + --> $DIR/lint-unused-unsafe.rs:557:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:567:20 + --> $DIR/lint-unused-unsafe.rs:563:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:578:24 + --> $DIR/lint-unused-unsafe.rs:574:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -754,7 +754,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:579:24 + --> $DIR/lint-unused-unsafe.rs:575:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -763,7 +763,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:580:24 + --> $DIR/lint-unused-unsafe.rs:576:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -772,7 +772,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:591:28 + --> $DIR/lint-unused-unsafe.rs:587:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -781,13 +781,13 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:589:20 + --> $DIR/lint-unused-unsafe.rs:585:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:592:28 + --> $DIR/lint-unused-unsafe.rs:588:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -796,7 +796,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:593:28 + --> $DIR/lint-unused-unsafe.rs:589:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -805,37 +805,37 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:603:20 + --> $DIR/lint-unused-unsafe.rs:599:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:613:20 + --> $DIR/lint-unused-unsafe.rs:609:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:614:24 + --> $DIR/lint-unused-unsafe.rs:610:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:615:24 + --> $DIR/lint-unused-unsafe.rs:611:24 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:621:20 + --> $DIR/lint-unused-unsafe.rs:617:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:632:24 + --> $DIR/lint-unused-unsafe.rs:628:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -844,7 +844,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:633:24 + --> $DIR/lint-unused-unsafe.rs:629:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -853,7 +853,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:634:24 + --> $DIR/lint-unused-unsafe.rs:630:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -862,7 +862,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:645:28 + --> $DIR/lint-unused-unsafe.rs:641:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -871,13 +871,13 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:643:20 + --> $DIR/lint-unused-unsafe.rs:639:20 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:646:28 + --> $DIR/lint-unused-unsafe.rs:642:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -886,7 +886,7 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:647:28 + --> $DIR/lint-unused-unsafe.rs:643:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -895,13 +895,13 @@ LL | let _ = || unsafe { let _ = || unsf(); }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:667:20 + --> $DIR/lint-unused-unsafe.rs:663:20 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:680:24 + --> $DIR/lint-unused-unsafe.rs:676:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -909,7 +909,7 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:693:24 + --> $DIR/lint-unused-unsafe.rs:689:24 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -917,37 +917,37 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:711:24 + --> $DIR/lint-unused-unsafe.rs:707:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:721:24 + --> $DIR/lint-unused-unsafe.rs:717:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:722:28 + --> $DIR/lint-unused-unsafe.rs:718:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:723:28 + --> $DIR/lint-unused-unsafe.rs:719:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:729:24 + --> $DIR/lint-unused-unsafe.rs:725:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:740:28 + --> $DIR/lint-unused-unsafe.rs:736:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -956,7 +956,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:741:28 + --> $DIR/lint-unused-unsafe.rs:737:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -965,7 +965,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:742:28 + --> $DIR/lint-unused-unsafe.rs:738:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -974,7 +974,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:753:32 + --> $DIR/lint-unused-unsafe.rs:749:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -983,13 +983,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:751:24 + --> $DIR/lint-unused-unsafe.rs:747:24 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:754:32 + --> $DIR/lint-unused-unsafe.rs:750:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -998,7 +998,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:755:32 + --> $DIR/lint-unused-unsafe.rs:751:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1007,37 +1007,37 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:765:24 + --> $DIR/lint-unused-unsafe.rs:761:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:775:24 + --> $DIR/lint-unused-unsafe.rs:771:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:776:28 + --> $DIR/lint-unused-unsafe.rs:772:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:777:28 + --> $DIR/lint-unused-unsafe.rs:773:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:783:24 + --> $DIR/lint-unused-unsafe.rs:779:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:794:28 + --> $DIR/lint-unused-unsafe.rs:790:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1046,7 +1046,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:795:28 + --> $DIR/lint-unused-unsafe.rs:791:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1055,7 +1055,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:796:28 + --> $DIR/lint-unused-unsafe.rs:792:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1064,7 +1064,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:807:32 + --> $DIR/lint-unused-unsafe.rs:803:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1073,13 +1073,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:805:24 + --> $DIR/lint-unused-unsafe.rs:801:24 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:808:32 + --> $DIR/lint-unused-unsafe.rs:804:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1088,7 +1088,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:809:32 + --> $DIR/lint-unused-unsafe.rs:805:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1097,13 +1097,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:829:24 + --> $DIR/lint-unused-unsafe.rs:825:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:842:28 + --> $DIR/lint-unused-unsafe.rs:838:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1111,7 +1111,7 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:855:28 + --> $DIR/lint-unused-unsafe.rs:851:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1119,37 +1119,37 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:869:24 + --> $DIR/lint-unused-unsafe.rs:865:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:879:24 + --> $DIR/lint-unused-unsafe.rs:875:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:880:28 + --> $DIR/lint-unused-unsafe.rs:876:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:881:28 + --> $DIR/lint-unused-unsafe.rs:877:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:887:24 + --> $DIR/lint-unused-unsafe.rs:883:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:898:28 + --> $DIR/lint-unused-unsafe.rs:894:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1158,7 +1158,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:899:28 + --> $DIR/lint-unused-unsafe.rs:895:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1167,7 +1167,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:900:28 + --> $DIR/lint-unused-unsafe.rs:896:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1176,7 +1176,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:911:32 + --> $DIR/lint-unused-unsafe.rs:907:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1185,13 +1185,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:909:24 + --> $DIR/lint-unused-unsafe.rs:905:24 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:912:32 + --> $DIR/lint-unused-unsafe.rs:908:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1200,7 +1200,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:913:32 + --> $DIR/lint-unused-unsafe.rs:909:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1209,37 +1209,37 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:923:24 + --> $DIR/lint-unused-unsafe.rs:919:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:933:24 + --> $DIR/lint-unused-unsafe.rs:929:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:934:28 + --> $DIR/lint-unused-unsafe.rs:930:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:935:28 + --> $DIR/lint-unused-unsafe.rs:931:28 | LL | let _ = || unsafe {}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:941:24 + --> $DIR/lint-unused-unsafe.rs:937:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:952:28 + --> $DIR/lint-unused-unsafe.rs:948:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1248,7 +1248,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:953:28 + --> $DIR/lint-unused-unsafe.rs:949:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1257,7 +1257,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:954:28 + --> $DIR/lint-unused-unsafe.rs:950:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1266,7 +1266,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:965:32 + --> $DIR/lint-unused-unsafe.rs:961:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1275,13 +1275,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:963:24 + --> $DIR/lint-unused-unsafe.rs:959:24 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:966:32 + --> $DIR/lint-unused-unsafe.rs:962:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1290,7 +1290,7 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:967:32 + --> $DIR/lint-unused-unsafe.rs:963:32 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1299,13 +1299,13 @@ LL | let _ = || unsafe { unsf() }; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:987:24 + --> $DIR/lint-unused-unsafe.rs:983:24 | LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1000:28 + --> $DIR/lint-unused-unsafe.rs:996:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1313,7 +1313,7 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1013:28 + --> $DIR/lint-unused-unsafe.rs:1009:28 | LL | let _ = || unsafe { | ------ because it's nested under this `unsafe` block @@ -1321,13 +1321,13 @@ LL | let _ = || unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1059:29 + --> $DIR/lint-unused-unsafe.rs:1055:29 | LL | let _ = async { unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1066:33 + --> $DIR/lint-unused-unsafe.rs:1062:33 | LL | let _ = async { unsafe { | ------ because it's nested under this `unsafe` block @@ -1336,7 +1336,7 @@ LL | let _ = async { unsafe { let _ = async { unsf() }; }}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1067:33 + --> $DIR/lint-unused-unsafe.rs:1063:33 | LL | let _ = async { unsafe { | ------ because it's nested under this `unsafe` block @@ -1345,7 +1345,7 @@ LL | let _ = async { unsafe { let _ = async { unsf() }; }}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1068:33 + --> $DIR/lint-unused-unsafe.rs:1064:33 | LL | let _ = async { unsafe { | ------ because it's nested under this `unsafe` block @@ -1354,13 +1354,13 @@ LL | let _ = async { unsafe { let _ = async { unsf() }; }}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1073:29 + --> $DIR/lint-unused-unsafe.rs:1069:29 | LL | let _ = async { unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1080:33 + --> $DIR/lint-unused-unsafe.rs:1076:33 | LL | let _ = async { unsafe { | ------ because it's nested under this `unsafe` block @@ -1369,7 +1369,7 @@ LL | let _ = async { unsafe { let _ = async { unsf() }; }}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1081:33 + --> $DIR/lint-unused-unsafe.rs:1077:33 | LL | let _ = async { unsafe { | ------ because it's nested under this `unsafe` block @@ -1378,7 +1378,7 @@ LL | let _ = async { unsafe { let _ = async { unsf() }; }}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1082:33 + --> $DIR/lint-unused-unsafe.rs:1078:33 | LL | let _ = async { unsafe { | ------ because it's nested under this `unsafe` block @@ -1387,13 +1387,13 @@ LL | let _ = async { unsafe { let _ = async { unsf() }; }}; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1092:22 + --> $DIR/lint-unused-unsafe.rs:1088:22 | LL | let _x: [(); unsafe { 0 }] = []; | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:1096:22 + --> $DIR/lint-unused-unsafe.rs:1092:22 | LL | let _x: [(); unsafe { unsafe { size() } }] = []; | ^^^^^^ unnecessary `unsafe` block diff --git a/tests/ui/span/lint-unused-unsafe.rs b/tests/ui/span/lint-unused-unsafe.rs index 5d042768be0..ca615f64f22 100644 --- a/tests/ui/span/lint-unused-unsafe.rs +++ b/tests/ui/span/lint-unused-unsafe.rs @@ -3,12 +3,8 @@ // edition:2018 -// revisions: mir - -// FIXME: Adapt -Zthir-unsafeck to behave the same as the mir version after #93678, -// then delete lint-unused-unsafe-thir.rs, and go back to using the settings below -// // revisions: mir thir -// // [thir]compile-flags: -Zthir-unsafeck +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![allow(dead_code)] #![deny(unused_unsafe)] diff --git a/tests/ui/span/lint-unused-unsafe.thir.stderr b/tests/ui/span/lint-unused-unsafe.thir.stderr new file mode 100644 index 00000000000..9e8d3359242 --- /dev/null +++ b/tests/ui/span/lint-unused-unsafe.thir.stderr @@ -0,0 +1,1402 @@ +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:22:13 + | +LL | fn bad1() { unsafe {} } + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:10:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:23:13 + | +LL | fn bad2() { unsafe { bad1() } } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:24:20 + | +LL | unsafe fn bad3() { unsafe {} } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:25:13 + | +LL | fn bad4() { unsafe { callback(||{}) } } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:28:5 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:35:5 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:70:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:79:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:80:13 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:81:13 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:86:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:96:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:97:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:98:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:108:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:106:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:109:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:110:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:120:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:130:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:131:13 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:132:13 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:138:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:149:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:150:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:151:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:162:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:160:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:163:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:164:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:174:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:184:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:185:13 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:186:13 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:192:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:203:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:204:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:205:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:216:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:214:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:217:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:218:17 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:238:9 + | +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:251:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:264:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:282:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:291:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:292:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:293:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:298:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:308:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:309:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:310:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:320:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:318:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:321:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:322:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:332:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:342:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:343:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:344:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:350:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:361:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:362:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:363:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:374:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:372:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:375:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:376:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:386:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:396:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:397:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:398:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:404:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:415:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:416:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:417:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:428:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:426:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:429:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:430:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:450:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:463:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:476:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:495:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:504:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:505:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:506:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:511:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:521:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsf(); +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:522:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:523:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:533:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:531:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:534:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:535:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:545:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:555:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:556:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:557:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:563:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:574:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsf(); +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:575:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:576:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:587:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:585:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:588:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:589:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:599:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:609:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:610:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:611:24 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:617:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:628:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsf(); +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:629:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:630:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:641:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:639:20 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:642:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:643:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { let _ = || unsf(); }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:663:20 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:676:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:689:24 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:707:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:717:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:718:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:719:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:725:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:736:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:737:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:738:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:749:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:747:24 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:750:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:751:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:761:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:771:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:772:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:773:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:779:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:790:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:791:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:792:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:803:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:801:24 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:804:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:805:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:825:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:838:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:851:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:865:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:875:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:876:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:877:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:883:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:894:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:895:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:896:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:907:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:905:24 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:908:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:909:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:919:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:929:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:930:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:931:28 + | +LL | let _ = || unsafe {}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:937:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:948:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsf(); +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:949:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:950:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:961:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:959:24 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:962:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:963:32 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = || unsafe { unsf() }; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:983:24 + | +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:996:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1009:28 + | +LL | let _ = || unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = || unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1055:29 + | +LL | let _ = async { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1062:33 + | +LL | let _ = async { unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = async { unsf() }; +LL | let _ = async { unsafe { let _ = async { unsf() }; }}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1063:33 + | +LL | let _ = async { unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = async { unsafe { let _ = async { unsf() }; }}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1064:33 + | +LL | let _ = async { unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = async { unsafe { let _ = async { unsf() }; }}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1069:29 + | +LL | let _ = async { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1076:33 + | +LL | let _ = async { unsafe { + | ------ because it's nested under this `unsafe` block +LL | let _ = async { unsf() }; +LL | let _ = async { unsafe { let _ = async { unsf() }; }}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1077:33 + | +LL | let _ = async { unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = async { unsafe { let _ = async { unsf() }; }}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1078:33 + | +LL | let _ = async { unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | let _ = async { unsafe { let _ = async { unsf() }; }}; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1088:22 + | +LL | let _x: [(); unsafe { 0 }] = []; + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:1092:22 + | +LL | let _x: [(); unsafe { unsafe { size() } }] = []; + | ^^^^^^ unnecessary `unsafe` block + +error: aborting due to 174 previous errors + diff --git a/tests/ui/specialization/min_specialization/issue-79224.rs b/tests/ui/specialization/min_specialization/issue-79224.rs index 104bddd076e..a118cb28b38 100644 --- a/tests/ui/specialization/min_specialization/issue-79224.rs +++ b/tests/ui/specialization/min_specialization/issue-79224.rs @@ -19,6 +19,7 @@ impl<B: ?Sized> Display for Cow<'_, B> { //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { //~^ ERROR: the trait bound `B: Clone` is not satisfied [E0277] + //~| ERROR: the trait bound `B: Clone` is not satisfied [E0277] write!(f, "foo") } } diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr index 9a4d557a152..7541579498e 100644 --- a/tests/ui/specialization/min_specialization/issue-79224.stderr +++ b/tests/ui/specialization/min_specialization/issue-79224.stderr @@ -22,6 +22,18 @@ help: consider further restricting this bound LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> { | +++++++++++++++++++ -error: aborting due to 2 previous errors +error[E0277]: the trait bound `B: Clone` is not satisfied + --> $DIR/issue-79224.rs:20:5 + | +LL | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B` + | + = note: required for `B` to implement `ToOwned` +help: consider further restricting this bound + | +LL | impl<B: ?Sized + std::clone::Clone> Display for Cow<'_, B> { + | +++++++++++++++++++ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/stability-attribute/stability-attribute-issue-43027.rs b/tests/ui/stability-attribute/stability-attribute-issue-43027.rs index 3f4fdfd0180..810fbef7b38 100644 --- a/tests/ui/stability-attribute/stability-attribute-issue-43027.rs +++ b/tests/ui/stability-attribute/stability-attribute-issue-43027.rs @@ -1,12 +1,12 @@ // check-pass #![feature(staged_api)] -#![stable(feature = "test", since = "0")] +#![stable(feature = "test", since = "3.3.3")] -#[stable(feature = "test", since = "0")] +#[stable(feature = "test", since = "3.3.3")] pub struct A<T>(pub T); -#[stable(feature = "test", since = "0")] -pub struct B<T>(#[stable(feature = "test", since = "0")] pub T); +#[stable(feature = "test", since = "3.3.3")] +pub struct B<T>(#[stable(feature = "test", since = "3.3.3")] pub T); fn main() { // Make sure the field is used to fill the stability cache diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs index 64f99635219..4fe8e45fd04 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs @@ -17,11 +17,11 @@ mod bogus_attribute_types_2 { #[stable = "a"] //~ ERROR malformed `stable` attribute fn f4() { } - #[stable(feature = "a", since = "b")] + #[stable(feature = "a", since = "3.3.3")] #[deprecated] //~ ERROR missing 'since' fn f5() { } - #[stable(feature = "a", since = "b")] + #[stable(feature = "a", since = "3.3.3")] #[deprecated = "a"] //~ ERROR missing 'since' fn f6() { } } diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index cc30e6ab9a9..8258b6f5ae0 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -5,19 +5,19 @@ #![stable(feature = "rust1", since = "1.0.0")] mod bogus_attribute_types_1 { - #[stable(feature = "a", since = "b", reason)] //~ ERROR unknown meta item 'reason' [E0541] + #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541] fn f1() { } #[stable(feature = "a", since)] //~ ERROR incorrect meta item [E0539] fn f2() { } - #[stable(feature, since = "a")] //~ ERROR incorrect meta item [E0539] + #[stable(feature, since = "3.3.3")] //~ ERROR incorrect meta item [E0539] fn f3() { } #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item [E0539] fn f5() { } - #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item [E0539] + #[stable(feature(b), since = "3.3.3")] //~ ERROR incorrect meta item [E0539] fn f6() { } } @@ -28,7 +28,7 @@ mod missing_feature_names { #[unstable(feature = "b")] //~ ERROR missing 'issue' [E0547] fn f2() { } - #[stable(since = "a")] //~ ERROR missing 'feature' [E0546] + #[stable(since = "3.3.3")] //~ ERROR missing 'feature' [E0546] fn f3() { } } @@ -36,28 +36,28 @@ mod missing_version { #[stable(feature = "a")] //~ ERROR missing 'since' [E0542] fn f1() { } - #[stable(feature = "a", since = "b")] + #[stable(feature = "a", since = "4.4.4")] #[deprecated(note = "a")] //~ ERROR missing 'since' [E0542] fn f2() { } - #[stable(feature = "a", since = "b")] + #[stable(feature = "a", since = "4.4.4")] #[deprecated(since = "a")] //~ ERROR missing 'note' [E0543] fn f3() { } } #[unstable(feature = "b", issue = "none")] -#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544] +#[stable(feature = "a", since = "4.4.4")] //~ ERROR multiple stability levels [E0544] fn multiple1() { } #[unstable(feature = "b", issue = "none")] #[unstable(feature = "b", issue = "none")] //~ ERROR multiple stability levels [E0544] fn multiple2() { } -#[stable(feature = "a", since = "b")] -#[stable(feature = "a", since = "b")] //~ ERROR multiple stability levels [E0544] +#[stable(feature = "a", since = "4.4.4")] +#[stable(feature = "a", since = "4.4.4")] //~ ERROR multiple stability levels [E0544] fn multiple3() { } -#[stable(feature = "a", since = "b")] //~ ERROR invalid stability version found +#[stable(feature = "e", since = "b")] //~ ERROR 'since' must be a Rust version number, such as "1.31.0" #[deprecated(since = "b", note = "text")] #[deprecated(since = "b", note = "text")] //~ ERROR multiple `deprecated` attributes #[rustc_const_unstable(feature = "c", issue = "none")] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 89a8425f5e7..955230742bd 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -11,10 +11,10 @@ LL | #[deprecated(since = "b", note = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0541]: unknown meta item 'reason' - --> $DIR/stability-attribute-sanity.rs:8:42 + --> $DIR/stability-attribute-sanity.rs:8:46 | -LL | #[stable(feature = "a", since = "b", reason)] - | ^^^^^^ expected one of `feature`, `since` +LL | #[stable(feature = "a", since = "4.4.4", reason)] + | ^^^^^^ expected one of `feature`, `since` error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:11:29 @@ -25,7 +25,7 @@ LL | #[stable(feature = "a", since)] error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:14:14 | -LL | #[stable(feature, since = "a")] +LL | #[stable(feature, since = "3.3.3")] | ^^^^^^^ error[E0539]: incorrect meta item @@ -37,7 +37,7 @@ LL | #[stable(feature = "a", since(b))] error[E0539]: incorrect meta item --> $DIR/stability-attribute-sanity.rs:20:14 | -LL | #[stable(feature(b), since = "a")] +LL | #[stable(feature(b), since = "3.3.3")] | ^^^^^^^^^^ error[E0546]: missing 'feature' @@ -55,8 +55,8 @@ LL | #[unstable(feature = "b")] error[E0546]: missing 'feature' --> $DIR/stability-attribute-sanity.rs:31:5 | -LL | #[stable(since = "a")] - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | #[stable(since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0542]: missing 'since' --> $DIR/stability-attribute-sanity.rs:36:5 @@ -79,8 +79,8 @@ LL | #[deprecated(since = "a")] error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:49:1 | -LL | #[stable(feature = "a", since = "b")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[stable(feature = "a", since = "4.4.4")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:53:1 @@ -91,7 +91,13 @@ LL | #[unstable(feature = "b", issue = "none")] error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:57:1 | -LL | #[stable(feature = "a", since = "b")] +LL | #[stable(feature = "a", since = "4.4.4")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: 'since' must be a Rust version number, such as "1.31.0" + --> $DIR/stability-attribute-sanity.rs:60:1 + | +LL | #[stable(feature = "e", since = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0544]: multiple stability levels @@ -100,15 +106,6 @@ error[E0544]: multiple stability levels LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: invalid stability version found - --> $DIR/stability-attribute-sanity.rs:60:1 - | -LL | #[stable(feature = "a", since = "b")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid stability version -... -LL | pub const fn multiple4() { } - | ---------------------------- the stability attribute annotates this item - error: invalid deprecation version found --> $DIR/stability-attribute-sanity.rs:67:1 | @@ -124,7 +121,7 @@ error[E0549]: deprecated attribute must be paired with either stable or unstable LL | #[deprecated(since = "a", note = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since b +error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since 4.4.4 --> $DIR/stability-attribute-sanity.rs:67:1 | LL | #[stable(feature = "a", since = "1.0.0")] diff --git a/tests/ui/stability-attribute/stability-attribute-trait-impl.rs b/tests/ui/stability-attribute/stability-attribute-trait-impl.rs index 1d138e26408..880000ee7a4 100644 --- a/tests/ui/stability-attribute/stability-attribute-trait-impl.rs +++ b/tests/ui/stability-attribute/stability-attribute-trait-impl.rs @@ -1,13 +1,13 @@ #![feature(staged_api, never_type, rust_cold_cc)] //~^ ERROR module has missing stability attribute -#[stable(feature = "a", since = "1")] +#[stable(feature = "a", since = "3.3.3")] struct StableType; #[unstable(feature = "b", issue = "none")] struct UnstableType; -#[stable(feature = "c", since = "1")] +#[stable(feature = "c", since = "3.3.3")] trait StableTrait {} #[unstable(feature = "d", issue = "none")] diff --git a/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr b/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr index 96322c2c945..018786dd26d 100644 --- a/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr +++ b/tests/ui/stability-attribute/stability-attribute-trait-impl.stderr @@ -21,7 +21,7 @@ error: module has missing stability attribute LL | / #![feature(staged_api, never_type, rust_cold_cc)] LL | | LL | | -LL | | #[stable(feature = "a", since = "1")] +LL | | #[stable(feature = "a", since = "3.3.3")] ... | LL | | LL | | fn main() {} diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs index 782444417a8..971a4654b4c 100644 --- a/tests/ui/target-feature/gate.rs +++ b/tests/ui/target-feature/gate.rs @@ -18,6 +18,7 @@ // gate-test-bpf_target_feature // gate-test-aarch64_ver_target_feature // gate-test-csky_target_feature +// gate-test-loongarch_target_feature #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index f56efb3bb83..0ec7427c3c4 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:22:18 + --> $DIR/gate.rs:23:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs new file mode 100644 index 00000000000..e0edd522431 --- /dev/null +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs @@ -0,0 +1,43 @@ +// Regression test for #116464 +// Checks that we do not suggest Trait<..., Assoc=arg> when the trait +// is referred to from one of its impls but do so at all other places + +pub trait Trait<T> { + type Assoc; +} + +impl<T, S> Trait<T> for i32 { + type Assoc = String; +} + +// Should not not trigger suggestion here... +impl<T, S> Trait<T, S> for () {} +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + +//... but should do so in all of the below cases except the last one +fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied +//~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied + 3 +} + +struct Struct<T: Trait<u32, String>> { +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + a: T +} + +trait AnotherTrait<T: Trait<T, i32>> {} +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + +impl<T: Trait<u32, String>> Struct<T> {} +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + +// Test for self type. Should not trigger suggestion as it doesn't have an +// associated type +trait YetAnotherTrait {} +impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {} +//~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied + + +fn main() { +} diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr new file mode 100644 index 00000000000..711ccf1b668 --- /dev/null +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -0,0 +1,109 @@ +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:14:12 + | +LL | impl<T, S> Trait<T, S> for () {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait<T> { + | ^^^^^ - + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:12 + | +LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait<T> { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | fn func<T: Trait<u32, Assoc = String>>(t: T) -> impl Trait<(), i32> { + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:46 + | +LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait<T> { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> { + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:18 + | +LL | struct Struct<T: Trait<u32, String>> { + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait<T> { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | struct Struct<T: Trait<u32, Assoc = String>> { + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:29:23 + | +LL | trait AnotherTrait<T: Trait<T, i32>> {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait<T> { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | trait AnotherTrait<T: Trait<T, Assoc = i32>> {} + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:9 + | +LL | impl<T: Trait<u32, String>> Struct<T> {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait<T> { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | impl<T: Trait<u32, Assoc = String>> Struct<T> {} + | +++++++ + +error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:38:58 + | +LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {} + | ^^^^^^ - help: remove this generic argument + | | + | expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:8 + | +LL | struct Struct<T: Trait<u32, String>> { + | ^^^^^^ - + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.rs b/tests/ui/traits/bound/on-structs-and-enums-static.rs index df3f8b8a599..066416cb362 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-static.rs +++ b/tests/ui/traits/bound/on-structs-and-enums-static.rs @@ -8,7 +8,7 @@ struct Foo<T:Trait> { static X: Foo<usize> = Foo { //~^ ERROR E0277 - x: 1, + x: 1, //~ ERROR: E0277 }; fn main() { diff --git a/tests/ui/traits/bound/on-structs-and-enums-static.stderr b/tests/ui/traits/bound/on-structs-and-enums-static.stderr index fa14aff684d..28bbe00c582 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-static.stderr +++ b/tests/ui/traits/bound/on-structs-and-enums-static.stderr @@ -15,6 +15,23 @@ note: required by a bound in `Foo` LL | struct Foo<T:Trait> { | ^^^^^ required by this bound in `Foo` -error: aborting due to previous error +error[E0277]: the trait bound `usize: Trait` is not satisfied + --> $DIR/on-structs-and-enums-static.rs:11:8 + | +LL | x: 1, + | ^ the trait `Trait` is not implemented for `usize` + | +help: this trait has no implementations, consider adding one + --> $DIR/on-structs-and-enums-static.rs:1:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ +note: required by a bound in `Foo` + --> $DIR/on-structs-and-enums-static.rs:5:14 + | +LL | struct Foo<T:Trait> { + | ^^^^^ required by this bound in `Foo` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/new-solver/specialization-transmute.rs b/tests/ui/traits/new-solver/specialization-transmute.rs index f6b19e7adf5..7523b828321 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.rs +++ b/tests/ui/traits/new-solver/specialization-transmute.rs @@ -10,7 +10,7 @@ trait Default { } impl<T> Default for T { - default type Id = T; + default type Id = T; //~ ERROR: type annotations needed // This will be fixed by #111994 fn intu(&self) -> &Self::Id { //~ ERROR type annotations needed self diff --git a/tests/ui/traits/new-solver/specialization-transmute.stderr b/tests/ui/traits/new-solver/specialization-transmute.stderr index 09b1405fefb..18965a465b3 100644 --- a/tests/ui/traits/new-solver/specialization-transmute.stderr +++ b/tests/ui/traits/new-solver/specialization-transmute.stderr @@ -16,6 +16,13 @@ LL | fn intu(&self) -> &Self::Id { | = note: cannot satisfy `<T as Default>::Id == _` -error: aborting due to previous error; 1 warning emitted +error[E0282]: type annotations needed + --> $DIR/specialization-transmute.rs:13:23 + | +LL | default type Id = T; + | ^ cannot infer type for associated type `<T as Default>::Id` + +error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.rs b/tests/ui/type-alias-impl-trait/generic_underconstrained.rs index d87a25aad58..1acacc778de 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained.rs +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.rs @@ -8,5 +8,6 @@ type Underconstrained<T: Trait> = impl Send; // no `Trait` bound fn underconstrain<T>(_: T) -> Underconstrained<T> { //~^ ERROR the trait bound `T: Trait` + //~| ERROR the trait bound `T: Trait` unimplemented!() } diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr index bc9280127ac..88529b370f1 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -14,6 +14,27 @@ help: consider restricting type parameter `T` LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> { | +++++++ -error: aborting due to previous error +error[E0277]: the trait bound `T: Trait` is not satisfied + --> $DIR/generic_underconstrained.rs:9:51 + | +LL | fn underconstrain<T>(_: T) -> Underconstrained<T> { + | ___________________________________________________^ +LL | | +LL | | +LL | | unimplemented!() +LL | | } + | |_^ the trait `Trait` is not implemented for `T` + | +note: required by a bound on the type alias `Underconstrained` + --> $DIR/generic_underconstrained.rs:6:26 + | +LL | type Underconstrained<T: Trait> = impl Send; + | ^^^^^ required by this bound +help: consider restricting type parameter `T` + | +LL | fn underconstrain<T: Trait>(_: T) -> Underconstrained<T> { + | +++++++ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs b/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs index 8adc0bf32a6..1e1bece9a1c 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.rs @@ -7,6 +7,7 @@ type Underconstrained<T: std::fmt::Debug> = impl Send; // not a defining use, because it doesn't define *all* possible generics fn underconstrained<U>(_: U) -> Underconstrained<U> { //~^ ERROR `U` doesn't implement `Debug` + //~| ERROR `U` doesn't implement `Debug` 5u32 } @@ -15,5 +16,6 @@ type Underconstrained2<T: std::fmt::Debug> = impl Send; // not a defining use, because it doesn't define *all* possible generics fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> { //~^ ERROR `V` doesn't implement `Debug` + //~| ERROR `V` doesn't implement `Debug` 5u32 } diff --git a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr index fdc9ec090db..b3b9cbca968 100644 --- a/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -15,13 +15,13 @@ LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> { | +++++++++++++++++ error[E0277]: `V` doesn't implement `Debug` - --> $DIR/generic_underconstrained2.rs:16:43 + --> $DIR/generic_underconstrained2.rs:17:43 | LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> { | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | note: required by a bound on the type alias `Underconstrained2` - --> $DIR/generic_underconstrained2.rs:13:27 + --> $DIR/generic_underconstrained2.rs:14:27 | LL | type Underconstrained2<T: std::fmt::Debug> = impl Send; | ^^^^^^^^^^^^^^^ required by this bound @@ -30,6 +30,48 @@ help: consider restricting type parameter `V` LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> { | +++++++++++++++++ -error: aborting due to 2 previous errors +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:8:53 + | +LL | fn underconstrained<U>(_: U) -> Underconstrained<U> { + | _____________________________________________________^ +LL | | +LL | | +LL | | 5u32 +LL | | } + | |_^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +note: required by a bound on the type alias `Underconstrained` + --> $DIR/generic_underconstrained2.rs:5:26 + | +LL | type Underconstrained<T: std::fmt::Debug> = impl Send; + | ^^^^^^^^^^^^^^^ required by this bound +help: consider restricting type parameter `U` + | +LL | fn underconstrained<U: std::fmt::Debug>(_: U) -> Underconstrained<U> { + | +++++++++++++++++ + +error[E0277]: `V` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:17:64 + | +LL | fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> { + | ________________________________________________________________^ +LL | | +LL | | +LL | | 5u32 +LL | | } + | |_^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +note: required by a bound on the type alias `Underconstrained2` + --> $DIR/generic_underconstrained2.rs:14:27 + | +LL | type Underconstrained2<T: std::fmt::Debug> = impl Send; + | ^^^^^^^^^^^^^^^ required by this bound +help: consider restricting type parameter `V` + | +LL | fn underconstrained2<U, V: std::fmt::Debug>(_: U, _: V) -> Underconstrained2<V> { + | +++++++++++++++++ + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr b/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr index aaf75cc3db9..e35913be899 100644 --- a/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr +++ b/tests/ui/type-alias-impl-trait/impl_trait_for_same_tait.stderr @@ -15,6 +15,8 @@ LL | impl Bop for Bar<()> {} ... LL | impl Bop for Barr {} | ^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<()>` + | + = note: upstream crates may add a new impl of trait `std::marker::FnPtr` for type `Barr` in future versions error[E0119]: conflicting implementations of trait `Bop` for type `Bar<()>` --> $DIR/impl_trait_for_same_tait.rs:30:1 diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs new file mode 100644 index 00000000000..3d1759097d6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.rs @@ -0,0 +1,17 @@ +// test for #113326 +#![feature(type_alias_impl_trait)] + +pub type Diff = impl Fn(usize) -> usize; + +pub fn lift() -> Diff { + |_: usize |loop {} +} + +pub fn add( + n: Diff, + m: Diff, +) -> Diff { + move |x: usize| m(n(x)) //~ ERROR: concrete type differs +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr new file mode 100644 index 00000000000..b2898a21190 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/recursive-fn-tait.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/recursive-fn-tait.rs:14:5 + | +LL | move |x: usize| m(n(x)) + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `{closure@$DIR/recursive-fn-tait.rs:7:5: 7:16}`, got `{closure@$DIR/recursive-fn-tait.rs:14:5: 14:20}` + | +note: previous use here + --> $DIR/recursive-fn-tait.rs:7:5 + | +LL | |_: usize |loop {} + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr b/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr index f53abe53bf1..c4f16429563 100644 --- a/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr +++ b/tests/ui/typeck/tag-that-dare-not-speak-its-name.stderr @@ -8,6 +8,10 @@ LL | let x : char = last(y); | = note: expected type `char` found enum `Option<_>` +help: consider using `Option::expect` to unwrap the `Option<_>` value, panicking if the value is an `Option::None` + | +LL | let x : char = last(y).expect("REASON"); + | +++++++++++++++++ error: aborting due to previous error diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.rs b/tests/ui/ufcs/ufcs-explicit-self-bad.rs index cb1fac0bae6..9b0f99a189a 100644 --- a/tests/ui/ufcs/ufcs-explicit-self-bad.rs +++ b/tests/ui/ufcs/ufcs-explicit-self-bad.rs @@ -36,6 +36,7 @@ impl<'a, T> SomeTrait for &'a Bar<T> { fn dummy1(self: &&'a Bar<T>) { } fn dummy2(self: &Bar<T>) {} //~ ERROR mismatched `self` parameter type //~^ ERROR mismatched `self` parameter type + //~| ERROR has an incompatible type for trait fn dummy3(self: &&Bar<T>) {} //~^ ERROR mismatched `self` parameter type //~| expected reference `&'a Bar<T>` diff --git a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr index f325d1d8182..0efaa41d48a 100644 --- a/tests/ui/ufcs/ufcs-explicit-self-bad.stderr +++ b/tests/ui/ufcs/ufcs-explicit-self-bad.stderr @@ -64,7 +64,7 @@ LL | fn dummy2(self: &Bar<T>) {} | ^^^^^^^ error[E0308]: mismatched `self` parameter type - --> $DIR/ufcs-explicit-self-bad.rs:39:21 + --> $DIR/ufcs-explicit-self-bad.rs:40:21 | LL | fn dummy3(self: &&Bar<T>) {} | ^^^^^^^^ lifetime mismatch @@ -72,7 +72,7 @@ LL | fn dummy3(self: &&Bar<T>) {} = note: expected reference `&'a Bar<T>` found reference `&Bar<T>` note: the anonymous lifetime defined here... - --> $DIR/ufcs-explicit-self-bad.rs:39:22 + --> $DIR/ufcs-explicit-self-bad.rs:40:22 | LL | fn dummy3(self: &&Bar<T>) {} | ^^^^^^^ @@ -83,7 +83,7 @@ LL | impl<'a, T> SomeTrait for &'a Bar<T> { | ^^ error[E0308]: mismatched `self` parameter type - --> $DIR/ufcs-explicit-self-bad.rs:39:21 + --> $DIR/ufcs-explicit-self-bad.rs:40:21 | LL | fn dummy3(self: &&Bar<T>) {} | ^^^^^^^^ lifetime mismatch @@ -96,12 +96,29 @@ note: the lifetime `'a` as defined here... LL | impl<'a, T> SomeTrait for &'a Bar<T> { | ^^ note: ...does not necessarily outlive the anonymous lifetime defined here - --> $DIR/ufcs-explicit-self-bad.rs:39:22 + --> $DIR/ufcs-explicit-self-bad.rs:40:22 | LL | fn dummy3(self: &&Bar<T>) {} | ^^^^^^^ -error: aborting due to 7 previous errors +error[E0053]: method `dummy2` has an incompatible type for trait + --> $DIR/ufcs-explicit-self-bad.rs:37:21 + | +LL | fn dummy2(self: &Bar<T>) {} + | ------^^^^^^^ + | | | + | | expected `&'a Bar<T>`, found `Bar<T>` + | help: change the self-receiver type to match the trait: `&self` + | +note: type in trait + --> $DIR/ufcs-explicit-self-bad.rs:31:15 + | +LL | fn dummy2(&self); + | ^^^^^ + = note: expected signature `fn(&&'a Bar<T>)` + found signature `fn(&Bar<T>)` + +error: aborting due to 8 previous errors -Some errors have detailed explanations: E0307, E0308. -For more information about an error, try `rustc --explain E0307`. +Some errors have detailed explanations: E0053, E0307, E0308. +For more information about an error, try `rustc --explain E0053`. diff --git a/tests/ui/union/issue-81199.rs b/tests/ui/union/issue-81199.rs index 628e7c6ed5d..b8b0d9d33e7 100644 --- a/tests/ui/union/issue-81199.rs +++ b/tests/ui/union/issue-81199.rs @@ -4,6 +4,7 @@ union PtrRepr<T: ?Sized> { mut_ptr: *mut T, components: PtrComponents<T>, //~^ ERROR the trait bound + //~| ERROR field must implement `Copy` } #[repr(C)] diff --git a/tests/ui/union/issue-81199.stderr b/tests/ui/union/issue-81199.stderr index 5bb98675361..0dd894beb2a 100644 --- a/tests/ui/union/issue-81199.stderr +++ b/tests/ui/union/issue-81199.stderr @@ -5,7 +5,7 @@ LL | components: PtrComponents<T>, | ^^^^^^^^^^^^^^^^ the trait `Pointee` is not implemented for `T` | note: required by a bound in `PtrComponents` - --> $DIR/issue-81199.rs:10:25 + --> $DIR/issue-81199.rs:11:25 | LL | struct PtrComponents<T: Pointee + ?Sized> { | ^^^^^^^ required by this bound in `PtrComponents` @@ -14,6 +14,19 @@ help: consider further restricting this bound LL | union PtrRepr<T: ?Sized + Pointee> { | +++++++++ -error: aborting due to previous error +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/issue-81199.rs:5:5 + | +LL | components: PtrComponents<T>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | components: std::mem::ManuallyDrop<PtrComponents<T>>, + | +++++++++++++++++++++++ + + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0740. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/union/union-unsized.mirunsafeck.stderr b/tests/ui/union/union-unsized.mirunsafeck.stderr index 59ab835fba2..f8da20413b2 100644 --- a/tests/ui/union/union-unsized.mirunsafeck.stderr +++ b/tests/ui/union/union-unsized.mirunsafeck.stderr @@ -17,7 +17,7 @@ LL | a: Box<str>, | ++++ + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:13:8 + --> $DIR/union-unsized.rs:14:8 | LL | b: str, | ^^^ doesn't have a size known at compile-time @@ -34,6 +34,31 @@ help: the `Box` type always has a statically known size and allocates its conten LL | b: Box<str>, | ++++ + -error: aborting due to 2 previous errors +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/union-unsized.rs:5:5 + | +LL | a: str, + | ^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | a: std::mem::ManuallyDrop<str>, + | +++++++++++++++++++++++ + + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/union-unsized.rs:14:5 + | +LL | b: str, + | ^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | b: std::mem::ManuallyDrop<str>, + | +++++++++++++++++++++++ + + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0740. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/union/union-unsized.rs b/tests/ui/union/union-unsized.rs index 8e897d7d3c6..b95b2e414f3 100644 --- a/tests/ui/union/union-unsized.rs +++ b/tests/ui/union/union-unsized.rs @@ -4,6 +4,7 @@ union U { a: str, //~^ ERROR the size for values of type + //~| ERROR field must implement `Copy` b: u8, } @@ -12,6 +13,7 @@ union W { a: u8, b: str, //~^ ERROR the size for values of type + //~| ERROR field must implement `Copy` } fn main() {} diff --git a/tests/ui/union/union-unsized.thirunsafeck.stderr b/tests/ui/union/union-unsized.thirunsafeck.stderr index 59ab835fba2..f8da20413b2 100644 --- a/tests/ui/union/union-unsized.thirunsafeck.stderr +++ b/tests/ui/union/union-unsized.thirunsafeck.stderr @@ -17,7 +17,7 @@ LL | a: Box<str>, | ++++ + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:13:8 + --> $DIR/union-unsized.rs:14:8 | LL | b: str, | ^^^ doesn't have a size known at compile-time @@ -34,6 +34,31 @@ help: the `Box` type always has a statically known size and allocates its conten LL | b: Box<str>, | ++++ + -error: aborting due to 2 previous errors +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/union-unsized.rs:5:5 + | +LL | a: str, + | ^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | a: std::mem::ManuallyDrop<str>, + | +++++++++++++++++++++++ + + +error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union + --> $DIR/union-unsized.rs:14:5 + | +LL | b: str, + | ^^^^^^ + | + = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` +help: wrap the field type in `ManuallyDrop<...>` + | +LL | b: std::mem::ManuallyDrop<str>, + | +++++++++++++++++++++++ + + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0740. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/unresolved/auxiliary/library.rs b/tests/ui/unresolved/auxiliary/library.rs new file mode 100644 index 00000000000..1169ed96225 --- /dev/null +++ b/tests/ui/unresolved/auxiliary/library.rs @@ -0,0 +1 @@ +pub struct SomeUsefulType; diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs new file mode 100644 index 00000000000..af8207aaadd --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs @@ -0,0 +1,31 @@ +// Test that we don't prepend `::` to paths referencing crates from the extern prelude +// when it can be avoided[^1] since it's more idiomatic to do so. +// +// [^1]: Counterexample: `unresolved-import-suggest-disambiguated-crate-name.rs` +#![feature(decl_macro)] // allows us to create items with hygienic names + +// aux-crate:library=library.rs +// edition: 2021 + +mod hygiene { + make!(); + macro make() { + // This won't conflict with the suggested *non-global* path as the syntax context differs. + mod library {} + } + + mod module {} + use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` +} + +mod glob { + use inner::*; + mod inner { + mod library {} + } + + mod module {} + use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` +} + +fn main() {} diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr new file mode 100644 index 00000000000..b0352ab6754 --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr @@ -0,0 +1,25 @@ +error[E0432]: unresolved import `module::SomeUsefulType` + --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:18:9 + | +LL | use module::SomeUsefulType; + | ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `hygiene::module` + | +help: consider importing this struct instead + | +LL | use library::SomeUsefulType; + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0432]: unresolved import `module::SomeUsefulType` + --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:28:9 + | +LL | use module::SomeUsefulType; + | ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `glob::module` + | +help: consider importing this struct instead + | +LL | use library::SomeUsefulType; + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed new file mode 100644 index 00000000000..2b20d3f106b --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed @@ -0,0 +1,19 @@ +// Regression test for issue #116970. +// +// When we suggest importing an item from a crate found in the extern prelude and there +// happens to exist a module or type in the current scope with the same name as the crate, +// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`). +// +// For context, when it can be avoided we don't prepend `::` to paths referencing crates +// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`. + +// run-rustfix + +// compile-flags: --crate-type=lib +// aux-crate:library=library.rs +// edition: 2021 + +mod library {} // this module shares the same name as the external crate! + +mod module {} +pub use ::library::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs new file mode 100644 index 00000000000..b810a7f5296 --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs @@ -0,0 +1,19 @@ +// Regression test for issue #116970. +// +// When we suggest importing an item from a crate found in the extern prelude and there +// happens to exist a module or type in the current scope with the same name as the crate, +// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`). +// +// For context, when it can be avoided we don't prepend `::` to paths referencing crates +// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`. + +// run-rustfix + +// compile-flags: --crate-type=lib +// aux-crate:library=library.rs +// edition: 2021 + +mod library {} // this module shares the same name as the external crate! + +mod module {} +pub use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr new file mode 100644 index 00000000000..f139c0f3cf1 --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr @@ -0,0 +1,14 @@ +error[E0432]: unresolved import `module::SomeUsefulType` + --> $DIR/unresolved-import-suggest-disambiguated-crate-name.rs:19:9 + | +LL | pub use module::SomeUsefulType; + | ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `module` + | +help: consider importing this struct instead + | +LL | pub use ::library::SomeUsefulType; + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr b/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr index 9e9cbcf33ae..2267da31512 100644 --- a/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr +++ b/tests/ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.thir.stderr @@ -16,9 +16,9 @@ LL | #[deny(unused_unsafe)] error: unnecessary `unsafe` block --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 | -LL | unsafe { - | ------ because it's nested under this `unsafe` block -... +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | v.set_len(24); LL | |w: &mut Vec<u32>| { unsafe { | ^^^^^^ unnecessary `unsafe` block diff --git a/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr b/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr index 13c080e5b6a..4cdd97e5e06 100644 --- a/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr +++ b/tests/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr @@ -76,12 +76,10 @@ LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:49:5 | LL | unsafe { unsafe { unsf() } } - | ------ ^^^^^^ unnecessary `unsafe` block - | | - | because it's nested under this `unsafe` block + | ^^^^^^ unnecessary `unsafe` block error[E0133]: call to unsafe function `unsf` is unsafe and requires unsafe block --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5 diff --git a/tests/ui/unsized/unsized-trait-impl-self-type.rs b/tests/ui/unsized/unsized-trait-impl-self-type.rs index df571a83382..603c0a221ec 100644 --- a/tests/ui/unsized/unsized-trait-impl-self-type.rs +++ b/tests/ui/unsized/unsized-trait-impl-self-type.rs @@ -9,6 +9,7 @@ struct S5<Y>(Y); impl<X: ?Sized> T3<X> for S5<X> { //~^ ERROR the size for values of type + //~| ERROR not all trait items implemented } fn main() { } diff --git a/tests/ui/unsized/unsized-trait-impl-self-type.stderr b/tests/ui/unsized/unsized-trait-impl-self-type.stderr index 4955d463fc2..5bc8dc590ca 100644 --- a/tests/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/tests/ui/unsized/unsized-trait-impl-self-type.stderr @@ -24,6 +24,16 @@ LL - impl<X: ?Sized> T3<X> for S5<X> { LL + impl<X> T3<X> for S5<X> { | -error: aborting due to previous error +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/unsized-trait-impl-self-type.rs:10:1 + | +LL | fn foo(&self, z: &Z); + | --------------------- `foo` from trait +... +LL | impl<X: ?Sized> T3<X> for S5<X> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0046, E0277. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/unsized/unsized-trait-impl-trait-arg.rs b/tests/ui/unsized/unsized-trait-impl-trait-arg.rs index 96e7e371f2a..e7602b175c8 100644 --- a/tests/ui/unsized/unsized-trait-impl-trait-arg.rs +++ b/tests/ui/unsized/unsized-trait-impl-trait-arg.rs @@ -7,6 +7,7 @@ trait T2<Z> { struct S4<Y: ?Sized>(Box<Y>); impl<X: ?Sized> T2<X> for S4<X> { //~^ ERROR the size for values of type + //~| ERROR not all trait items implemented } fn main() { } diff --git a/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr b/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr index 8761c293af4..e9353d2bbd9 100644 --- a/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/tests/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -21,6 +21,16 @@ help: consider relaxing the implicit `Sized` restriction LL | trait T2<Z: ?Sized> { | ++++++++ -error: aborting due to previous error +error[E0046]: not all trait items implemented, missing: `foo` + --> $DIR/unsized-trait-impl-trait-arg.rs:8:1 + | +LL | fn foo(&self, z: Z); + | -------------------- `foo` from trait +... +LL | impl<X: ?Sized> T2<X> for S4<X> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0046, E0277. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/unsized/unsized7.rs b/tests/ui/unsized/unsized7.rs index 422a784814e..63e015c28d3 100644 --- a/tests/ui/unsized/unsized7.rs +++ b/tests/ui/unsized/unsized7.rs @@ -11,6 +11,7 @@ trait T1<Z: T> { struct S3<Y: ?Sized>(Box<Y>); impl<X: ?Sized + T> T1<X> for S3<X> { //~^ ERROR the size for values of type + //~| ERROR not all trait items implemented } fn main() { } diff --git a/tests/ui/unsized/unsized7.stderr b/tests/ui/unsized/unsized7.stderr index c313a2724c0..2edde159653 100644 --- a/tests/ui/unsized/unsized7.stderr +++ b/tests/ui/unsized/unsized7.stderr @@ -21,6 +21,16 @@ help: consider relaxing the implicit `Sized` restriction LL | trait T1<Z: T + ?Sized> { | ++++++++ -error: aborting due to previous error +error[E0046]: not all trait items implemented, missing: `dummy` + --> $DIR/unsized7.rs:12:1 + | +LL | fn dummy(&self) -> Z; + | --------------------- `dummy` from trait +... +LL | impl<X: ?Sized + T> T1<X> for S3<X> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `dummy` in implementation + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0046, E0277. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/wf/hir-wf-check-erase-regions.rs b/tests/ui/wf/hir-wf-check-erase-regions.rs index 3855f2c35c1..2820d5f6d07 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.rs +++ b/tests/ui/wf/hir-wf-check-erase-regions.rs @@ -5,6 +5,7 @@ pub struct Table<T, const N: usize>([Option<T>; N]); impl<'a, T, const N: usize> IntoIterator for &'a Table<T, N> { type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>; //~ ERROR `&'a T` is not an iterator + //~^ ERROR `&'a T` is not an iterator type Item = &'a T; fn into_iter(self) -> Self::IntoIter { //~ ERROR `&'a T` is not an iterator diff --git a/tests/ui/wf/hir-wf-check-erase-regions.stderr b/tests/ui/wf/hir-wf-check-erase-regions.stderr index 2843983c716..eb0a8f8f69a 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.stderr +++ b/tests/ui/wf/hir-wf-check-erase-regions.stderr @@ -11,7 +11,7 @@ note: required by a bound in `Flatten` --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL error[E0277]: `&'a T` is not an iterator - --> $DIR/hir-wf-check-erase-regions.rs:10:27 + --> $DIR/hir-wf-check-erase-regions.rs:11:27 | LL | fn into_iter(self) -> Self::IntoIter { | ^^^^^^^^^^^^^^ `&'a T` is not an iterator @@ -22,6 +22,18 @@ LL | fn into_iter(self) -> Self::IntoIter { note: required by a bound in `Flatten` --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL -error: aborting due to 2 previous errors +error[E0277]: `&'a T` is not an iterator + --> $DIR/hir-wf-check-erase-regions.rs:7:21 + | +LL | type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&'a T` + = help: the trait `Iterator` is implemented for `&mut I` + = note: required for `Flatten<std::slice::Iter<'a, T>>` to implement `Iterator` +note: required by a bound in `std::iter::IntoIterator::IntoIter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/issue-110157.rs b/tests/ui/wf/issue-110157.rs index 43a8ce72ff1..07e2c5d58c3 100644 --- a/tests/ui/wf/issue-110157.rs +++ b/tests/ui/wf/issue-110157.rs @@ -2,6 +2,7 @@ struct NeedsDropTypes<'tcx, F>(std::marker::PhantomData<&'tcx F>); impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> //~^ ERROR type annotations needed +//~| ERROR not all trait items implemented where F: Fn(&Missing) -> Result<I, ()>, //~^ ERROR cannot find type `Missing` in this scope diff --git a/tests/ui/wf/issue-110157.stderr b/tests/ui/wf/issue-110157.stderr index 91d801e9470..16bd34a6d8e 100644 --- a/tests/ui/wf/issue-110157.stderr +++ b/tests/ui/wf/issue-110157.stderr @@ -1,11 +1,11 @@ error[E0412]: cannot find type `Missing` in this scope - --> $DIR/issue-110157.rs:6:12 + --> $DIR/issue-110157.rs:7:12 | LL | F: Fn(&Missing) -> Result<I, ()>, | ^^^^^^^ not found in this scope error[E0412]: cannot find type `Missing` in this scope - --> $DIR/issue-110157.rs:8:24 + --> $DIR/issue-110157.rs:9:24 | LL | I: Iterator<Item = Missing>, | ^^^^^^^ not found in this scope @@ -26,7 +26,22 @@ LL | impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> LL | I: Iterator<Item = Missing>, | ------------------------ unsatisfied trait bound introduced here -error: aborting due to 3 previous errors +error[E0046]: not all trait items implemented, missing: `Item`, `next` + --> $DIR/issue-110157.rs:3:1 + | +LL | / impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> +LL | | +LL | | +LL | | where +LL | | F: Fn(&Missing) -> Result<I, ()>, +LL | | +LL | | I: Iterator<Item = Missing>, + | |________________________________^ missing `Item`, `next` in implementation + | + = help: implement the missing item: `type Item = /* Type */;` + = help: implement the missing item: `fn next(&mut self) -> Option<<Self as Iterator>::Item> { todo!() }` + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0283, E0412. -For more information about an error, try `rustc --explain E0283`. +Some errors have detailed explanations: E0046, E0283, E0412. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/wf/wf-const-type.rs b/tests/ui/wf/wf-const-type.rs index df79aa26712..64b0d9c8de7 100644 --- a/tests/ui/wf/wf-const-type.rs +++ b/tests/ui/wf/wf-const-type.rs @@ -9,6 +9,7 @@ struct NotCopy; const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; //~^ ERROR E0277 +//~| ERROR E0277 fn main() { } diff --git a/tests/ui/wf/wf-const-type.stderr b/tests/ui/wf/wf-const-type.stderr index 617969720a6..039e907705e 100644 --- a/tests/ui/wf/wf-const-type.stderr +++ b/tests/ui/wf/wf-const-type.stderr @@ -16,6 +16,24 @@ LL + #[derive(Copy)] LL | struct NotCopy; | -error: aborting due to previous error +error[E0277]: the trait bound `NotCopy: Copy` is not satisfied + --> $DIR/wf-const-type.rs:10:50 + | +LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; + | ^^^^ the trait `Copy` is not implemented for `NotCopy` + | + = note: required for `Option<NotCopy>` to implement `Copy` +note: required by a bound in `IsCopy` + --> $DIR/wf-const-type.rs:7:17 + | +LL | struct IsCopy<T:Copy> { t: T } + | ^^^^ required by this bound in `IsCopy` +help: consider annotating `NotCopy` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | struct NotCopy; + | + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-static-type.rs b/tests/ui/wf/wf-static-type.rs index 1c35e1daf44..f454fe30e77 100644 --- a/tests/ui/wf/wf-static-type.rs +++ b/tests/ui/wf/wf-static-type.rs @@ -9,6 +9,7 @@ struct NotCopy; static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; //~^ ERROR E0277 +//~| ERROR E0277 fn main() { } diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr index bb5a57834eb..65dae260143 100644 --- a/tests/ui/wf/wf-static-type.stderr +++ b/tests/ui/wf/wf-static-type.stderr @@ -16,6 +16,24 @@ LL + #[derive(Copy)] LL | struct NotCopy; | -error: aborting due to previous error +error[E0277]: the trait bound `NotCopy: Copy` is not satisfied + --> $DIR/wf-static-type.rs:10:51 + | +LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None }; + | ^^^^ the trait `Copy` is not implemented for `NotCopy` + | + = note: required for `Option<NotCopy>` to implement `Copy` +note: required by a bound in `IsCopy` + --> $DIR/wf-static-type.rs:7:17 + | +LL | struct IsCopy<T:Copy> { t: T } + | ^^^^ required by this bound in `IsCopy` +help: consider annotating `NotCopy` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | struct NotCopy; + | + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. |
